wiconfig.c revision 1.22 1 /* $NetBSD: wiconfig.c,v 1.22 2002/03/04 01:26:58 dbj 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 <net/if_ieee80211.h>
54 #include <dev/ic/wi_ieee.h>
55 #else
56 #include <dev/pcmcia/if_wavelan_ieee.h>
57 #endif
58 #endif
59
60 #include <stdio.h>
61 #include <string.h>
62 #include <ctype.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 #include <errno.h>
66 #include <err.h>
67
68 #if !defined(lint)
69 static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\
70 Bill Paul. All rights reserved.";
71 static const char rcsid[] =
72 "@(#) $Id: wiconfig.c,v 1.22 2002/03/04 01:26:58 dbj Exp $";
73 #endif
74
75 struct wi_table {
76 int wi_type;
77 int wi_code;
78 #define WI_NONE 0x00
79 #define WI_STRING 0x01
80 #define WI_BOOL 0x02
81 #define WI_WORDS 0x03
82 #define WI_HEXBYTES 0x04
83 #define WI_KEYSTRUCT 0x05
84 #define WI_BITS 0x06
85 char *wi_label; /* label used to print info */
86 int wi_opt; /* option character to set this */
87 char *wi_desc;
88 char *wi_optval;
89 };
90
91 /* already define in wireg.h XXX */
92 #define WI_APRATE_0 0x00 /* NONE */
93 #define WI_APRATE_1 0x0A /* 1 Mbps */
94 #define WI_APRATE_2 0x14 /* 2 Mbps */
95 #define WI_APRATE_5 0x37 /* 5.5 Mbps */
96 #define WI_APRATE_11 0x6E /* 11 Mbps */
97
98 #ifdef WI_RID_SCAN_APS
99 static void wi_apscan __P((char *));
100 static int get_if_flags __P((int, const char *));
101 static int set_if_flags __P((int, const char *, int));
102 #endif
103 static void wi_getval __P((char *, struct wi_req *));
104 static void wi_setval __P((char *, struct wi_req *));
105 static void wi_printstr __P((struct wi_req *));
106 static void wi_setstr __P((char *, int, char *));
107 static void wi_setbytes __P((char *, int, char *, int));
108 static void wi_setword __P((char *, int, int));
109 static void wi_sethex __P((char *, int, char *));
110 static void wi_printwords __P((struct wi_req *));
111 static void wi_printbool __P((struct wi_req *));
112 static void wi_printhex __P((struct wi_req *));
113 static void wi_printbits __P((struct wi_req *));
114 static void wi_dumpinfo __P((char *));
115 static void wi_setkeys __P((char *, char *, int));
116 static void wi_printkeys __P((struct wi_req *));
117 static void wi_dumpstats __P((char *));
118 static void usage __P((void));
119 static struct wi_table *
120 wi_optlookup __P((struct wi_table *, int));
121 static int wi_hex2int(char c);
122 static void wi_str2key __P((char *, struct wi_key *));
123 int main __P((int argc, char **argv));
124
125 #ifdef WI_RID_SCAN_APS
126 static int get_if_flags(s, name)
127 int s;
128 const char *name;
129 {
130 struct ifreq ifreq;
131 int flags;
132
133 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
134 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) == -1)
135 err(1, "SIOCGIFFLAGS");
136 flags = ifreq.ifr_flags;
137
138 return flags;
139 }
140
141 static int set_if_flags(s, name, flags)
142 int s;
143 const char *name;
144 int flags;
145 {
146 struct ifreq ifreq;
147
148 ifreq.ifr_flags = flags;
149 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
150 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) == -1)
151 err(1, "SIOCSIFFLAGS");
152
153 return 0;
154 }
155
156 static void wi_apscan(iface)
157 char *iface;
158 {
159 struct wi_req wreq;
160 struct ifreq ifr;
161 int s;
162 int naps, rate;
163 int retries = 10;
164 int flags;
165 struct wi_apinfo *w;
166 int i, j;
167
168 if (iface == NULL)
169 errx(1, "must specify interface name");
170
171 s = socket(AF_INET, SOCK_DGRAM, 0);
172 if (s == -1)
173 err(1, "socket");
174 flags = get_if_flags(s, iface);
175 if ((flags & IFF_UP) == 0)
176 flags = set_if_flags(s, iface, flags | IFF_UP);
177
178 memset((char *)&wreq, 0, sizeof(wreq));
179
180 wreq.wi_type = WI_RID_SCAN_APS;
181 wreq.wi_len = 4;
182 /* note chan. 1 is the least significant bit */
183 wreq.wi_val[0] = 0x7ff; /* 1 bit per channel, 1-11 */
184 wreq.wi_val[1] = 3; /* tx rate */
185
186 /* write the request */
187 wi_setval(iface, &wreq);
188
189 /* now poll for a result */
190 memset((char *)&wreq, 0, sizeof(wreq));
191
192 wreq.wi_type = WI_RID_READ_APS;
193 wreq.wi_len = WI_MAX_DATALEN;
194
195 /* we have to do this ourself as opposed to
196 * using getval, because we cannot bail if
197 * the ioctl fails
198 */
199 memset((char *)&ifr, 0, sizeof(ifr));
200 strcpy(ifr.ifr_name, iface);
201 ifr.ifr_data = (caddr_t)&wreq;
202
203 printf("scanning ...");
204 fflush(stdout);
205 while (ioctl(s, SIOCGWAVELAN, &ifr) == -1) {
206 retries--;
207 if (retries >= 0) {
208 printf("."); fflush(stdout);
209 sleep(1);
210 } else
211 break;
212 errno = 0;
213 }
214
215 if (errno) {
216 set_if_flags(s, iface, flags);
217 close(s);
218 err(1, "ioctl");
219 }
220 printf("\nAP Information\n");
221
222 naps = *(int *)wreq.wi_val;
223 w = (struct wi_apinfo *)(((char *)&wreq.wi_val) + sizeof(int));
224 for ( i = 0; i < naps; i++, w++) {
225 printf("ap[%d]:\n", i);
226 if (w->scanreason) {
227 static char *scanm[] = {
228 "Host initiated",
229 "Firmware initiated",
230 "Inquiry request from host"
231 };
232 printf("\tScanReason:\t\t\t[ %s ]\n",
233 scanm[w->scanreason - 1]);
234 }
235 printf("\tnetname (SSID):\t\t\t[ ");
236 for (j = 0; j < w->namelen; j++) {
237 printf("%c", w->name[j]);
238 }
239 printf(" ]\n");
240 printf("\tBSSID:\t\t\t\t[ %02x:%02x:%02x:%02x:%02x:%02x ]\n",
241 w->bssid[0]&0xff, w->bssid[1]&0xff,
242 w->bssid[2]&0xff, w->bssid[3]&0xff,
243 w->bssid[4]&0xff, w->bssid[5]&0xff);
244 printf("\tChannel:\t\t\t[ %d ]\n", w->channel);
245 printf("\tQuality/Signal/Noise [signal]:\t[ %d / %d / %d ]\n"
246 "\t [dBm]:\t[ %d / %d / %d ]\n",
247 w->quality, w->signal, w->noise,
248 w->quality, w->signal - 149, w->noise - 149);
249 printf("\tBSS Beacon Interval [msec]:\t[ %d ]\n", w->interval);
250 printf("\tCapinfo:\t\t\t[ ");
251 if (w->capinfo & IEEE80211_CAPINFO_ESS)
252 printf("ESS ");
253 if (w->capinfo & IEEE80211_CAPINFO_PRIVACY)
254 printf("WEP ");
255 printf("]\n");
256
257 switch (w->rate) {
258 case WI_APRATE_1:
259 rate = 1;
260 break;
261 case WI_APRATE_2:
262 rate = 2;
263 break;
264 case WI_APRATE_5:
265 rate = 5.5;
266 break;
267 case WI_APRATE_11:
268 rate = 11;
269 break;
270 case WI_APRATE_0:
271 default:
272 rate = 0;
273 break;
274 }
275 if (rate) printf("\tDataRate [Mbps]:\t\t[ %d ]\n", rate);
276 }
277
278 set_if_flags(s, iface, flags);
279 close(s);
280 }
281 #endif
282
283 static void wi_getval(iface, wreq)
284 char *iface;
285 struct wi_req *wreq;
286 {
287 struct ifreq ifr;
288 int s;
289
290 bzero((char *)&ifr, sizeof(ifr));
291
292 strcpy(ifr.ifr_name, iface);
293 ifr.ifr_data = (caddr_t)wreq;
294
295 s = socket(AF_INET, SOCK_DGRAM, 0);
296
297 if (s == -1)
298 err(1, "socket");
299
300 if (ioctl(s, SIOCGWAVELAN, &ifr) == -1)
301 err(1, "SIOCGWAVELAN");
302
303 close(s);
304
305 return;
306 }
307
308 static void wi_setval(iface, wreq)
309 char *iface;
310 struct wi_req *wreq;
311 {
312 struct ifreq ifr;
313 int s;
314
315 bzero((char *)&ifr, sizeof(ifr));
316
317 strcpy(ifr.ifr_name, iface);
318 ifr.ifr_data = (caddr_t)wreq;
319
320 s = socket(AF_INET, SOCK_DGRAM, 0);
321
322 if (s == -1)
323 err(1, "socket");
324
325 if (ioctl(s, SIOCSWAVELAN, &ifr) == -1)
326 err(1, "SIOCSWAVELAN");
327
328 close(s);
329
330 return;
331 }
332
333 void wi_printstr(wreq)
334 struct wi_req *wreq;
335 {
336 char *ptr;
337 int i;
338
339 if (wreq->wi_type == WI_RID_SERIALNO) {
340 ptr = (char *)&wreq->wi_val;
341 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
342 if (ptr[i] == '\0')
343 ptr[i] = ' ';
344 }
345 } else {
346 int len = le16toh(wreq->wi_val[0]);
347
348 ptr = (char *)&wreq->wi_val[1];
349 for (i = 0; i < len; i++) {
350 if (ptr[i] == '\0')
351 ptr[i] = ' ';
352 }
353 }
354
355 ptr[i] = '\0';
356 printf("[ %s ]", ptr);
357
358 return;
359 }
360
361 void wi_setstr(iface, code, str)
362 char *iface;
363 int code;
364 char *str;
365 {
366 struct wi_req wreq;
367
368 bzero((char *)&wreq, sizeof(wreq));
369
370 if (strlen(str) > 30)
371 errx(1, "string too long");
372
373 wreq.wi_type = code;
374 wreq.wi_len = 18;
375 wreq.wi_val[0] = htole16(strlen(str));
376 bcopy(str, (char *)&wreq.wi_val[1], strlen(str));
377
378 wi_setval(iface, &wreq);
379
380 return;
381 }
382
383 void wi_setbytes(iface, code, bytes, len)
384 char *iface;
385 int code;
386 char *bytes;
387 int len;
388 {
389 struct wi_req wreq;
390
391 bzero((char *)&wreq, sizeof(wreq));
392
393 wreq.wi_type = code;
394 wreq.wi_len = (len / 2) + 1;
395 bcopy(bytes, (char *)&wreq.wi_val[0], len);
396
397 wi_setval(iface, &wreq);
398
399 return;
400 }
401
402 void wi_setword(iface, code, word)
403 char *iface;
404 int code;
405 int word;
406 {
407 struct wi_req wreq;
408
409 bzero((char *)&wreq, sizeof(wreq));
410
411 wreq.wi_type = code;
412 wreq.wi_len = 2;
413 wreq.wi_val[0] = htole16(word);
414
415 wi_setval(iface, &wreq);
416
417 return;
418 }
419
420 void wi_sethex(iface, code, str)
421 char *iface;
422 int code;
423 char *str;
424 {
425 struct ether_addr *addr;
426
427 addr = ether_aton(str);
428 if (addr == NULL)
429 errx(1, "badly formatted address");
430
431 wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN);
432
433 return;
434 }
435
436 static int
437 wi_hex2int(char c)
438 {
439 if (c >= '0' && c <= '9')
440 return (c - '0');
441 if (c >= 'A' && c <= 'F')
442 return (c - 'A' + 10);
443 if (c >= 'a' && c <= 'f')
444 return (c - 'a' + 10);
445
446 return (0);
447 }
448
449 static void wi_str2key(s, k)
450 char *s;
451 struct wi_key *k;
452 {
453 int n, i;
454 char *p;
455
456 /* Is this a hex string? */
457 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
458 /* Yes, convert to int. */
459 n = 0;
460 p = (char *)&k->wi_keydat[0];
461 for (i = 2; i < strlen(s); i+= 2) {
462 *p++ = (wi_hex2int(s[i]) << 4) + wi_hex2int(s[i + 1]);
463 n++;
464 }
465 k->wi_keylen = htole16(n);
466 } else {
467 /* No, just copy it in. */
468 bcopy(s, k->wi_keydat, strlen(s));
469 k->wi_keylen = htole16(strlen(s));
470 }
471
472 return;
473 }
474
475 static void wi_setkeys(iface, key, idx)
476 char *iface;
477 char *key;
478 int idx;
479 {
480 struct wi_req wreq;
481 struct wi_ltv_keys *keys;
482 struct wi_key *k;
483
484 bzero((char *)&wreq, sizeof(wreq));
485 wreq.wi_len = WI_MAX_DATALEN;
486 wreq.wi_type = WI_RID_WEP_AVAIL;
487
488 wi_getval(iface, &wreq);
489 if (le16toh(wreq.wi_val[0]) == 0)
490 err(1, "no WEP option available on this card");
491
492 bzero((char *)&wreq, sizeof(wreq));
493 wreq.wi_len = WI_MAX_DATALEN;
494 wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
495
496 wi_getval(iface, &wreq);
497 keys = (struct wi_ltv_keys *)&wreq;
498
499 if (key[0] == '0' && (key[1] == 'x' || key[1] == 'X')) {
500 if (strlen(key) > 30)
501 err(1, "encryption key must be no "
502 "more than 28 hex digits long");
503 } else {
504 if (strlen(key) > 14)
505 err(1, "encryption key must be no "
506 "more than 14 characters long");
507 }
508
509 if (idx > 3)
510 err(1, "only 4 encryption keys available");
511
512 k = &keys->wi_keys[idx];
513 wi_str2key(key, k);
514
515 wreq.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
516 wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
517 wi_setval(iface, &wreq);
518
519 return;
520 }
521
522 static void wi_printkeys(wreq)
523 struct wi_req *wreq;
524 {
525 int i, j, bn;
526 struct wi_key *k;
527 struct wi_ltv_keys *keys;
528 char *ptr;
529
530 keys = (struct wi_ltv_keys *)wreq;
531
532 for (i = 0, bn = 0; i < 4; i++, bn = 0) {
533 k = &keys->wi_keys[i];
534 ptr = (char *)k->wi_keydat;
535 for (j = 0; j < le16toh(k->wi_keylen); j++) {
536 if (!isprint((unsigned char) ptr[j])) {
537 bn = 1;
538 break;
539 }
540 }
541
542 if (bn) {
543 printf("[ 0x");
544 for (j = 0; j < le16toh(k->wi_keylen); j++)
545 printf("%02x", ((unsigned char *) ptr)[j]);
546 printf(" ]");
547 } else {
548 ptr[j] = '\0';
549 printf("[ %s ]", ptr);
550 }
551 }
552
553 return;
554 };
555
556 void wi_printwords(wreq)
557 struct wi_req *wreq;
558 {
559 int i;
560
561 printf("[ ");
562 for (i = 0; i < wreq->wi_len - 1; i++)
563 printf("%d ", le16toh(wreq->wi_val[i]));
564 printf("]");
565
566 return;
567 }
568
569 void wi_printbool(wreq)
570 struct wi_req *wreq;
571 {
572 if (le16toh(wreq->wi_val[0]))
573 printf("[ On ]");
574 else
575 printf("[ Off ]");
576
577 return;
578 }
579
580 void wi_printhex(wreq)
581 struct wi_req *wreq;
582 {
583 int i;
584 unsigned char *c;
585
586 c = (unsigned char *)&wreq->wi_val;
587
588 printf("[ ");
589 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
590 printf("%02x", c[i]);
591 if (i < ((wreq->wi_len - 1) * 2) - 1)
592 printf(":");
593 }
594
595 printf(" ]");
596 return;
597 }
598
599 void wi_printbits(wreq)
600 struct wi_req *wreq;
601 {
602 int i;
603 int bits = le16toh(wreq->wi_val[0]);
604
605 printf("[");
606 for (i = 0; i < 16; i++) {
607 if (bits & 0x1) {
608 printf(" %d", i+1);
609 }
610 bits >>= 1;
611 }
612 printf(" ]");
613 return;
614 }
615
616 static struct wi_table wi_table[] = {
617 { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" },
618 { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t",
619 's', "station name" },
620 { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t",
621 'q', "own SSID" },
622 { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" },
623 { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t",
624 'n', "network name" },
625 { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" },
626 { WI_RID_CHANNEL_LIST, WI_BITS, "Channel list:\t\t\t\t" },
627 { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t",
628 'f', "frequency" },
629 { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" },
630 { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" },
631 { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" },
632 { WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t",
633 'p', "port type" },
634 { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t",
635 'm', "MAC address" },
636 { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t",
637 't', "TX rate" },
638 { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"},
639 { WI_RID_OWN_BEACON_INT, WI_WORDS, "Beacon Interval (current) [msec]:\t"},
640 { WI_RID_MAX_DATALEN, WI_WORDS, "Maximum data length:\t\t\t",
641 'd', "maximum data length" },
642 { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t",
643 'r', "RTS threshold" },
644 { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t",
645 'c', "create ibss" },
646 { WI_RID_MICROWAVE_OVEN, WI_WORDS, "Microwave oven robustness:\t\t",
647 'M', "microwave oven robustness enabled" },
648 { WI_RID_ROAMING_MODE, WI_WORDS, "Roaming mode(1:firm,3:disable):\t\t",
649 'R', "roaming mode" },
650 { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t",
651 'a', "system scale" },
652 { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t",
653 'P', "power management enabled" },
654 { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time (msec):\t\t\t",
655 'S', "max sleep duration" },
656 { 0, WI_NONE }
657 };
658
659 static struct wi_table wi_crypt_table[] = {
660 { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t",
661 'e', "encryption" },
662 { WI_RID_AUTH_CNTL, WI_WORDS, "Authentication type \n(1=OpenSys, 2=Shared Key):\t\t",
663 'A', "authentication type" },
664 { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" },
665 { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" },
666 { 0, WI_NONE }
667 };
668
669 static struct wi_table *wi_tables[] = {
670 wi_table,
671 wi_crypt_table,
672 NULL
673 };
674
675 static struct wi_table *
676 wi_optlookup(table, opt)
677 struct wi_table *table;
678 int opt;
679 {
680 struct wi_table *wt;
681
682 for (wt = table; wt->wi_type != 0; wt++)
683 if (wt->wi_opt == opt)
684 return (wt);
685 return (NULL);
686 }
687
688 static void wi_dumpinfo(iface)
689 char *iface;
690 {
691 struct wi_req wreq;
692 int i, has_wep;
693 struct wi_table *w;
694
695 bzero((char *)&wreq, sizeof(wreq));
696
697 wreq.wi_len = WI_MAX_DATALEN;
698 wreq.wi_type = WI_RID_WEP_AVAIL;
699
700 wi_getval(iface, &wreq);
701 has_wep = le16toh(wreq.wi_val[0]);
702
703 w = wi_table;
704
705 for (i = 0; w[i].wi_code != WI_NONE; i++) {
706 bzero((char *)&wreq, sizeof(wreq));
707
708 wreq.wi_len = WI_MAX_DATALEN;
709 wreq.wi_type = w[i].wi_type;
710
711 wi_getval(iface, &wreq);
712 printf("%s", w[i].wi_label);
713 switch (w[i].wi_code) {
714 case WI_STRING:
715 wi_printstr(&wreq);
716 break;
717 case WI_WORDS:
718 wi_printwords(&wreq);
719 break;
720 case WI_BOOL:
721 wi_printbool(&wreq);
722 break;
723 case WI_HEXBYTES:
724 wi_printhex(&wreq);
725 break;
726 case WI_BITS:
727 wi_printbits(&wreq);
728 break;
729 default:
730 break;
731 }
732 printf("\n");
733 }
734
735 if (has_wep) {
736 w = wi_crypt_table;
737 for (i = 0; w[i].wi_code != WI_NONE; i++) {
738 bzero((char *)&wreq, sizeof(wreq));
739
740 wreq.wi_len = WI_MAX_DATALEN;
741 wreq.wi_type = w[i].wi_type;
742
743 wi_getval(iface, &wreq);
744 printf("%s", w[i].wi_label);
745 switch (w[i].wi_code) {
746 case WI_STRING:
747 wi_printstr(&wreq);
748 break;
749 case WI_WORDS:
750 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
751 wreq.wi_val[0] =
752 htole16(le16toh(wreq.wi_val[0]) + 1);
753 wi_printwords(&wreq);
754 break;
755 case WI_BOOL:
756 wi_printbool(&wreq);
757 break;
758 case WI_HEXBYTES:
759 wi_printhex(&wreq);
760 break;
761 case WI_KEYSTRUCT:
762 wi_printkeys(&wreq);
763 break;
764 default:
765 break;
766 }
767 printf("\n");
768 }
769 }
770
771 return;
772 }
773
774 static void wi_dumpstats(iface)
775 char *iface;
776 {
777 struct wi_req wreq;
778 struct wi_counters *c;
779
780 bzero((char *)&wreq, sizeof(wreq));
781 wreq.wi_len = WI_MAX_DATALEN;
782 wreq.wi_type = WI_RID_IFACE_STATS;
783
784 wi_getval(iface, &wreq);
785
786 c = (struct wi_counters *)&wreq.wi_val;
787
788 /* XXX native byte order */
789 printf("Transmitted unicast frames:\t\t%d\n",
790 c->wi_tx_unicast_frames);
791 printf("Transmitted multicast frames:\t\t%d\n",
792 c->wi_tx_multicast_frames);
793 printf("Transmitted fragments:\t\t\t%d\n",
794 c->wi_tx_fragments);
795 printf("Transmitted unicast octets:\t\t%d\n",
796 c->wi_tx_unicast_octets);
797 printf("Transmitted multicast octets:\t\t%d\n",
798 c->wi_tx_multicast_octets);
799 printf("Single transmit retries:\t\t%d\n",
800 c->wi_tx_single_retries);
801 printf("Multiple transmit retries:\t\t%d\n",
802 c->wi_tx_multi_retries);
803 printf("Transmit retry limit exceeded:\t\t%d\n",
804 c->wi_tx_retry_limit);
805 printf("Transmit discards:\t\t\t%d\n",
806 c->wi_tx_discards);
807 printf("Transmit discards due to wrong SA:\t%d\n",
808 c->wi_tx_discards_wrong_sa);
809 printf("Received unicast frames:\t\t%d\n",
810 c->wi_rx_unicast_frames);
811 printf("Received multicast frames:\t\t%d\n",
812 c->wi_rx_multicast_frames);
813 printf("Received fragments:\t\t\t%d\n",
814 c->wi_rx_fragments);
815 printf("Received unicast octets:\t\t%d\n",
816 c->wi_rx_unicast_octets);
817 printf("Received multicast octets:\t\t%d\n",
818 c->wi_rx_multicast_octets);
819 printf("Receive FCS errors:\t\t\t%d\n",
820 c->wi_rx_fcs_errors);
821 printf("Receive discards due to no buffer:\t%d\n",
822 c->wi_rx_discards_nobuf);
823 printf("Can't decrypt WEP frame:\t\t%d\n",
824 c->wi_rx_WEP_cant_decrypt);
825 printf("Received message fragments:\t\t%d\n",
826 c->wi_rx_msg_in_msg_frags);
827 printf("Received message bad fragments:\t\t%d\n",
828 c->wi_rx_msg_in_bad_msg_frags);
829
830 return;
831 }
832
833 static void
834 usage()
835 {
836
837 fprintf(stderr,
838 "usage: %s interface "
839 "[-oD] [-t tx rate] [-n network name] [-s station name]\n"
840 " [-e 0|1] [-k key [-v 1|2|3|4]] [-T 1|2|3|4]\n"
841 " [-c 0|1] [-q SSID] [-p port type] [-a access point density]\n"
842 " [-m MAC address] [-d max data length] [-r RTS threshold]\n"
843 " [-f frequency] [-M 0|1] [-P 0|1] [-S max sleep duration]\n"
844 " [-A 0|1 ] [-R 1|3]\n"
845 ,
846 getprogname());
847 exit(1);
848 }
849
850 int main(argc, argv)
851 int argc;
852 char *argv[];
853 {
854 struct wi_table *wt, **table;
855 char *iface, *key, *keyv[4], *tx_crypt_key;
856 int ch, dumpinfo, dumpstats, modifier, oldind, apscan;
857
858 #define SET_OPERAND(opr, desc) do { \
859 if ((opr) == NULL) \
860 (opr) = optarg; \
861 else \
862 warnx("%s is already specified to %s", \
863 desc, (opr)); \
864 } while (0)
865
866 dumpinfo = 1;
867 dumpstats = 0;
868 apscan = 0;
869 iface = key = keyv[0] = keyv[1] = keyv[2] = keyv[3] =
870 tx_crypt_key = NULL;
871
872 if (argc > 1 && argv[1][0] != '-') {
873 iface = argv[1];
874 optind++;
875 }
876
877 while ((ch = getopt(argc, argv,
878 "a:c:d:e:f:hi:k:m:n:op:q:r:s:t:A:M:S:P:R:T:DZ:")) != -1) {
879 if (ch != 'i')
880 dumpinfo = 0;
881 /*
882 * Lookup generic options and remeber operand if found.
883 */
884 for (table = wi_tables; *table != NULL; table++)
885 if ((wt = wi_optlookup(*table, ch)) != NULL) {
886 SET_OPERAND(wt->wi_optval, wt->wi_desc);
887 break;
888 }
889 if (wt == NULL)
890 /*
891 * Handle special options.
892 */
893 switch (ch) {
894 case 'o':
895 dumpstats = 1;
896 break;
897 case 'i':
898 SET_OPERAND(iface, "interface");
899 break;
900 case 'k':
901 key = optarg;
902 oldind = optind;
903 opterr = 0;
904 ch = getopt(argc, argv, "v:");
905 opterr = 1;
906 switch (ch) {
907 case 'v':
908 modifier = atoi(optarg) - 1;
909 break;
910 default:
911 modifier = 0;
912 optind = oldind;
913 break;
914 }
915 keyv[modifier] = key;
916 break;
917 case 'T':
918 SET_OPERAND(tx_crypt_key, "TX encryption key");
919 break;
920 case 'D':
921 apscan = 1;
922 break;
923 case 'h':
924 default:
925 usage();
926 break;
927 }
928 }
929
930 if (iface == NULL)
931 usage();
932
933 for (table = wi_tables; *table != NULL; table++)
934 for (wt = *table; wt->wi_code != WI_NONE; wt++)
935 if (wt->wi_optval != NULL) {
936 switch (wt->wi_code) {
937 case WI_BOOL:
938 case WI_WORDS:
939 wi_setword(iface, wt->wi_type,
940 atoi(wt->wi_optval));
941 break;
942 case WI_STRING:
943 wi_setstr(iface, wt->wi_type,
944 wt->wi_optval);
945 break;
946 case WI_HEXBYTES:
947 wi_sethex(iface, wt->wi_type,
948 wt->wi_optval);
949 break;
950 }
951 }
952
953 if (tx_crypt_key != NULL)
954 wi_setword(iface, WI_RID_TX_CRYPT_KEY, atoi(tx_crypt_key) - 1);
955
956 for (modifier = 0; modifier < sizeof(keyv) / sizeof(keyv[0]);
957 modifier++)
958 if (keyv[modifier] != NULL)
959 wi_setkeys(iface, keyv[modifier], modifier);
960
961 if (dumpstats)
962 wi_dumpstats(iface);
963 if (dumpinfo)
964 wi_dumpinfo(iface);
965
966 if (apscan)
967 #ifdef WI_RID_SCAN_APS
968 wi_apscan(iface);
969 #else
970 errx(1, "AP scan mode is not available.");
971 #endif
972
973 exit(0);
974 }
975