wiconfig.c revision 1.14 1 /* $NetBSD: wiconfig.c,v 1.14 2001/05/16 10:49:06 tsubai Exp $ */
2 /*
3 * Copyright (c) 1997, 1998, 1999
4 * Bill Paul <wpaul (at) ctr.columbia.edu>. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Bill Paul.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * From: Id: wicontrol.c,v 1.6 1999/05/22 16:12:49 wpaul Exp $
34 */
35
36 #include <sys/types.h>
37 #include <sys/cdefs.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42
43 #include <net/if.h>
44 #ifdef __FreeBSD__
45 #include <net/if_var.h>
46 #include <net/ethernet.h>
47
48 #include <machine/if_wavelan_ieee.h>
49 #else
50 #include <netinet/in.h>
51 #include <netinet/if_ether.h>
52 #ifdef __NetBSD__
53 #include <dev/ic/wi_ieee.h>
54 #else
55 #include <dev/pcmcia/if_wavelan_ieee.h>
56 #endif
57 #endif
58
59 #include <stdio.h>
60 #include <string.h>
61 #include <ctype.h>
62 #include <stdlib.h>
63 #include <unistd.h>
64 #include <errno.h>
65 #include <err.h>
66
67 #if !defined(lint)
68 static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\
69 Bill Paul. All rights reserved.";
70 static const char rcsid[] =
71 "@(#) $Id: wiconfig.c,v 1.14 2001/05/16 10:49:06 tsubai Exp $";
72 #endif
73
74 struct wi_table {
75 int wi_type;
76 int wi_code;
77 #define WI_NONE 0x00
78 #define WI_STRING 0x01
79 #define WI_BOOL 0x02
80 #define WI_WORDS 0x03
81 #define WI_HEXBYTES 0x04
82 #define WI_KEYSTRUCT 0x05
83 char *wi_label; /* label used to print info */
84 int wi_opt; /* option character to set this */
85 char *wi_desc;
86 char *wi_optval;
87 };
88
89 static void wi_getval __P((char *, struct wi_req *));
90 static void wi_setval __P((char *, struct wi_req *));
91 static void wi_printstr __P((struct wi_req *));
92 static void wi_setstr __P((char *, int, char *));
93 static void wi_setbytes __P((char *, int, char *, int));
94 static void wi_setword __P((char *, int, int));
95 static void wi_sethex __P((char *, int, char *));
96 static void wi_printwords __P((struct wi_req *));
97 static void wi_printbool __P((struct wi_req *));
98 static void wi_printhex __P((struct wi_req *));
99 static void wi_dumpinfo __P((char *));
100 static void wi_setkeys __P((char *, char *, int));
101 static void wi_printkeys __P((struct wi_req *));
102 static void wi_dumpstats __P((char *));
103 static void usage __P((void));
104 static struct wi_table *
105 wi_optlookup __P((struct wi_table *, int));
106 static int wi_hex2int(char c);
107 static void wi_str2key __P((char *, struct wi_key *));
108 int main __P((int argc, char **argv));
109
110 static void wi_getval(iface, wreq)
111 char *iface;
112 struct wi_req *wreq;
113 {
114 struct ifreq ifr;
115 int s;
116
117 bzero((char *)&ifr, sizeof(ifr));
118
119 strcpy(ifr.ifr_name, iface);
120 ifr.ifr_data = (caddr_t)wreq;
121
122 s = socket(AF_INET, SOCK_DGRAM, 0);
123
124 if (s == -1)
125 err(1, "socket");
126
127 if (ioctl(s, SIOCGWAVELAN, &ifr) == -1)
128 err(1, "SIOCGWAVELAN");
129
130 close(s);
131
132 return;
133 }
134
135 static void wi_setval(iface, wreq)
136 char *iface;
137 struct wi_req *wreq;
138 {
139 struct ifreq ifr;
140 int s;
141
142 bzero((char *)&ifr, sizeof(ifr));
143
144 strcpy(ifr.ifr_name, iface);
145 ifr.ifr_data = (caddr_t)wreq;
146
147 s = socket(AF_INET, SOCK_DGRAM, 0);
148
149 if (s == -1)
150 err(1, "socket");
151
152 if (ioctl(s, SIOCSWAVELAN, &ifr) == -1)
153 err(1, "SIOCSWAVELAN");
154
155 close(s);
156
157 return;
158 }
159
160 void wi_printstr(wreq)
161 struct wi_req *wreq;
162 {
163 char *ptr;
164 int i;
165
166 if (wreq->wi_type == WI_RID_SERIALNO) {
167 ptr = (char *)&wreq->wi_val;
168 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
169 if (ptr[i] == '\0')
170 ptr[i] = ' ';
171 }
172 } else {
173 int len = le16toh(wreq->wi_val[0]);
174
175 ptr = (char *)&wreq->wi_val[1];
176 for (i = 0; i < len; i++) {
177 if (ptr[i] == '\0')
178 ptr[i] = ' ';
179 }
180 }
181
182 ptr[i] = '\0';
183 printf("[ %s ]", ptr);
184
185 return;
186 }
187
188 void wi_setstr(iface, code, str)
189 char *iface;
190 int code;
191 char *str;
192 {
193 struct wi_req wreq;
194
195 bzero((char *)&wreq, sizeof(wreq));
196
197 if (strlen(str) > 30)
198 errx(1, "string too long");
199
200 wreq.wi_type = code;
201 wreq.wi_len = 18;
202 wreq.wi_val[0] = htole16(strlen(str));
203 bcopy(str, (char *)&wreq.wi_val[1], strlen(str));
204
205 wi_setval(iface, &wreq);
206
207 return;
208 }
209
210 void wi_setbytes(iface, code, bytes, len)
211 char *iface;
212 int code;
213 char *bytes;
214 int len;
215 {
216 struct wi_req wreq;
217
218 bzero((char *)&wreq, sizeof(wreq));
219
220 wreq.wi_type = code;
221 wreq.wi_len = (len / 2) + 1;
222 bcopy(bytes, (char *)&wreq.wi_val[0], len);
223
224 wi_setval(iface, &wreq);
225
226 return;
227 }
228
229 void wi_setword(iface, code, word)
230 char *iface;
231 int code;
232 int word;
233 {
234 struct wi_req wreq;
235
236 bzero((char *)&wreq, sizeof(wreq));
237
238 wreq.wi_type = code;
239 wreq.wi_len = 2;
240 wreq.wi_val[0] = htole16(word);
241
242 wi_setval(iface, &wreq);
243
244 return;
245 }
246
247 void wi_sethex(iface, code, str)
248 char *iface;
249 int code;
250 char *str;
251 {
252 struct ether_addr *addr;
253
254 addr = ether_aton(str);
255 if (addr == NULL)
256 errx(1, "badly formatted address");
257
258 wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN);
259
260 return;
261 }
262
263 static int
264 wi_hex2int(char c)
265 {
266 if (c >= '0' && c <= '9')
267 return (c - '0');
268 if (c >= 'A' && c <= 'F')
269 return (c - 'A' + 10);
270 if (c >= 'a' && c <= 'f')
271 return (c - 'a' + 10);
272
273 return (0);
274 }
275
276 static void wi_str2key(s, k)
277 char *s;
278 struct wi_key *k;
279 {
280 int n, i;
281 char *p;
282
283 /* Is this a hex string? */
284 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
285 /* Yes, convert to int. */
286 n = 0;
287 p = (char *)&k->wi_keydat[0];
288 for (i = 2; i < strlen(s); i+= 2) {
289 *p++ = (wi_hex2int(s[i]) << 4) + wi_hex2int(s[i + 1]);
290 n++;
291 }
292 k->wi_keylen = htole16(n);
293 } else {
294 /* No, just copy it in. */
295 bcopy(s, k->wi_keydat, strlen(s));
296 k->wi_keylen = htole16(strlen(s));
297 }
298
299 return;
300 }
301
302 static void wi_setkeys(iface, key, idx)
303 char *iface;
304 char *key;
305 int idx;
306 {
307 struct wi_req wreq;
308 struct wi_ltv_keys *keys;
309 struct wi_key *k;
310
311 bzero((char *)&wreq, sizeof(wreq));
312 wreq.wi_len = WI_MAX_DATALEN;
313 wreq.wi_type = WI_RID_WEP_AVAIL;
314
315 wi_getval(iface, &wreq);
316 if (le16toh(wreq.wi_val[0]) == 0)
317 err(1, "no WEP option available on this card");
318
319 bzero((char *)&wreq, sizeof(wreq));
320 wreq.wi_len = WI_MAX_DATALEN;
321 wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
322
323 wi_getval(iface, &wreq);
324 keys = (struct wi_ltv_keys *)&wreq;
325
326 if (key[0] == '0' && (key[1] == 'x' || key[1] == 'X')) {
327 if (strlen(key) > 30)
328 err(1, "encryption key must be no "
329 "more than 28 hex digits long");
330 } else {
331 if (strlen(key) > 14)
332 err(1, "encryption key must be no "
333 "more than 14 characters long");
334 }
335
336 if (idx > 3)
337 err(1, "only 4 encryption keys available");
338
339 k = &keys->wi_keys[idx];
340 wi_str2key(key, k);
341
342 wreq.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
343 wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
344 wi_setval(iface, &wreq);
345
346 return;
347 }
348
349 static void wi_printkeys(wreq)
350 struct wi_req *wreq;
351 {
352 int i, j, bn;
353 struct wi_key *k;
354 struct wi_ltv_keys *keys;
355 char *ptr;
356
357 keys = (struct wi_ltv_keys *)wreq;
358
359 for (i = 0, bn = 0; i < 4; i++, bn = 0) {
360 k = &keys->wi_keys[i];
361 ptr = (char *)k->wi_keydat;
362 for (j = 0; j < le16toh(k->wi_keylen); j++) {
363 if (!isprint((unsigned char) ptr[j])) {
364 bn = 1;
365 break;
366 }
367 }
368
369 if (bn) {
370 printf("[ 0x");
371 for (j = 0; j < le16toh(k->wi_keylen); j++)
372 printf("%02x", ((unsigned char *) ptr)[j]);
373 printf(" ]");
374 } else {
375 ptr[j] = '\0';
376 printf("[ %s ]", ptr);
377 }
378 }
379
380 return;
381 };
382
383 void wi_printwords(wreq)
384 struct wi_req *wreq;
385 {
386 int i;
387
388 printf("[ ");
389 for (i = 0; i < wreq->wi_len - 1; i++)
390 printf("%d ", le16toh(wreq->wi_val[i]));
391 printf("]");
392
393 return;
394 }
395
396 void wi_printbool(wreq)
397 struct wi_req *wreq;
398 {
399 if (le16toh(wreq->wi_val[0]))
400 printf("[ On ]");
401 else
402 printf("[ Off ]");
403
404 return;
405 }
406
407 void wi_printhex(wreq)
408 struct wi_req *wreq;
409 {
410 int i;
411 unsigned char *c;
412
413 c = (unsigned char *)&wreq->wi_val;
414
415 printf("[ ");
416 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
417 printf("%02x", c[i]);
418 if (i < ((wreq->wi_len - 1) * 2) - 1)
419 printf(":");
420 }
421
422 printf(" ]");
423 return;
424 }
425
426 static struct wi_table wi_table[] = {
427 { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" },
428 { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t",
429 's', "station name" },
430 { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t",
431 'q', "own SSID" },
432 { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" },
433 { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t",
434 'n', "network name" },
435 { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" },
436 { WI_RID_CHANNEL_LIST, WI_WORDS, "Channel list:\t\t\t\t" },
437 { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t",
438 'f', "frequency" },
439 { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" },
440 { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" },
441 { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" },
442 { WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t",
443 'p', "port type" },
444 { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t",
445 'm', "MAC address" },
446 { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t",
447 't', "TX rate" },
448 { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"},
449 { WI_RID_MAX_DATALEN, WI_WORDS, "Maximum data length:\t\t\t",
450 'd', "maximum data length" },
451 { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t",
452 'r', "RTS threshold" },
453 { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t",
454 'c', "create ibss" },
455 { WI_RID_MICROWAVE_OVEN, WI_WORDS, "Microwave oven robustness:\t\t",
456 'M', "microwave oven robustness enabled" },
457 { WI_RID_ROAMING_MODE, WI_WORDS, "Roaming mode(1:firm,3:disable):\t\t",
458 'R', "roaming mode" },
459 { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t",
460 'a', "system scale" },
461 { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t",
462 'P', "power management enabled" },
463 { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time (msec):\t\t\t",
464 'S', "max sleep duration" },
465 { 0, WI_NONE }
466 };
467
468 static struct wi_table wi_crypt_table[] = {
469 { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t",
470 'e', "encryption" },
471 { WI_RID_AUTH_CNTL, WI_WORDS, "Authentication type \n(1=OpenSys, 2=Shared Key):\t\t",
472 'A', "authentication type" },
473 { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" },
474 { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" },
475 { 0, WI_NONE }
476 };
477
478 static struct wi_table *wi_tables[] = {
479 wi_table,
480 wi_crypt_table,
481 NULL
482 };
483
484 static struct wi_table *
485 wi_optlookup(table, opt)
486 struct wi_table *table;
487 int opt;
488 {
489 struct wi_table *wt;
490
491 for (wt = table; wt->wi_type != 0; wt++)
492 if (wt->wi_opt == opt)
493 return (wt);
494 return (NULL);
495 }
496
497 static void wi_dumpinfo(iface)
498 char *iface;
499 {
500 struct wi_req wreq;
501 int i, has_wep;
502 struct wi_table *w;
503
504 bzero((char *)&wreq, sizeof(wreq));
505
506 wreq.wi_len = WI_MAX_DATALEN;
507 wreq.wi_type = WI_RID_WEP_AVAIL;
508
509 wi_getval(iface, &wreq);
510 has_wep = le16toh(wreq.wi_val[0]);
511
512 w = wi_table;
513
514 for (i = 0; w[i].wi_code != WI_NONE; i++) {
515 bzero((char *)&wreq, sizeof(wreq));
516
517 wreq.wi_len = WI_MAX_DATALEN;
518 wreq.wi_type = w[i].wi_type;
519
520 wi_getval(iface, &wreq);
521 printf("%s", w[i].wi_label);
522 switch (w[i].wi_code) {
523 case WI_STRING:
524 wi_printstr(&wreq);
525 break;
526 case WI_WORDS:
527 wi_printwords(&wreq);
528 break;
529 case WI_BOOL:
530 wi_printbool(&wreq);
531 break;
532 case WI_HEXBYTES:
533 wi_printhex(&wreq);
534 break;
535 default:
536 break;
537 }
538 printf("\n");
539 }
540
541 if (has_wep) {
542 w = wi_crypt_table;
543 for (i = 0; w[i].wi_code != WI_NONE; i++) {
544 bzero((char *)&wreq, sizeof(wreq));
545
546 wreq.wi_len = WI_MAX_DATALEN;
547 wreq.wi_type = w[i].wi_type;
548
549 wi_getval(iface, &wreq);
550 printf("%s", w[i].wi_label);
551 switch (w[i].wi_code) {
552 case WI_STRING:
553 wi_printstr(&wreq);
554 break;
555 case WI_WORDS:
556 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
557 wreq.wi_val[0] =
558 htole16(le16toh(wreq.wi_val[0]) + 1);
559 wi_printwords(&wreq);
560 break;
561 case WI_BOOL:
562 wi_printbool(&wreq);
563 break;
564 case WI_HEXBYTES:
565 wi_printhex(&wreq);
566 break;
567 case WI_KEYSTRUCT:
568 wi_printkeys(&wreq);
569 break;
570 default:
571 break;
572 }
573 printf("\n");
574 }
575 }
576
577 return;
578 }
579
580 static void wi_dumpstats(iface)
581 char *iface;
582 {
583 struct wi_req wreq;
584 struct wi_counters *c;
585
586 bzero((char *)&wreq, sizeof(wreq));
587 wreq.wi_len = WI_MAX_DATALEN;
588 wreq.wi_type = WI_RID_IFACE_STATS;
589
590 wi_getval(iface, &wreq);
591
592 c = (struct wi_counters *)&wreq.wi_val;
593
594 /* XXX native byte order */
595 printf("Transmitted unicast frames:\t\t%d\n",
596 c->wi_tx_unicast_frames);
597 printf("Transmitted multicast frames:\t\t%d\n",
598 c->wi_tx_multicast_frames);
599 printf("Transmitted fragments:\t\t\t%d\n",
600 c->wi_tx_fragments);
601 printf("Transmitted unicast octets:\t\t%d\n",
602 c->wi_tx_unicast_octets);
603 printf("Transmitted multicast octets:\t\t%d\n",
604 c->wi_tx_multicast_octets);
605 printf("Single transmit retries:\t\t%d\n",
606 c->wi_tx_single_retries);
607 printf("Multiple transmit retries:\t\t%d\n",
608 c->wi_tx_multi_retries);
609 printf("Transmit retry limit exceeded:\t\t%d\n",
610 c->wi_tx_retry_limit);
611 printf("Transmit discards:\t\t\t%d\n",
612 c->wi_tx_discards);
613 printf("Transmit discards due to wrong SA:\t%d\n",
614 c->wi_tx_discards_wrong_sa);
615 printf("Received unicast frames:\t\t%d\n",
616 c->wi_rx_unicast_frames);
617 printf("Received multicast frames:\t\t%d\n",
618 c->wi_rx_multicast_frames);
619 printf("Received fragments:\t\t\t%d\n",
620 c->wi_rx_fragments);
621 printf("Received unicast octets:\t\t%d\n",
622 c->wi_rx_unicast_octets);
623 printf("Received multicast octets:\t\t%d\n",
624 c->wi_rx_multicast_octets);
625 printf("Receive FCS errors:\t\t\t%d\n",
626 c->wi_rx_fcs_errors);
627 printf("Receive discards due to no buffer:\t%d\n",
628 c->wi_rx_discards_nobuf);
629 printf("Can't decrypt WEP frame:\t\t%d\n",
630 c->wi_rx_WEP_cant_decrypt);
631 printf("Received message fragments:\t\t%d\n",
632 c->wi_rx_msg_in_msg_frags);
633 printf("Received message bad fragments:\t\t%d\n",
634 c->wi_rx_msg_in_bad_msg_frags);
635
636 return;
637 }
638
639 static void
640 usage()
641 {
642
643 fprintf(stderr,
644 "usage: %s interface "
645 "[-o] [-t tx rate] [-n network name] [-s station name]\n"
646 " [-e 0|1] [-k key [-v 1|2|3|4]] [-T 1|2|3|4]\n"
647 " [-c 0|1] [-q SSID] [-p port type] [-a access point density]\n"
648 " [-m MAC address] [-d max data length] [-r RTS threshold]\n"
649 " [-f frequency] [-M 0|1] [-P 0|1] [-S max sleep duration]\n"
650 " [-A 0|1 ] [-R 1|3]\n"
651 ,
652 getprogname());
653 exit(1);
654 }
655
656 int main(argc, argv)
657 int argc;
658 char *argv[];
659 {
660 struct wi_table *wt, **table;
661 char *iface, *key, *keyv[4], *tx_crypt_key;
662 int ch, dumpinfo, dumpstats, modifier, oldind;
663
664 #define SET_OPERAND(opr, desc) do { \
665 if ((opr) == NULL) \
666 (opr) = optarg; \
667 else \
668 warnx("%s is already specified to %s", \
669 desc, (opr)); \
670 } while (0)
671
672 dumpinfo = 1;
673 dumpstats = 0;
674 iface = key = keyv[0] = keyv[1] = keyv[2] = keyv[3] =
675 tx_crypt_key = NULL;
676
677 if (argc > 1 && argv[1][0] != '-') {
678 iface = argv[1];
679 optind++;
680 }
681
682 while ((ch = getopt(argc, argv,
683 "a:c:d:e:f:hi:k:m:n:op:q:r:s:t:A:M:S:P:R:T:")) != -1) {
684 if (ch != 'i')
685 dumpinfo = 0;
686 /*
687 * Lookup generic options and remeber operand if found.
688 */
689 for (table = wi_tables; *table != NULL; table++)
690 if ((wt = wi_optlookup(*table, ch)) != NULL) {
691 SET_OPERAND(wt->wi_optval, wt->wi_desc);
692 break;
693 }
694 if (wt == NULL)
695 /*
696 * Handle special options.
697 */
698 switch (ch) {
699 case 'o':
700 dumpstats = 1;
701 break;
702 case 'i':
703 SET_OPERAND(iface, "interface");
704 break;
705 case 'k':
706 key = optarg;
707 oldind = optind;
708 opterr = 0;
709 ch = getopt(argc, argv, "v:");
710 opterr = 1;
711 switch (ch) {
712 case 'v':
713 modifier = atoi(optarg) - 1;
714 break;
715 default:
716 modifier = 0;
717 optind = oldind;
718 break;
719 }
720 keyv[modifier] = key;
721 break;
722 case 'T':
723 SET_OPERAND(tx_crypt_key, "TX encryption key");
724 break;
725 case 'h':
726 default:
727 usage();
728 break;
729 }
730 }
731
732 if (iface == NULL)
733 usage();
734
735 for (table = wi_tables; *table != NULL; table++)
736 for (wt = *table; wt->wi_code != WI_NONE; wt++)
737 if (wt->wi_optval != NULL) {
738 switch (wt->wi_code) {
739 case WI_BOOL:
740 case WI_WORDS:
741 wi_setword(iface, wt->wi_type,
742 atoi(wt->wi_optval));
743 break;
744 case WI_STRING:
745 wi_setstr(iface, wt->wi_type,
746 wt->wi_optval);
747 break;
748 case WI_HEXBYTES:
749 wi_sethex(iface, wt->wi_type,
750 wt->wi_optval);
751 break;
752 }
753 }
754
755 if (tx_crypt_key != NULL)
756 wi_setword(iface, WI_RID_TX_CRYPT_KEY, atoi(tx_crypt_key) - 1);
757
758 for (modifier = 0; modifier < sizeof(keyv) / sizeof(keyv[0]);
759 modifier++)
760 if (keyv[modifier] != NULL)
761 wi_setkeys(iface, keyv[modifier], modifier);
762
763 if (dumpstats)
764 wi_dumpstats(iface);
765 if (dumpinfo)
766 wi_dumpinfo(iface);
767
768 exit(0);
769 }
770