]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/wicontrol/wicontrol.c
- Restore header printing to wi_printaplist()
[FreeBSD/FreeBSD.git] / usr.sbin / wicontrol / wicontrol.c
1 /*
2  * Copyright (c) 1997, 1998, 1999
3  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #ifndef lint
34 static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\
35         Bill Paul. All rights reserved.";
36 static const char rcsid[] =
37         "$FreeBSD$";
38 #endif /* not lint */
39
40 #include <sys/types.h>
41 #include <sys/cdefs.h>
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <net/ethernet.h>
50
51 #include <net/if_ieee80211.h>
52 #include <dev/wi/if_wavelan_ieee.h>
53 #include <dev/wi/if_wireg.h>
54
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <ctype.h>
60 #include <errno.h>
61 #include <err.h>
62
63 static int wi_getval(const char *, struct wi_req *);
64 static void wi_setval(const char *, struct wi_req *);
65 static void wi_printstr(struct wi_req *);
66 static void wi_setstr(const char *, int, char *);
67 static void wi_setbytes(const char *, int, char *, int);
68 static void wi_setword(const char *, int, int);
69 static void wi_sethex(const char *, int, char *);
70 static void wi_printwords(struct wi_req *);
71 static void wi_printbool(struct wi_req *);
72 static void wi_printhex(struct wi_req *);
73 static void wi_printaps(struct wi_req *);
74 static void wi_dumpinfo(const char *);
75 static void wi_dumpstats(const char *);
76 static void wi_setkeys(const char *, char *, int);
77 static void wi_printkeys(struct wi_req *);
78 static void wi_printaplist(const char *);
79 static int wi_hex2int(char);
80 static void wi_str2key(char *, struct wi_key *);
81 #ifdef WICACHE
82 static void wi_zerocache(const char *);
83 static void wi_readcache(const char *);
84 #endif
85 static void usage(const char *);
86 static int listaps;
87 static int quiet;
88
89 /*
90  * Print a value a la the %b format of the kernel's printf
91  * (ripped screaming from ifconfig/ifconfig.c)
92  */
93 void
94 printb(char *s, uint32_t v, char *bits)
95 {
96         int i, any = 0;
97         char c;
98
99         if (bits && *bits == 8)
100                 printf("%s=%o", s, v);
101         else
102                 printf("%s=%x", s, v);
103         bits++;
104         if (bits) {
105                 putchar('<');
106                 while ((i = *bits++)) {
107                         if (v & (1 << (i-1))) {
108                                 if (any)
109                                         putchar(',');
110                                 any = 1;
111                                 for (; (c = *bits) > 32; bits++)
112                                         putchar(c);
113                         } else
114                                 for (; *bits > 32; bits++)
115                                         ;
116                 }
117                 putchar('>');
118         }
119 }
120
121 static int
122 wi_getval(const char *iface, struct wi_req *wreq)
123 {
124         struct ifreq            ifr;
125         int                     s;
126
127         bzero((char *)&ifr, sizeof(ifr));
128
129         strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
130         ifr.ifr_data = (caddr_t)wreq;
131
132         s = socket(AF_INET, SOCK_DGRAM, 0);
133
134         if (s == -1)
135                 err(1, "socket");
136
137         if (ioctl(s, SIOCGWAVELAN, &ifr) == -1) {
138                 if (errno != EINPROGRESS)
139                         err(1, "SIOCGWAVELAN");
140                 return (-1);
141         }
142
143         close(s);
144
145         return (0);
146 }
147
148 static void
149 wi_setval(const char *iface, struct wi_req *wreq)
150 {
151         struct ifreq            ifr;
152         int                     s;
153
154         bzero((char *)&ifr, sizeof(ifr));
155
156         strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
157         ifr.ifr_data = (caddr_t)wreq;
158
159         s = socket(AF_INET, SOCK_DGRAM, 0);
160
161         if (s == -1)
162                 err(1, "socket");
163
164         if (ioctl(s, SIOCSWAVELAN, &ifr) == -1)
165                 err(1, "SIOCSWAVELAN");
166
167         close(s);
168
169         return;
170 }
171
172 void
173 wi_printstr(struct wi_req *wreq)
174 {
175         char                    *ptr;
176         int                     i;
177
178         if (wreq->wi_type == WI_RID_SERIALNO) {
179                 ptr = (char *)&wreq->wi_val;
180                 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
181                         if (ptr[i] == '\0')
182                                 ptr[i] = ' ';
183                 }
184         } else {
185                 ptr = (char *)&wreq->wi_val[1];
186                 for (i = 0; i < wreq->wi_val[0]; i++) {
187                         if (ptr[i] == '\0')
188                                 ptr[i] = ' ';
189                 }
190         }
191
192         ptr[i] = '\0';
193         printf("[ %s ]", ptr);
194
195         return;
196 }
197
198 void
199 wi_setstr(const char *iface, int code, char *str)
200 {
201         struct wi_req           wreq;
202
203         if (iface == NULL)
204                 errx(1, "must specify interface name");
205
206         if (str == NULL)
207                 errx(1, "must specify string");
208
209         bzero((char *)&wreq, sizeof(wreq));
210
211         if (strlen(str) > 30)
212                 errx(1, "string too long");
213
214         wreq.wi_type = code;
215         wreq.wi_len = 18;
216         wreq.wi_val[0] = strlen(str);
217         bcopy(str, (char *)&wreq.wi_val[1], strlen(str));
218
219         wi_setval(iface, &wreq);
220
221         return;
222 }
223
224 void
225 wi_setbytes(const char *iface, int code, char *bytes, int len)
226 {
227         struct wi_req           wreq;
228
229         if (iface == NULL)
230                 errx(1, "must specify interface name");
231
232         bzero((char *)&wreq, sizeof(wreq));
233
234         wreq.wi_type = code;
235         wreq.wi_len = (len / 2) + 1;
236         bcopy(bytes, (char *)&wreq.wi_val[0], len);
237
238         wi_setval(iface, &wreq);
239
240         return;
241 }
242
243 void
244 wi_setword(const char *iface, int code, int word)
245 {
246         struct wi_req           wreq;
247
248         bzero((char *)&wreq, sizeof(wreq));
249
250         wreq.wi_type = code;
251         wreq.wi_len = 2;
252         wreq.wi_val[0] = word;
253
254         wi_setval(iface, &wreq);
255
256         return;
257 }
258
259 void
260 wi_sethex(const char *iface, int code, char *str)
261 {
262         struct ether_addr       *addr;
263
264         if (str == NULL)
265                 errx(1, "must specify address");
266
267         addr = ether_aton(str);
268
269         if (addr == NULL)
270                 errx(1, "badly formatted address");
271
272         wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN);
273
274         return;
275 }
276
277 static int
278 wi_hex2int(char c)
279 {
280         if (c >= '0' && c <= '9')
281                 return (c - '0');
282         if (c >= 'A' && c <= 'F')
283                 return (c - 'A' + 10);
284         if (c >= 'a' && c <= 'f')
285                 return (c - 'a' + 10);
286
287         return (0); 
288 }
289
290 static void
291 wi_str2key(char *s, struct wi_key *k)
292 {
293         int                     n, i;
294         char                    *p;
295
296         /* Is this a hex string? */
297         if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
298                 /* Yes, convert to int. */
299                 n = 0;
300                 p = (char *)&k->wi_keydat[0];
301                 for (i = 2; s[i] != '\0' && s[i + 1] != '\0'; i+= 2) {
302                         *p++ = (wi_hex2int(s[i]) << 4) + wi_hex2int(s[i + 1]);
303                         n++;
304                 }
305                 if (s[i] != '\0')
306                         errx(1, "hex strings must be of even length");
307                 k->wi_keylen = n;
308         } else {
309                 /* No, just copy it in. */
310                 bcopy(s, k->wi_keydat, strlen(s));
311                 k->wi_keylen = strlen(s);
312         }
313
314         return;
315 }
316
317 static void
318 wi_setkeys(const char *iface, char *key, int idx)
319 {
320         int                     keylen;
321         struct wi_req           wreq;
322         struct wi_ltv_keys      *keys;
323         struct wi_key           *k;
324
325         bzero((char *)&wreq, sizeof(wreq));
326         wreq.wi_len = WI_MAX_DATALEN;
327         wreq.wi_type = WI_RID_WEP_AVAIL;
328
329         wi_getval(iface, &wreq);
330         if (wreq.wi_val[0] == 0)
331                 errx(1, "no WEP option available on this card");
332
333         bzero((char *)&wreq, sizeof(wreq));
334         wreq.wi_len = WI_MAX_DATALEN;
335         wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
336
337         wi_getval(iface, &wreq);
338         keys = (struct wi_ltv_keys *)&wreq;
339
340         keylen = strlen(key);
341         if (key[0] == '0' && (key[1] == 'x' || key[1] == 'X')) {
342                 if (keylen != 2 && keylen != 12 && keylen != 28) {
343                         errx(1, "encryption key must be 0, 10, or 26 "
344                             "hex digits long");
345                 }
346         } else {
347                 if (keylen != 0 && keylen != 5 && keylen != 13) {
348                         errx(1, "encryption key must be 0, 5, or 13 "
349                             "bytes long");
350                 }
351         }
352
353         if (idx > 3)
354                 errx(1, "only 4 encryption keys available");
355
356         k = &keys->wi_keys[idx];
357         wi_str2key(key, k);
358
359         wreq.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
360         wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
361         wi_setval(iface, &wreq);
362
363         return;
364 }
365
366 static void
367 wi_printkeys(struct wi_req *wreq)
368 {
369         int                     i, j;
370         int                     isprintable;
371         struct wi_key           *k;
372         struct wi_ltv_keys      *keys;
373         char                    *ptr;
374
375         keys = (struct wi_ltv_keys *)wreq;
376
377         for (i = 0; i < 4; i++) {
378                 k = &keys->wi_keys[i];
379                 ptr = (char *)k->wi_keydat;
380                 isprintable = 1;
381                 for (j = 0; j < k->wi_keylen; j++) {
382                         if (!isprint(ptr[j])) {
383                                 isprintable = 0;
384                                 break;
385                         }
386                 }
387                 if (isprintable) {
388                         ptr[j] = '\0';
389                         printf("[ %s ]", ptr);
390                 } else {
391                         printf("[ 0x");
392                         for (j = 0; j < k->wi_keylen; j++) {
393                                 printf("%02x", ptr[j] & 0xFF);
394                         }
395                         printf(" ]");
396                                         
397                 }
398         }
399
400         return;
401 };
402
403 void
404 wi_printwords(struct wi_req *wreq)
405 {
406         int                     i;
407
408         printf("[ ");
409         for (i = 0; i < wreq->wi_len - 1; i++)
410                 printf("%d ", wreq->wi_val[i]);
411         printf("]");
412
413         return;
414 }
415
416 void
417 wi_printswords(struct wi_req *wreq)
418 {
419         int                     i;
420
421         printf("[ ");
422         for (i = 0; i < wreq->wi_len - 1; i++)
423                 printf("%d ", ((int16_t *) wreq->wi_val)[i]);
424         printf("]");
425
426         return;
427 }
428
429 void
430 wi_printhexwords(struct wi_req *wreq)
431 {
432         int                     i;
433
434         printf("[ ");
435         for (i = 0; i < wreq->wi_len - 1; i++)
436                 printf("%x ", wreq->wi_val[i]);
437         printf("]");
438
439         return;
440 }
441
442 void
443 wi_printregdoms(struct wi_req *wreq)
444 {
445         int                     i;
446         struct wi_ltv_domains   *regdom = (struct wi_ltv_domains *)wreq;
447
448         printf("[ ");
449         for (i = 0; i < regdom->wi_num_dom; i++) {
450                 switch (regdom->wi_domains[i]) {
451                 case 0x10: printf("usa"); break;
452                 case 0x20: printf("canada"); break;
453                 case 0x30: printf("eu/au"); break;
454                 case 0x31: printf("es"); break;
455                 case 0x32: printf("fr"); break;
456                 case 0x40: printf("jp"); break;
457                 case 0x41: printf("jp new"); break;
458                 default: printf("0x%x", regdom->wi_domains[i]); break;
459                 }
460                 if (i < regdom->wi_num_dom - 1)
461                         printf(", ");
462         }
463         printf(" ]");
464
465         return;
466 }
467
468 void
469 wi_printbool(struct wi_req *wreq)
470 {
471         if (wreq->wi_val[0])
472                 printf("[ On ]");
473         else
474                 printf("[ Off ]");
475
476         return;
477 }
478
479 void
480 wi_printhex(struct wi_req *wreq)
481 {
482         int                     i;
483         unsigned char           *c;
484
485         c = (unsigned char *)&wreq->wi_val;
486
487         printf("[ ");
488         for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
489                 printf("%02x", c[i]);
490                 if (i < ((wreq->wi_len - 1) * 2) - 1)
491                         printf(":");
492         }
493
494         printf(" ]");
495         return;
496 }
497
498 static int
499 get_wiaprate(int inrate)
500 {
501         int rate;
502
503         switch (inrate) {
504         case WI_APRATE_1:
505                 rate = 1;
506                 break;
507         case WI_APRATE_2:
508                 rate = 2;
509                 break;
510         case WI_APRATE_5:
511                 rate = 5.5;
512                 break;
513         case WI_APRATE_11:
514                 rate = 11;
515                 break;
516 #ifdef WI_APRATE_0
517         case WI_APRATE_0:
518 #endif
519         default:
520                 rate = 0;
521                 break;
522         }
523
524         return (rate);
525 }
526
527 void
528 wi_printaplist(const char *iface)
529 {
530         int                     prism2;
531         struct wi_req           wreq;
532         struct wi_apinfo        *w;
533         int i, nstations;
534         float rate;
535
536         if (!quiet)
537                 printf("Available APs:\n");
538
539         /* first determine if this is a prism2 card or not */
540         wreq.wi_len = WI_MAX_DATALEN;
541         wreq.wi_type = WI_RID_PRISM2;
542
543         wi_getval(iface, &wreq);
544         prism2 = wreq.wi_val[0];
545
546         /* send out a scan request */
547         wreq.wi_len = 1;
548         wreq.wi_type = WI_RID_SCAN_APS;
549
550         wi_setval(iface, &wreq);
551
552         do {
553                 /*
554                  * sleep for 100 milliseconds so there's enough time for the card to
555                  * respond... prism2's take a little longer.
556                  */
557                 usleep(prism2 ? 500000 : 100000);
558
559                 /* get the scan results */
560                 wreq.wi_len = WI_MAX_DATALEN;
561                 wreq.wi_type = WI_RID_SCAN_RES;
562         } while (wi_getval(iface, &wreq) == -1 && errno == EINPROGRESS);
563
564         nstations = *(int *)wreq.wi_val;
565         if (!quiet) {
566                 printf("%d station%s:\n", nstations, nstations == 1 ? "" : "s");
567                 printf("SSID                 BSSID             Chan    SN   S   N   Intrvl  Capinfo\n");
568         }
569         w =  (struct wi_apinfo *)(((char *)&wreq.wi_val) + sizeof(int));
570         for ( i = 0; i < nstations; i++, w++) {
571                 printf("%-20.*s %02x:%02x:%02x:%02x:%02x:%02x   %-2d "
572                     "[ %3d %3d %3d ]    %-3d  "
573                     , w->namelen, w->name
574                     , w->bssid[0]&0xff, w->bssid[1]&0xff
575                     , w->bssid[2]&0xff, w->bssid[3]&0xff
576                     , w->bssid[4]&0xff, w->bssid[5]&0xff
577                     , w->channel
578                     , w->quality, w->signal, w->noise
579                     , w->interval
580                 );
581
582                 if (!quiet) {
583                         printf("[ ");
584                         if (w->capinfo & IEEE80211_CAPINFO_ESS)
585                                 printf("ESS ");
586                         if (w->capinfo & IEEE80211_CAPINFO_PRIVACY)
587                                 printf("WEP ");
588                         printf("]\n              ");
589
590                         rate = get_wiaprate(w->rate);
591                         if (rate) printf("* %2.1f *\n", rate);
592                 }
593                 putchar('\n');
594         }
595 }
596
597 #define WI_STRING               0x01
598 #define WI_BOOL                 0x02
599 #define WI_WORDS                0x03
600 #define WI_HEXBYTES             0x04
601 #define WI_KEYSTRUCT            0x05
602 #define WI_SWORDS               0x06
603 #define WI_HEXWORDS             0x07
604 #define WI_REGDOMS              0x08
605
606 struct wi_table {
607         int                     wi_code;
608         int                     wi_type;
609         const char              *wi_str;
610 };
611
612 static struct wi_table wi_table[] = {
613         { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" },
614         { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t" },
615         { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t" },
616         { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" },
617         { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t" },
618         { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" },
619         { WI_RID_CHANNEL_LIST, WI_HEXWORDS, "Channel list:\t\t\t\t" },
620         { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t" },
621         { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" },
622         { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" },
623         { WI_RID_DBM_COMMS_QUAL, WI_SWORDS, "dBm Coms Quality:\t\t\t" },
624         { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" },
625         { WI_RID_PROCFRAME, WI_BOOL, "Process 802.11b Frame:\t\t\t" },
626         { WI_RID_PRISM2, WI_WORDS, "Intersil-Prism2 based card:\t\t" },
627         { WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t"},
628         { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t"},
629         { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t"},
630         { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"},
631         { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t"},
632         { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t" },
633         { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t" },
634         { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t" },
635         { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time:\t\t\t\t" },
636         { WI_RID_PRI_IDENTITY, WI_WORDS, "PRI Identity:\t\t\t\t" },
637         { WI_RID_STA_IDENTITY, WI_WORDS, "STA Identity:\t\t\t\t" } ,
638         { WI_RID_CARD_ID, WI_HEXWORDS, "Card ID register:\t\t\t" },
639         { WI_RID_REG_DOMAINS, WI_REGDOMS, "Regulatory Domains:\t\t\t" },
640         { WI_RID_TEMP_TYPE, WI_WORDS, "Temperature Range:\t\t\t" },
641 #ifdef WI_EXTRA_INFO
642         { WI_RID_PRI_SUP_RANGE, WI_WORDS, "PRI Sup Range:\t\t\t\t" },
643         { WI_RID_CIF_ACT_RANGE, WI_WORDS, "CFI Act Sup Range:\t\t\t" },
644         { WI_RID_STA_SUP_RANGE, WI_WORDS, "STA Sup Range:\t\t\t\t" } ,
645         { WI_RID_MFI_ACT_RANGE, WI_WORDS, "MFI Act Sup Range:\t\t\t" } ,
646 #endif
647         { 0, 0, NULL }
648 };
649
650 static struct wi_table wi_crypt_table[] = {
651         { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t" },
652         { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" },
653         { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" },
654         { 0, 0, NULL }
655 };
656
657 static void
658 wi_dumpinfo(const char *iface)
659 {
660         struct wi_req           wreq;
661         int                     i, has_wep;
662         struct wi_table         *w;
663
664         bzero((char *)&wreq, sizeof(wreq));
665
666         wreq.wi_len = WI_MAX_DATALEN;
667         wreq.wi_type = WI_RID_WEP_AVAIL;
668
669         wi_getval(iface, &wreq);
670         has_wep = wreq.wi_val[0];
671
672         w = wi_table;
673
674         for (i = 0; w[i].wi_type; i++) {
675                 bzero((char *)&wreq, sizeof(wreq));
676
677                 wreq.wi_len = WI_MAX_DATALEN;
678                 wreq.wi_type = w[i].wi_code;
679
680                 wi_getval(iface, &wreq);
681                 printf("%s", w[i].wi_str);
682                 switch(w[i].wi_type) {
683                 case WI_STRING:
684                         wi_printstr(&wreq);
685                         break;
686                 case WI_WORDS:
687                         wi_printwords(&wreq);
688                         break;
689                 case WI_SWORDS:
690                         wi_printswords(&wreq);
691                         break;
692                 case WI_HEXWORDS:
693                         wi_printhexwords(&wreq);
694                         break;
695                 case WI_REGDOMS:
696                         wi_printregdoms(&wreq);
697                         break;
698                 case WI_BOOL:
699                         wi_printbool(&wreq);
700                         break;
701                 case WI_HEXBYTES:
702                         wi_printhex(&wreq);
703                         break;
704                 default:
705                         break;
706                 }       
707                 printf("\n");
708         }
709
710         if (has_wep) {
711                 w = wi_crypt_table;
712                 for (i = 0; w[i].wi_type; i++) {
713                         bzero((char *)&wreq, sizeof(wreq));
714
715                         wreq.wi_len = WI_MAX_DATALEN;
716                         wreq.wi_type = w[i].wi_code;
717
718                         wi_getval(iface, &wreq);
719                         printf("%s", w[i].wi_str);
720                         switch(w[i].wi_type) {
721                         case WI_STRING:
722                                 wi_printstr(&wreq);
723                                 break;
724                         case WI_WORDS:
725                                 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
726                                         wreq.wi_val[0]++;
727                                 wi_printwords(&wreq);
728                                 break;
729                         case WI_BOOL:
730                                 wi_printbool(&wreq);
731                                 break;
732                         case WI_HEXBYTES:
733                                 wi_printhex(&wreq);
734                                 break;
735                         case WI_KEYSTRUCT:
736                                 wi_printkeys(&wreq);
737                                 break;
738                         default:
739                                 break;
740                         }       
741                         printf("\n");
742                 }
743         }
744
745         if (listaps)
746                 wi_printaplist(iface);
747
748         return;
749 }
750
751 static void
752 wi_dumpstats(const char *iface)
753 {
754         struct wi_req           wreq;
755         struct wi_counters      *c;
756
757         if (iface == NULL)
758                 errx(1, "must specify interface name");
759
760         bzero((char *)&wreq, sizeof(wreq));
761         wreq.wi_len = WI_MAX_DATALEN;
762         wreq.wi_type = WI_RID_IFACE_STATS;
763
764         wi_getval(iface, &wreq);
765
766         c = (struct wi_counters *)&wreq.wi_val;
767
768         printf("Transmitted unicast frames:\t\t%d\n",
769             c->wi_tx_unicast_frames);
770         printf("Transmitted multicast frames:\t\t%d\n",
771             c->wi_tx_multicast_frames);
772         printf("Transmitted fragments:\t\t\t%d\n",
773             c->wi_tx_fragments);
774         printf("Transmitted unicast octets:\t\t%d\n",
775             c->wi_tx_unicast_octets);
776         printf("Transmitted multicast octets:\t\t%d\n",
777             c->wi_tx_multicast_octets);
778         printf("Single transmit retries:\t\t%d\n",
779             c->wi_tx_single_retries);
780         printf("Multiple transmit retries:\t\t%d\n",
781             c->wi_tx_multi_retries);
782         printf("Transmit retry limit exceeded:\t\t%d\n",
783             c->wi_tx_retry_limit);
784         printf("Transmit discards:\t\t\t%d\n",
785             c->wi_tx_discards);
786         printf("Transmit discards due to wrong SA:\t%d\n",
787             c->wi_tx_discards_wrong_sa);
788         printf("Received unicast frames:\t\t%d\n",
789             c->wi_rx_unicast_frames);
790         printf("Received multicast frames:\t\t%d\n",
791             c->wi_rx_multicast_frames);
792         printf("Received fragments:\t\t\t%d\n",
793             c->wi_rx_fragments);
794         printf("Received unicast octets:\t\t%d\n",
795             c->wi_rx_unicast_octets);
796         printf("Received multicast octets:\t\t%d\n",
797             c->wi_rx_multicast_octets);
798         printf("Receive FCS errors:\t\t\t%d\n",
799             c->wi_rx_fcs_errors);
800         printf("Receive discards due to no buffer:\t%d\n",
801             c->wi_rx_discards_nobuf);
802         printf("Can't decrypt WEP frame:\t\t%d\n",
803             c->wi_rx_WEP_cant_decrypt);
804         printf("Received message fragments:\t\t%d\n",
805             c->wi_rx_msg_in_msg_frags);
806         printf("Received message bad fragments:\t\t%d\n",
807             c->wi_rx_msg_in_bad_msg_frags);
808
809         return;
810 }
811
812 static void
813 usage(const char *p)
814 {
815         fprintf(stderr, "usage:  %s -i iface\n", p);
816         fprintf(stderr, "\t%s -i iface -o\n", p);
817         fprintf(stderr, "\t%s -i iface -l\n", p);
818         fprintf(stderr, "\t%s -i iface -t tx rate\n", p);
819         fprintf(stderr, "\t%s -i iface -n network name\n", p);
820         fprintf(stderr, "\t%s -i iface -s station name\n", p);
821         fprintf(stderr, "\t%s -i iface -c 0|1\n", p);
822         fprintf(stderr, "\t%s -i iface -q SSID\n", p);
823         fprintf(stderr, "\t%s -i iface -p port type\n", p);
824         fprintf(stderr, "\t%s -i iface -a access point density\n", p);
825         fprintf(stderr, "\t%s -i iface -m mac address\n", p);
826         fprintf(stderr, "\t%s -i iface -d max data length\n", p);
827         fprintf(stderr, "\t%s -i iface -e 0|1\n", p);
828         fprintf(stderr, "\t%s -i iface -k encryption key [-v 1|2|3|4]\n", p);
829         fprintf(stderr, "\t%s -i iface -r RTS threshold\n", p);
830         fprintf(stderr, "\t%s -i iface -f frequency\n", p);
831         fprintf(stderr, "\t%s -i iface -F 0|1\n", p);
832         fprintf(stderr, "\t%s -i iface -P 0|1\n", p);
833         fprintf(stderr, "\t%s -i iface -S max sleep duration\n", p);
834         fprintf(stderr, "\t%s -i iface -T 1|2|3|4\n", p);
835 #ifdef WICACHE
836         fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
837         fprintf(stderr, "\t%s -i iface -C print signal cache\n", p);
838 #endif
839
840         exit(1);
841 }
842
843 static void
844 wi_printaps(struct wi_req *wreq)
845 {
846         struct wi_apinfo        *w;
847         int i, j, nstations, rate;
848
849         nstations = *(int *)wreq->wi_val;
850         printf("%d station%s:\n", nstations, nstations == 1 ? "" : "s");
851         w =  (struct wi_apinfo *)(((char *)&wreq->wi_val) + sizeof(int));
852         for ( i = 0; i < nstations; i++, w++) {
853                 printf("ap[%d]:\n", i);
854                 if (w->scanreason) {
855                         static char *scanm[] = {
856                                 "Host initiated",
857                                 "Firmware initiated",
858                                 "Inquiry request from host"
859                         };
860                         printf("\tScanReason:\t\t\t[ %s ]\n",
861                                 scanm[w->scanreason - 1]);
862                 }
863                 printf("\tnetname (SSID):\t\t\t[ ");
864                         for (j = 0; j < w->namelen; j++) {
865                                 printf("%c", w->name[j]);
866                         }
867                         printf(" ]\n");
868                 printf("\tBSSID:\t\t\t\t[ %02x:%02x:%02x:%02x:%02x:%02x ]\n",
869                         w->bssid[0]&0xff, w->bssid[1]&0xff,
870                         w->bssid[2]&0xff, w->bssid[3]&0xff,
871                         w->bssid[4]&0xff, w->bssid[5]&0xff);
872                 printf("\tChannel:\t\t\t[ %d ]\n", w->channel);
873                 printf("\tQuality/Signal/Noise [signal]:\t[ %d / %d / %d ]\n"
874                        "\t                        [dBm]:\t[ %d / %d / %d ]\n", 
875                         w->quality, w->signal, w->noise,
876                         w->quality, w->signal - 149, w->noise - 149);
877                 printf("\tBSS Beacon Interval [msec]:\t[ %d ]\n", w->interval); 
878                 printf("\tCapinfo:\t\t\t[ "); 
879                         if (w->capinfo & IEEE80211_CAPINFO_ESS)
880                                 printf("ESS ");
881                         if (w->capinfo & IEEE80211_CAPINFO_PRIVACY)
882                                 printf("WEP ");
883                         printf("]\n");
884
885                 switch (w->rate) {
886                 case WI_APRATE_1:
887                         rate = 1;
888                         break;
889                 case WI_APRATE_2:
890                         rate = 2;
891                         break;
892                 case WI_APRATE_5:
893                         rate = 5.5;
894                         break;
895                 case WI_APRATE_11:
896                         rate = 11;
897                         break;
898 #ifdef WI_APRATE_0
899                 case WI_APRATE_0:
900 #endif
901                 default:
902                         rate = 0;
903                         break;
904                 }
905                 if (rate) printf("\tDataRate [Mbps]:\t\t[ %d ]\n", rate);
906         }
907 }
908
909 static void
910 wi_dumpstations(const char *iface)
911 {
912         struct wi_req           wreq;
913
914         if (iface == NULL)
915                 errx(1, "must specify interface name");
916
917         bzero((char *)&wreq, sizeof(wreq));
918         wreq.wi_len = WI_MAX_DATALEN;
919         wreq.wi_type = WI_RID_READ_APS;
920
921         wi_getval(iface, &wreq);
922
923         wi_printaps(&wreq);
924 }
925
926 #ifdef WICACHE
927 static void
928 wi_zerocache(const char *iface)
929 {
930         struct wi_req           wreq;
931
932         if (iface == NULL)
933                 errx(1, "must specify interface name");
934
935         bzero((char *)&wreq, sizeof(wreq));
936         wreq.wi_len = 0;
937         wreq.wi_type = WI_RID_ZERO_CACHE;
938
939         wi_getval(iface, &wreq);
940 }
941
942 static void
943 wi_readcache(const char *iface)
944 {
945         struct wi_req           wreq;
946         int                     *wi_sigitems;
947         struct wi_sigcache      *sc;
948         char *                  pt;
949         int                     i;
950
951         if (iface == NULL)
952                 errx(1, "must specify interface name");
953
954         bzero((char *)&wreq, sizeof(wreq));
955         wreq.wi_len = WI_MAX_DATALEN;
956         wreq.wi_type = WI_RID_READ_CACHE;
957
958         wi_getval(iface, &wreq);
959
960         wi_sigitems = (int *) &wreq.wi_val; 
961         pt = ((char *) &wreq.wi_val);
962         pt += sizeof(int);
963         sc = (struct wi_sigcache *) pt;
964
965         for (i = 0; i < *wi_sigitems; i++) {
966                 printf("[%d/%d]:", i+1, *wi_sigitems);
967                 printf(" %02x:%02x:%02x:%02x:%02x:%02x,",
968                                         sc->macsrc[0]&0xff,
969                                         sc->macsrc[1]&0xff,
970                                         sc->macsrc[2]&0xff,
971                                         sc->macsrc[3]&0xff,
972                                         sc->macsrc[4]&0xff,
973                                         sc->macsrc[5]&0xff);
974                 printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff),
975                                         ((sc->ipsrc >> 8) & 0xff),
976                                         ((sc->ipsrc >> 16) & 0xff),
977                                         ((sc->ipsrc >> 24) & 0xff));
978                 printf(" sig: %d, noise: %d, qual: %d\n",
979                                         sc->signal,
980                                         sc->noise,
981                                         sc->quality);
982                 sc++;
983         }
984
985         return;
986 }
987 #endif
988
989 int
990 main(int argc, char *argv[])
991 {
992         int                     ch;
993         const char              *iface = NULL;
994         char                    *p = argv[0];
995         char                    *key = NULL;
996         int                     modifier = 0;
997
998         /* Get the interface name */
999         opterr = 0;
1000         ch = getopt(argc, argv, "i:");
1001         if (ch == 'i') {
1002                 iface = optarg;
1003         } else {
1004                 if (argc > 1 && *argv[1] != '-') {
1005                         iface = argv[1];
1006                         optind = 2; 
1007                 } else {
1008                         iface = "wi0";
1009                         optind = 1;
1010                 }
1011                 optreset = 1;
1012         }
1013         opterr = 1;
1014                 
1015         while((ch = getopt(argc, argv,
1016             "a:c:d:e:f:hi:k:lm:n:op:q:r:s:t:v:CF:LP:QS:T:Z")) != -1) {
1017                 switch(ch) {
1018                 case 'Z':
1019 #ifdef WICACHE
1020                         wi_zerocache(iface);
1021 #else
1022                         printf("WICACHE not available\n");
1023 #endif
1024                         exit(0);
1025                         break;
1026                 case 'C':
1027 #ifdef WICACHE
1028                         wi_readcache(iface);
1029 #else
1030                         printf("WICACHE not available\n");
1031 #endif
1032                         exit(0);
1033                         break;
1034                 case 'o':
1035                         wi_dumpstats(iface);
1036                         exit(0);
1037                         break;
1038                 case 'c':
1039                         wi_setword(iface, WI_RID_CREATE_IBSS, atoi(optarg));
1040                         exit(0);
1041                         break;
1042                 case 'd':
1043                         wi_setword(iface, WI_RID_MAX_DATALEN, atoi(optarg));
1044                         exit(0);
1045                         break;
1046                 case 'e':
1047                         wi_setword(iface, WI_RID_ENCRYPTION, atoi(optarg));
1048                         exit(0);
1049                         break;
1050                 case 'f':
1051                         wi_setword(iface, WI_RID_OWN_CHNL, atoi(optarg));
1052                         exit(0);
1053                         break;
1054                 case 'F':
1055                         wi_setword(iface, WI_RID_PROCFRAME, atoi(optarg));
1056                         exit(0);
1057                         break;
1058                 case 'k':
1059                         key = optarg;
1060                         break;
1061                 case 'L':
1062                         listaps++;
1063                         break;
1064                 case 'l':
1065                         wi_dumpstations(iface);
1066                         exit(0);
1067                         break;
1068                 case 'p':
1069                         wi_setword(iface, WI_RID_PORTTYPE, atoi(optarg));
1070                         exit(0);
1071                         break;
1072                 case 'r':
1073                         wi_setword(iface, WI_RID_RTS_THRESH, atoi(optarg));
1074                         exit(0);
1075                         break;
1076                 case 't':
1077                         wi_setword(iface, WI_RID_TX_RATE, atoi(optarg));
1078                         exit(0);
1079                         break;
1080                 case 'n':
1081                         wi_setstr(iface, WI_RID_DESIRED_SSID, optarg);
1082                         exit(0);
1083                         break;
1084                 case 's':
1085                         wi_setstr(iface, WI_RID_NODENAME, optarg);
1086                         exit(0);
1087                         break;
1088                 case 'm':
1089                         wi_sethex(iface, WI_RID_MAC_NODE, optarg);
1090                         exit(0);
1091                         break;
1092                 case 'Q':
1093                         quiet = 1;
1094                         break;
1095                 case 'q':
1096                         wi_setstr(iface, WI_RID_OWN_SSID, optarg);
1097                         exit(0);
1098                         break;
1099                 case 'S':
1100                         wi_setword(iface, WI_RID_MAX_SLEEP, atoi(optarg));
1101                         exit(0);
1102                         break;
1103                 case 'T':
1104                         wi_setword(iface,
1105                             WI_RID_TX_CRYPT_KEY, atoi(optarg) - 1);
1106                         exit(0);
1107                         break;
1108                 case 'P':
1109                         wi_setword(iface, WI_RID_PM_ENABLED, atoi(optarg));
1110                         exit(0);
1111                         break;
1112                 case 'a':
1113                         wi_setword(iface, WI_RID_SYSTEM_SCALE, atoi(optarg));
1114                         exit(0);
1115                         break;
1116                 case 'v':
1117                         modifier = atoi(optarg);
1118                         modifier--;
1119                         break;
1120                 case 'h':
1121                 default:
1122                         usage(p);
1123                         break;
1124                 }
1125         }
1126
1127         if (iface == NULL)
1128                 usage(p);
1129
1130         if (key != NULL) {
1131                 wi_setkeys(iface, key, modifier);
1132                 exit(0);
1133         }
1134
1135         if (listaps > 1) {
1136                 wi_printaplist(iface);
1137                 exit(0);
1138         }
1139
1140         wi_dumpinfo(iface);
1141
1142         exit(0);
1143 }