Initial import from FreeBSD RELENG_4:
[dragonfly.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: src/usr.sbin/wicontrol/wicontrol.c,v 1.9.2.7 2002/08/03 07:24:17 imp Exp $";
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/wi_hostap.h>
54 #include <dev/wi/if_wireg.h>
55
56 #include <stdio.h>
57 #include <string.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <ctype.h>
61 #include <errno.h>
62 #include <err.h>
63
64 static void wi_getval(const char *, struct wi_req *);
65 static void wi_setval(const char *, struct wi_req *);
66 static void wi_printstr(struct wi_req *);
67 static void wi_setstr(const char *, int, char *);
68 static void wi_setbytes(const char *, int, char *, int);
69 static void wi_setword(const char *, int, int);
70 static void wi_sethex(const char *, int, char *);
71 static void wi_printwords(struct wi_req *);
72 static void wi_printbool(struct wi_req *);
73 static void wi_printhex(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
87 int listaps;
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(s, v, bits)
95         char *s;
96         char *bits;
97         unsigned short v;
98 {
99         int i, any = 0;
100         char c;
101
102         if (bits && *bits == 8)
103                 printf("%s=%o", s, v);
104         else
105                 printf("%s=%x", s, v);
106         bits++;
107         if (bits) {
108                 putchar('<');
109                 while ((i = *bits++)) {
110                         if (v & (1 << (i-1))) {
111                                 if (any)
112                                         putchar(',');
113                                 any = 1;
114                                 for (; (c = *bits) > 32; bits++)
115                                         putchar(c);
116                         } else
117                                 for (; *bits > 32; bits++)
118                                         ;
119                 }
120                 putchar('>');
121         }
122 }
123
124 static void
125 wi_getval(const char *iface, struct wi_req *wreq)
126 {
127         struct ifreq            ifr;
128         int                     s;
129
130         bzero((char *)&ifr, sizeof(ifr));
131
132         strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
133         ifr.ifr_data = (caddr_t)wreq;
134
135         s = socket(AF_INET, SOCK_DGRAM, 0);
136
137         if (s == -1)
138                 err(1, "socket");
139
140         if (ioctl(s, SIOCGWAVELAN, &ifr) == -1)
141                 err(1, "SIOCGWAVELAN");
142
143         close(s);
144
145         return;
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_printbool(struct wi_req *wreq)
418 {
419         if (wreq->wi_val[0])
420                 printf("[ On ]");
421         else
422                 printf("[ Off ]");
423
424         return;
425 }
426
427 void
428 wi_printhex(struct wi_req *wreq)
429 {
430         int                     i;
431         unsigned char           *c;
432
433         c = (unsigned char *)&wreq->wi_val;
434
435         printf("[ ");
436         for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
437                 printf("%02x", c[i]);
438                 if (i < ((wreq->wi_len - 1) * 2) - 1)
439                         printf(":");
440         }
441
442         printf(" ]");
443         return;
444 }
445
446 void
447 wi_printaplist(const char *iface)
448 {
449         int                     prism2, len, i = 0, j;
450         struct wi_req           wreq;
451         struct wi_scan_p2_hdr   *wi_p2_h;
452         struct wi_scan_res      *res;
453
454         printf("Available APs:\n");
455
456         /* first determine if this is a prism2 card or not */
457         wreq.wi_len = WI_MAX_DATALEN;
458         wreq.wi_type = WI_RID_PRISM2;
459
460         wi_getval(iface, &wreq);
461         prism2 = wreq.wi_val[0];
462
463         /* send out a scan request */
464         wreq.wi_len = prism2 ? 3 : 1;
465         wreq.wi_type = WI_RID_SCAN_REQ;
466
467         if (prism2) {
468                 wreq.wi_val[0] = 0x3FFF;
469                 wreq.wi_val[1] = 0x000F;
470         }
471
472         wi_setval(iface, &wreq);
473
474         /*
475          * sleep for 100 milliseconds so there's enough time for the card to
476          * respond... prism2's take a little longer.
477          */
478         usleep(prism2 ? 500000 : 100000);
479
480         /* get the scan results */
481         wreq.wi_len = WI_MAX_DATALEN;
482         wreq.wi_type = WI_RID_SCAN_RES;
483
484         wi_getval(iface, &wreq);
485
486         if (prism2) {
487                 wi_p2_h = (struct wi_scan_p2_hdr *)wreq.wi_val;
488
489                 /* if the reason is 0, this info is invalid */
490                 if (wi_p2_h->wi_reason == 0)
491                         return;
492
493                 i = 4;
494         }
495
496         len = prism2 ? WI_PRISM2_RES_SIZE : WI_WAVELAN_RES_SIZE;
497
498         for (; i < (wreq.wi_len * 2) - len; i += len) {
499                 res = (struct wi_scan_res *)((char *)wreq.wi_val + i);
500
501                 res->wi_ssid[res->wi_ssid_len] = '\0';
502
503                 printf("    %-8s  [ %02x:%02x:%02x:%02x:%02x:%02x ]  [ %-2d ]  "
504                     "[ %d %d %d ]  %-3d  ", res->wi_ssid,
505                     res->wi_bssid[0], res->wi_bssid[1], res->wi_bssid[2],
506                     res->wi_bssid[3], res->wi_bssid[4], res->wi_bssid[5],
507                     res->wi_chan, res->wi_signal - res->wi_noise,
508                     res->wi_signal, res->wi_noise, res->wi_interval);
509
510                 if (res->wi_capinfo) {
511                         printf("[ ");
512                         if (res->wi_capinfo & WI_CAPINFO_ESS)
513                                 printf("ess ");
514                         if (res->wi_capinfo & WI_CAPINFO_IBSS)
515                                 printf("ibss ");
516                         if (res->wi_capinfo & WI_CAPINFO_PRIV)
517                                 printf("priv ");
518                         printf("]  ");
519                 }
520
521                 if (prism2) {
522                         printf("\n              [ ");
523                         for (j = 0; res->wi_srates[j] != 0; j++) {
524                                 res->wi_srates[j] = res->wi_srates[j] &
525                                     WI_VAR_SRATES_MASK;
526                                 printf("%d.%d ", res->wi_srates[j] / 2,
527                                     (res->wi_srates[j] % 2) * 5);
528                         }
529                         printf("]  ");
530
531                         printf("* %2.1f *", res->wi_rate == 0xa ? 1 :
532                             (res->wi_rate == 0x14 ? 2 :
533                             (res->wi_rate == 0x37 ? 5.5 :
534                             (res->wi_rate == 0x6e ? 11 : 0))));
535                 }
536
537                 putchar('\n');
538         }
539
540         return;
541 }
542
543 #define WI_STRING               0x01
544 #define WI_BOOL                 0x02
545 #define WI_WORDS                0x03
546 #define WI_HEXBYTES             0x04
547 #define WI_KEYSTRUCT            0x05
548
549 struct wi_table {
550         int                     wi_code;
551         int                     wi_type;
552         const char              *wi_str;
553 };
554
555 static struct wi_table wi_table[] = {
556         { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" },
557         { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t" },
558         { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t" },
559         { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" },
560         { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t" },
561         { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" },
562         { WI_RID_CHANNEL_LIST, WI_WORDS, "Channel list:\t\t\t\t" },
563         { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t" },
564         { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" },
565         { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" },
566         { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" },
567         { WI_RID_PROCFRAME, WI_BOOL, "Process 802.11b Frame:\t\t\t" },
568         { WI_RID_PRISM2, WI_WORDS, "Intersil-Prism2 based card:\t\t" },
569         { WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t"},
570         { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t"},
571         { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t"},
572         { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"},
573         { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t"},
574         { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t" },
575         { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t" },
576         { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t" },
577         { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time:\t\t\t\t" },
578         { 0, 0, NULL }
579 };
580
581 static struct wi_table wi_crypt_table[] = {
582         { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t" },
583         { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" },
584         { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" },
585         { 0, 0, NULL }
586 };
587
588 static void
589 wi_dumpinfo(const char *iface)
590 {
591         struct wi_req           wreq;
592         int                     i, has_wep;
593         struct wi_table         *w;
594
595         bzero((char *)&wreq, sizeof(wreq));
596
597         wreq.wi_len = WI_MAX_DATALEN;
598         wreq.wi_type = WI_RID_WEP_AVAIL;
599
600         wi_getval(iface, &wreq);
601         has_wep = wreq.wi_val[0];
602
603         w = wi_table;
604
605         for (i = 0; w[i].wi_type; i++) {
606                 bzero((char *)&wreq, sizeof(wreq));
607
608                 wreq.wi_len = WI_MAX_DATALEN;
609                 wreq.wi_type = w[i].wi_code;
610
611                 wi_getval(iface, &wreq);
612                 printf("%s", w[i].wi_str);
613                 switch(w[i].wi_type) {
614                 case WI_STRING:
615                         wi_printstr(&wreq);
616                         break;
617                 case WI_WORDS:
618                         wi_printwords(&wreq);
619                         break;
620                 case WI_BOOL:
621                         wi_printbool(&wreq);
622                         break;
623                 case WI_HEXBYTES:
624                         wi_printhex(&wreq);
625                         break;
626                 default:
627                         break;
628                 }       
629                 printf("\n");
630         }
631
632         if (has_wep) {
633                 w = wi_crypt_table;
634                 for (i = 0; w[i].wi_type; i++) {
635                         bzero((char *)&wreq, sizeof(wreq));
636
637                         wreq.wi_len = WI_MAX_DATALEN;
638                         wreq.wi_type = w[i].wi_code;
639
640                         wi_getval(iface, &wreq);
641                         printf("%s", w[i].wi_str);
642                         switch(w[i].wi_type) {
643                         case WI_STRING:
644                                 wi_printstr(&wreq);
645                                 break;
646                         case WI_WORDS:
647                                 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
648                                         wreq.wi_val[0]++;
649                                 wi_printwords(&wreq);
650                                 break;
651                         case WI_BOOL:
652                                 wi_printbool(&wreq);
653                                 break;
654                         case WI_HEXBYTES:
655                                 wi_printhex(&wreq);
656                                 break;
657                         case WI_KEYSTRUCT:
658                                 wi_printkeys(&wreq);
659                                 break;
660                         default:
661                                 break;
662                         }       
663                         printf("\n");
664                 }
665         }
666
667         if (listaps)
668                 wi_printaplist(iface);
669
670         return;
671 }
672
673 static void
674 wi_dumpstats(const char *iface)
675 {
676         struct wi_req           wreq;
677         struct wi_counters      *c;
678
679         if (iface == NULL)
680                 errx(1, "must specify interface name");
681
682         bzero((char *)&wreq, sizeof(wreq));
683         wreq.wi_len = WI_MAX_DATALEN;
684         wreq.wi_type = WI_RID_IFACE_STATS;
685
686         wi_getval(iface, &wreq);
687
688         c = (struct wi_counters *)&wreq.wi_val;
689
690         printf("Transmitted unicast frames:\t\t%d\n",
691             c->wi_tx_unicast_frames);
692         printf("Transmitted multicast frames:\t\t%d\n",
693             c->wi_tx_multicast_frames);
694         printf("Transmitted fragments:\t\t\t%d\n",
695             c->wi_tx_fragments);
696         printf("Transmitted unicast octets:\t\t%d\n",
697             c->wi_tx_unicast_octets);
698         printf("Transmitted multicast octets:\t\t%d\n",
699             c->wi_tx_multicast_octets);
700         printf("Single transmit retries:\t\t%d\n",
701             c->wi_tx_single_retries);
702         printf("Multiple transmit retries:\t\t%d\n",
703             c->wi_tx_multi_retries);
704         printf("Transmit retry limit exceeded:\t\t%d\n",
705             c->wi_tx_retry_limit);
706         printf("Transmit discards:\t\t\t%d\n",
707             c->wi_tx_discards);
708         printf("Transmit discards due to wrong SA:\t%d\n",
709             c->wi_tx_discards_wrong_sa);
710         printf("Received unicast frames:\t\t%d\n",
711             c->wi_rx_unicast_frames);
712         printf("Received multicast frames:\t\t%d\n",
713             c->wi_rx_multicast_frames);
714         printf("Received fragments:\t\t\t%d\n",
715             c->wi_rx_fragments);
716         printf("Received unicast octets:\t\t%d\n",
717             c->wi_rx_unicast_octets);
718         printf("Received multicast octets:\t\t%d\n",
719             c->wi_rx_multicast_octets);
720         printf("Receive FCS errors:\t\t\t%d\n",
721             c->wi_rx_fcs_errors);
722         printf("Receive discards due to no buffer:\t%d\n",
723             c->wi_rx_discards_nobuf);
724         printf("Can't decrypt WEP frame:\t\t%d\n",
725             c->wi_rx_WEP_cant_decrypt);
726         printf("Received message fragments:\t\t%d\n",
727             c->wi_rx_msg_in_msg_frags);
728         printf("Received message bad fragments:\t\t%d\n",
729             c->wi_rx_msg_in_bad_msg_frags);
730
731         return;
732 }
733
734 static void
735 usage(const char *p)
736 {
737         fprintf(stderr, "usage:  %s -i iface\n", p);
738         fprintf(stderr, "\t%s -i iface -o\n", p);
739         fprintf(stderr, "\t%s -i iface -l\n", p);
740         fprintf(stderr, "\t%s -i iface -t tx rate\n", p);
741         fprintf(stderr, "\t%s -i iface -n network name\n", p);
742         fprintf(stderr, "\t%s -i iface -s station name\n", p);
743         fprintf(stderr, "\t%s -i iface -c 0|1\n", p);
744         fprintf(stderr, "\t%s -i iface -q SSID\n", p);
745         fprintf(stderr, "\t%s -i iface -p port type\n", p);
746         fprintf(stderr, "\t%s -i iface -a access point density\n", p);
747         fprintf(stderr, "\t%s -i iface -m mac address\n", p);
748         fprintf(stderr, "\t%s -i iface -d max data length\n", p);
749         fprintf(stderr, "\t%s -i iface -e 0|1\n", p);
750         fprintf(stderr, "\t%s -i iface -k encryption key [-v 1|2|3|4]\n", p);
751         fprintf(stderr, "\t%s -i iface -r RTS threshold\n", p);
752         fprintf(stderr, "\t%s -i iface -f frequency\n", p);
753         fprintf(stderr, "\t%s -i iface -F 0|1\n", p);
754         fprintf(stderr, "\t%s -i iface -P 0|1\n", p);
755         fprintf(stderr, "\t%s -i iface -S max sleep duration\n", p);
756         fprintf(stderr, "\t%s -i iface -T 1|2|3|4\n", p);
757 #ifdef WICACHE
758         fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
759         fprintf(stderr, "\t%s -i iface -C print signal cache\n", p);
760 #endif
761
762         exit(1);
763 }
764
765 static void
766 wi_dumpstations(const char *iface)
767 {
768         struct hostap_getall    reqall;
769         struct hostap_sta       stas[WIHAP_MAX_STATIONS];
770         struct ifreq            ifr;
771         int i, s;
772
773         bzero(&ifr, sizeof(ifr));
774         strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
775         ifr.ifr_data = (caddr_t) & reqall;
776         bzero(&reqall, sizeof(reqall));
777         reqall.size = sizeof(stas);
778         reqall.addr = stas;
779         bzero(&stas, sizeof(stas));
780
781         s = socket(AF_INET, SOCK_DGRAM, 0);
782         if (s == -1)
783                 err(1, "socket");
784
785         if (ioctl(s, SIOCHOSTAP_GETALL, &ifr) < 0)
786                 err(1, "SIOCHOSTAP_GETALL");
787
788         printf("%d station%s:\n", reqall.nstations, reqall.nstations>1?"s":"");
789         for (i = 0; i < reqall.nstations; i++) {
790                 struct hostap_sta *info = &stas[i];
791
792                 printf("%02x:%02x:%02x:%02x:%02x:%02x  asid=%04x",
793                         info->addr[0], info->addr[1], info->addr[2],
794                         info->addr[3], info->addr[4], info->addr[5],
795                         info->asid - 0xc001);
796                 printb(", flags", info->flags, HOSTAP_FLAGS_BITS);
797                 printb(", caps", info->capinfo, IEEE80211_CAPINFO_BITS);
798                 printb(", rates", info->rates, WI_RATES_BITS);
799                 if (info->sig_info)
800                         printf(", sig=%d/%d",
801                             info->sig_info >> 8, info->sig_info & 0xff);
802                 putchar('\n');
803         }
804 }
805
806 #ifdef WICACHE
807 static void
808 wi_zerocache(const char *iface)
809 {
810         struct wi_req           wreq;
811
812         if (iface == NULL)
813                 errx(1, "must specify interface name");
814
815         bzero((char *)&wreq, sizeof(wreq));
816         wreq.wi_len = 0;
817         wreq.wi_type = WI_RID_ZERO_CACHE;
818
819         wi_getval(iface, &wreq);
820 }
821
822 static void
823 wi_readcache(const char *iface)
824 {
825         struct wi_req           wreq;
826         int                     *wi_sigitems;
827         struct wi_sigcache      *sc;
828         char *                  pt;
829         int                     i;
830
831         if (iface == NULL)
832                 errx(1, "must specify interface name");
833
834         bzero((char *)&wreq, sizeof(wreq));
835         wreq.wi_len = WI_MAX_DATALEN;
836         wreq.wi_type = WI_RID_READ_CACHE;
837
838         wi_getval(iface, &wreq);
839
840         wi_sigitems = (int *) &wreq.wi_val; 
841         pt = ((char *) &wreq.wi_val);
842         pt += sizeof(int);
843         sc = (struct wi_sigcache *) pt;
844
845         for (i = 0; i < *wi_sigitems; i++) {
846                 printf("[%d/%d]:", i+1, *wi_sigitems);
847                 printf(" %02x:%02x:%02x:%02x:%02x:%02x,",
848                                         sc->macsrc[0]&0xff,
849                                         sc->macsrc[1]&0xff,
850                                         sc->macsrc[2]&0xff,
851                                         sc->macsrc[3]&0xff,
852                                         sc->macsrc[4]&0xff,
853                                         sc->macsrc[5]&0xff);
854                 printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff),
855                                         ((sc->ipsrc >> 8) & 0xff),
856                                         ((sc->ipsrc >> 16) & 0xff),
857                                         ((sc->ipsrc >> 24) & 0xff));
858                 printf(" sig: %d, noise: %d, qual: %d\n",
859                                         sc->signal,
860                                         sc->noise,
861                                         sc->quality);
862                 sc++;
863         }
864
865         return;
866 }
867 #endif
868
869 int
870 main(int argc, char *argv[])
871 {
872         int                     ch;
873         const char              *iface = NULL;
874         char                    *p = argv[0];
875         char                    *key = NULL;
876         int                     modifier = 0;
877
878         /* Get the interface name */
879         opterr = 0;
880         ch = getopt(argc, argv, "i:");
881         if (ch == 'i') {
882                 iface = optarg;
883         } else {
884                 if (argc > 1 && *argv[1] != '-') {
885                         iface = argv[1];
886                         optind = 2; 
887                 } else {
888                         iface = "wi0";
889                         optind = 1;
890                 }
891                 optreset = 1;
892         }
893         opterr = 1;
894                 
895         while((ch = getopt(argc, argv,
896             "a:hoc:d:e:f:i:k:lp:r:q:t:n:s:m:v:F:LP:S:T:ZC")) != -1) {
897                 switch(ch) {
898                 case 'Z':
899 #ifdef WICACHE
900                         wi_zerocache(iface);
901 #else
902                         printf("WICACHE not available\n");
903 #endif
904                         exit(0);
905                         break;
906                 case 'C':
907 #ifdef WICACHE
908                         wi_readcache(iface);
909 #else
910                         printf("WICACHE not available\n");
911 #endif
912                         exit(0);
913                         break;
914                 case 'o':
915                         wi_dumpstats(iface);
916                         exit(0);
917                         break;
918                 case 'c':
919                         wi_setword(iface, WI_RID_CREATE_IBSS, atoi(optarg));
920                         exit(0);
921                         break;
922                 case 'd':
923                         wi_setword(iface, WI_RID_MAX_DATALEN, atoi(optarg));
924                         exit(0);
925                         break;
926                 case 'e':
927                         wi_setword(iface, WI_RID_ENCRYPTION, atoi(optarg));
928                         exit(0);
929                         break;
930                 case 'f':
931                         wi_setword(iface, WI_RID_OWN_CHNL, atoi(optarg));
932                         exit(0);
933                         break;
934                 case 'F':
935                         wi_setword(iface, WI_RID_PROCFRAME, atoi(optarg));
936                         exit(0);
937                         break;
938                 case 'k':
939                         key = optarg;
940                         break;
941                 case 'L':
942                         listaps = 1;
943                         break;
944                 case 'l':
945                         wi_dumpstations(iface);
946                         exit(0);
947                         break;
948                 case 'p':
949                         wi_setword(iface, WI_RID_PORTTYPE, atoi(optarg));
950                         exit(0);
951                         break;
952                 case 'r':
953                         wi_setword(iface, WI_RID_RTS_THRESH, atoi(optarg));
954                         exit(0);
955                         break;
956                 case 't':
957                         wi_setword(iface, WI_RID_TX_RATE, atoi(optarg));
958                         exit(0);
959                         break;
960                 case 'n':
961                         wi_setstr(iface, WI_RID_DESIRED_SSID, optarg);
962                         exit(0);
963                         break;
964                 case 's':
965                         wi_setstr(iface, WI_RID_NODENAME, optarg);
966                         exit(0);
967                         break;
968                 case 'm':
969                         wi_sethex(iface, WI_RID_MAC_NODE, optarg);
970                         exit(0);
971                         break;
972                 case 'q':
973                         wi_setstr(iface, WI_RID_OWN_SSID, optarg);
974                         exit(0);
975                         break;
976                 case 'S':
977                         wi_setword(iface, WI_RID_MAX_SLEEP, atoi(optarg));
978                         exit(0);
979                         break;
980                 case 'T':
981                         wi_setword(iface,
982                             WI_RID_TX_CRYPT_KEY, atoi(optarg) - 1);
983                         exit(0);
984                         break;
985                 case 'P':
986                         wi_setword(iface, WI_RID_PM_ENABLED, atoi(optarg));
987                         exit(0);
988                         break;
989                 case 'a':
990                         wi_setword(iface, WI_RID_SYSTEM_SCALE, atoi(optarg));
991                         exit(0);
992                         break;
993                 case 'v':
994                         modifier = atoi(optarg);
995                         modifier--;
996                         break;
997                 case 'h':
998                 default:
999                         usage(p);
1000                         break;
1001                 }
1002         }
1003
1004         if (iface == NULL)
1005                 usage(p);
1006
1007         if (key != NULL) {
1008                 wi_setkeys(iface, key, modifier);
1009                 exit(0);
1010         }
1011
1012         wi_dumpinfo(iface);
1013
1014         exit(0);
1015 }