Kernel tree reorganization stage 2: Major cvs repository work.
[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  * @(#) Copyright (c) 1997, 1998, 1999 Bill Paul. All rights reserved.
33  * $FreeBSD: src/usr.sbin/wicontrol/wicontrol.c,v 1.9.2.7 2002/08/03 07:24:17 imp Exp $
34  * $DragonFly: src/usr.sbin/wicontrol/Attic/wicontrol.c,v 1.3 2003/08/08 04:18:49 dillon Exp $
35  */
36
37 #include <sys/types.h>
38 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/socket.h>
43
44 #include <net/if.h>
45 #include <net/if_var.h>
46 #include <net/ethernet.h>
47
48 #include <net/if_ieee80211.h>
49 #include <dev/netif/wi/if_wavelan_ieee.h>
50 #include <dev/netif/wi/wi_hostap.h>
51 #include <dev/netif/wi/if_wireg.h>
52
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <ctype.h>
58 #include <errno.h>
59 #include <err.h>
60
61 static void wi_getval(const char *, struct wi_req *);
62 static void wi_setval(const char *, struct wi_req *);
63 static void wi_printstr(struct wi_req *);
64 static void wi_setstr(const char *, int, char *);
65 static void wi_setbytes(const char *, int, char *, int);
66 static void wi_setword(const char *, int, int);
67 static void wi_sethex(const char *, int, char *);
68 static void wi_printwords(struct wi_req *);
69 static void wi_printbool(struct wi_req *);
70 static void wi_printhex(struct wi_req *);
71 static void wi_dumpinfo(const char *);
72 static void wi_dumpstats(const char *);
73 static void wi_setkeys(const char *, char *, int);
74 static void wi_printkeys(struct wi_req *);
75 static void wi_printaplist(const char *);
76 static int wi_hex2int(char);
77 static void wi_str2key(char *, struct wi_key *);
78 #ifdef WICACHE
79 static void wi_zerocache(const char *);
80 static void wi_readcache(const char *);
81 #endif
82 static void usage(const char *);
83
84 int listaps;
85
86 /*
87  * Print a value a la the %b format of the kernel's printf
88  * (ripped screaming from ifconfig/ifconfig.c)
89  */
90 void
91 printb(s, v, bits)
92         char *s;
93         char *bits;
94         unsigned short v;
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 void
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                 err(1, "SIOCGWAVELAN");
139
140         close(s);
141
142         return;
143 }
144
145 static void
146 wi_setval(const char *iface, struct wi_req *wreq)
147 {
148         struct ifreq            ifr;
149         int                     s;
150
151         bzero((char *)&ifr, sizeof(ifr));
152
153         strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
154         ifr.ifr_data = (caddr_t)wreq;
155
156         s = socket(AF_INET, SOCK_DGRAM, 0);
157
158         if (s == -1)
159                 err(1, "socket");
160
161         if (ioctl(s, SIOCSWAVELAN, &ifr) == -1)
162                 err(1, "SIOCSWAVELAN");
163
164         close(s);
165
166         return;
167 }
168
169 void
170 wi_printstr(struct wi_req *wreq)
171 {
172         char                    *ptr;
173         int                     i;
174
175         if (wreq->wi_type == WI_RID_SERIALNO) {
176                 ptr = (char *)&wreq->wi_val;
177                 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
178                         if (ptr[i] == '\0')
179                                 ptr[i] = ' ';
180                 }
181         } else {
182                 ptr = (char *)&wreq->wi_val[1];
183                 for (i = 0; i < wreq->wi_val[0]; i++) {
184                         if (ptr[i] == '\0')
185                                 ptr[i] = ' ';
186                 }
187         }
188
189         ptr[i] = '\0';
190         printf("[ %s ]", ptr);
191
192         return;
193 }
194
195 void
196 wi_setstr(const char *iface, int code, char *str)
197 {
198         struct wi_req           wreq;
199
200         if (iface == NULL)
201                 errx(1, "must specify interface name");
202
203         if (str == NULL)
204                 errx(1, "must specify string");
205
206         bzero((char *)&wreq, sizeof(wreq));
207
208         if (strlen(str) > 30)
209                 errx(1, "string too long");
210
211         wreq.wi_type = code;
212         wreq.wi_len = 18;
213         wreq.wi_val[0] = strlen(str);
214         bcopy(str, (char *)&wreq.wi_val[1], strlen(str));
215
216         wi_setval(iface, &wreq);
217
218         return;
219 }
220
221 void
222 wi_setbytes(const char *iface, int code, char *bytes, int len)
223 {
224         struct wi_req           wreq;
225
226         if (iface == NULL)
227                 errx(1, "must specify interface name");
228
229         bzero((char *)&wreq, sizeof(wreq));
230
231         wreq.wi_type = code;
232         wreq.wi_len = (len / 2) + 1;
233         bcopy(bytes, (char *)&wreq.wi_val[0], len);
234
235         wi_setval(iface, &wreq);
236
237         return;
238 }
239
240 void
241 wi_setword(const char *iface, int code, int word)
242 {
243         struct wi_req           wreq;
244
245         bzero((char *)&wreq, sizeof(wreq));
246
247         wreq.wi_type = code;
248         wreq.wi_len = 2;
249         wreq.wi_val[0] = word;
250
251         wi_setval(iface, &wreq);
252
253         return;
254 }
255
256 void
257 wi_sethex(const char *iface, int code, char *str)
258 {
259         struct ether_addr       *addr;
260
261         if (str == NULL)
262                 errx(1, "must specify address");
263
264         addr = ether_aton(str);
265
266         if (addr == NULL)
267                 errx(1, "badly formatted address");
268
269         wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN);
270
271         return;
272 }
273
274 static int
275 wi_hex2int(char c)
276 {
277         if (c >= '0' && c <= '9')
278                 return (c - '0');
279         if (c >= 'A' && c <= 'F')
280                 return (c - 'A' + 10);
281         if (c >= 'a' && c <= 'f')
282                 return (c - 'a' + 10);
283
284         return (0); 
285 }
286
287 static void
288 wi_str2key(char *s, struct wi_key *k)
289 {
290         int                     n, i;
291         char                    *p;
292
293         /* Is this a hex string? */
294         if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
295                 /* Yes, convert to int. */
296                 n = 0;
297                 p = (char *)&k->wi_keydat[0];
298                 for (i = 2; s[i] != '\0' && s[i + 1] != '\0'; i+= 2) {
299                         *p++ = (wi_hex2int(s[i]) << 4) + wi_hex2int(s[i + 1]);
300                         n++;
301                 }
302                 if (s[i] != '\0')
303                         errx(1, "hex strings must be of even length");
304                 k->wi_keylen = n;
305         } else {
306                 /* No, just copy it in. */
307                 bcopy(s, k->wi_keydat, strlen(s));
308                 k->wi_keylen = strlen(s);
309         }
310
311         return;
312 }
313
314 static void
315 wi_setkeys(const char *iface, char *key, int idx)
316 {
317         int                     keylen;
318         struct wi_req           wreq;
319         struct wi_ltv_keys      *keys;
320         struct wi_key           *k;
321
322         bzero((char *)&wreq, sizeof(wreq));
323         wreq.wi_len = WI_MAX_DATALEN;
324         wreq.wi_type = WI_RID_WEP_AVAIL;
325
326         wi_getval(iface, &wreq);
327         if (wreq.wi_val[0] == 0)
328                 errx(1, "no WEP option available on this card");
329
330         bzero((char *)&wreq, sizeof(wreq));
331         wreq.wi_len = WI_MAX_DATALEN;
332         wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
333
334         wi_getval(iface, &wreq);
335         keys = (struct wi_ltv_keys *)&wreq;
336
337         keylen = strlen(key);
338         if (key[0] == '0' && (key[1] == 'x' || key[1] == 'X')) {
339                 if (keylen != 2 && keylen != 12 && keylen != 28) {
340                         errx(1, "encryption key must be 0, 10, or 26 "
341                             "hex digits long");
342                 }
343         } else {
344                 if (keylen != 0 && keylen != 5 && keylen != 13) {
345                         errx(1, "encryption key must be 0, 5, or 13 "
346                             "bytes long");
347                 }
348         }
349
350         if (idx > 3)
351                 errx(1, "only 4 encryption keys available");
352
353         k = &keys->wi_keys[idx];
354         wi_str2key(key, k);
355
356         wreq.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
357         wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
358         wi_setval(iface, &wreq);
359
360         return;
361 }
362
363 static void
364 wi_printkeys(struct wi_req *wreq)
365 {
366         int                     i, j;
367         int                     isprintable;
368         struct wi_key           *k;
369         struct wi_ltv_keys      *keys;
370         char                    *ptr;
371
372         keys = (struct wi_ltv_keys *)wreq;
373
374         for (i = 0; i < 4; i++) {
375                 k = &keys->wi_keys[i];
376                 ptr = (char *)k->wi_keydat;
377                 isprintable = 1;
378                 for (j = 0; j < k->wi_keylen; j++) {
379                         if (!isprint(ptr[j])) {
380                                 isprintable = 0;
381                                 break;
382                         }
383                 }
384                 if (isprintable) {
385                         ptr[j] = '\0';
386                         printf("[ %s ]", ptr);
387                 } else {
388                         printf("[ 0x");
389                         for (j = 0; j < k->wi_keylen; j++) {
390                                 printf("%02x", ptr[j] & 0xFF);
391                         }
392                         printf(" ]");
393                                         
394                 }
395         }
396
397         return;
398 };
399
400 void
401 wi_printwords(struct wi_req *wreq)
402 {
403         int                     i;
404
405         printf("[ ");
406         for (i = 0; i < wreq->wi_len - 1; i++)
407                 printf("%d ", wreq->wi_val[i]);
408         printf("]");
409
410         return;
411 }
412
413 void
414 wi_printbool(struct wi_req *wreq)
415 {
416         if (wreq->wi_val[0])
417                 printf("[ On ]");
418         else
419                 printf("[ Off ]");
420
421         return;
422 }
423
424 void
425 wi_printhex(struct wi_req *wreq)
426 {
427         int                     i;
428         unsigned char           *c;
429
430         c = (unsigned char *)&wreq->wi_val;
431
432         printf("[ ");
433         for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
434                 printf("%02x", c[i]);
435                 if (i < ((wreq->wi_len - 1) * 2) - 1)
436                         printf(":");
437         }
438
439         printf(" ]");
440         return;
441 }
442
443 void
444 wi_printaplist(const char *iface)
445 {
446         int                     prism2, len, i = 0, j;
447         struct wi_req           wreq;
448         struct wi_scan_p2_hdr   *wi_p2_h;
449         struct wi_scan_res      *res;
450
451         printf("Available APs:\n");
452
453         /* first determine if this is a prism2 card or not */
454         wreq.wi_len = WI_MAX_DATALEN;
455         wreq.wi_type = WI_RID_PRISM2;
456
457         wi_getval(iface, &wreq);
458         prism2 = wreq.wi_val[0];
459
460         /* send out a scan request */
461         wreq.wi_len = prism2 ? 3 : 1;
462         wreq.wi_type = WI_RID_SCAN_REQ;
463
464         if (prism2) {
465                 wreq.wi_val[0] = 0x3FFF;
466                 wreq.wi_val[1] = 0x000F;
467         }
468
469         wi_setval(iface, &wreq);
470
471         /*
472          * sleep for 100 milliseconds so there's enough time for the card to
473          * respond... prism2's take a little longer.
474          */
475         usleep(prism2 ? 500000 : 100000);
476
477         /* get the scan results */
478         wreq.wi_len = WI_MAX_DATALEN;
479         wreq.wi_type = WI_RID_SCAN_RES;
480
481         wi_getval(iface, &wreq);
482
483         if (prism2) {
484                 wi_p2_h = (struct wi_scan_p2_hdr *)wreq.wi_val;
485
486                 /* if the reason is 0, this info is invalid */
487                 if (wi_p2_h->wi_reason == 0)
488                         return;
489
490                 i = 4;
491         }
492
493         len = prism2 ? WI_PRISM2_RES_SIZE : WI_WAVELAN_RES_SIZE;
494
495         for (; i < (wreq.wi_len * 2) - len; i += len) {
496                 res = (struct wi_scan_res *)((char *)wreq.wi_val + i);
497
498                 res->wi_ssid[res->wi_ssid_len] = '\0';
499
500                 printf("    %-8s  [ %02x:%02x:%02x:%02x:%02x:%02x ]  [ %-2d ]  "
501                     "[ %d %d %d ]  %-3d  ", res->wi_ssid,
502                     res->wi_bssid[0], res->wi_bssid[1], res->wi_bssid[2],
503                     res->wi_bssid[3], res->wi_bssid[4], res->wi_bssid[5],
504                     res->wi_chan, res->wi_signal - res->wi_noise,
505                     res->wi_signal, res->wi_noise, res->wi_interval);
506
507                 if (res->wi_capinfo) {
508                         printf("[ ");
509                         if (res->wi_capinfo & WI_CAPINFO_ESS)
510                                 printf("ess ");
511                         if (res->wi_capinfo & WI_CAPINFO_IBSS)
512                                 printf("ibss ");
513                         if (res->wi_capinfo & WI_CAPINFO_PRIV)
514                                 printf("priv ");
515                         printf("]  ");
516                 }
517
518                 if (prism2) {
519                         printf("\n              [ ");
520                         for (j = 0; res->wi_srates[j] != 0; j++) {
521                                 res->wi_srates[j] = res->wi_srates[j] &
522                                     WI_VAR_SRATES_MASK;
523                                 printf("%d.%d ", res->wi_srates[j] / 2,
524                                     (res->wi_srates[j] % 2) * 5);
525                         }
526                         printf("]  ");
527
528                         printf("* %2.1f *", res->wi_rate == 0xa ? 1 :
529                             (res->wi_rate == 0x14 ? 2 :
530                             (res->wi_rate == 0x37 ? 5.5 :
531                             (res->wi_rate == 0x6e ? 11 : 0))));
532                 }
533
534                 putchar('\n');
535         }
536
537         return;
538 }
539
540 #define WI_STRING               0x01
541 #define WI_BOOL                 0x02
542 #define WI_WORDS                0x03
543 #define WI_HEXBYTES             0x04
544 #define WI_KEYSTRUCT            0x05
545
546 struct wi_table {
547         int                     wi_code;
548         int                     wi_type;
549         const char              *wi_str;
550 };
551
552 static struct wi_table wi_table[] = {
553         { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" },
554         { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t" },
555         { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t" },
556         { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" },
557         { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t" },
558         { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" },
559         { WI_RID_CHANNEL_LIST, WI_WORDS, "Channel list:\t\t\t\t" },
560         { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t" },
561         { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" },
562         { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" },
563         { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" },
564         { WI_RID_PROCFRAME, WI_BOOL, "Process 802.11b Frame:\t\t\t" },
565         { WI_RID_PRISM2, WI_WORDS, "Intersil-Prism2 based card:\t\t" },
566         { WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t"},
567         { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t"},
568         { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t"},
569         { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"},
570         { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t"},
571         { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t" },
572         { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t" },
573         { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t" },
574         { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time:\t\t\t\t" },
575         { 0, 0, NULL }
576 };
577
578 static struct wi_table wi_crypt_table[] = {
579         { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t" },
580         { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" },
581         { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" },
582         { 0, 0, NULL }
583 };
584
585 static void
586 wi_dumpinfo(const char *iface)
587 {
588         struct wi_req           wreq;
589         int                     i, has_wep;
590         struct wi_table         *w;
591
592         bzero((char *)&wreq, sizeof(wreq));
593
594         wreq.wi_len = WI_MAX_DATALEN;
595         wreq.wi_type = WI_RID_WEP_AVAIL;
596
597         wi_getval(iface, &wreq);
598         has_wep = wreq.wi_val[0];
599
600         w = wi_table;
601
602         for (i = 0; w[i].wi_type; i++) {
603                 bzero((char *)&wreq, sizeof(wreq));
604
605                 wreq.wi_len = WI_MAX_DATALEN;
606                 wreq.wi_type = w[i].wi_code;
607
608                 wi_getval(iface, &wreq);
609                 printf("%s", w[i].wi_str);
610                 switch(w[i].wi_type) {
611                 case WI_STRING:
612                         wi_printstr(&wreq);
613                         break;
614                 case WI_WORDS:
615                         wi_printwords(&wreq);
616                         break;
617                 case WI_BOOL:
618                         wi_printbool(&wreq);
619                         break;
620                 case WI_HEXBYTES:
621                         wi_printhex(&wreq);
622                         break;
623                 default:
624                         break;
625                 }       
626                 printf("\n");
627         }
628
629         if (has_wep) {
630                 w = wi_crypt_table;
631                 for (i = 0; w[i].wi_type; i++) {
632                         bzero((char *)&wreq, sizeof(wreq));
633
634                         wreq.wi_len = WI_MAX_DATALEN;
635                         wreq.wi_type = w[i].wi_code;
636
637                         wi_getval(iface, &wreq);
638                         printf("%s", w[i].wi_str);
639                         switch(w[i].wi_type) {
640                         case WI_STRING:
641                                 wi_printstr(&wreq);
642                                 break;
643                         case WI_WORDS:
644                                 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
645                                         wreq.wi_val[0]++;
646                                 wi_printwords(&wreq);
647                                 break;
648                         case WI_BOOL:
649                                 wi_printbool(&wreq);
650                                 break;
651                         case WI_HEXBYTES:
652                                 wi_printhex(&wreq);
653                                 break;
654                         case WI_KEYSTRUCT:
655                                 wi_printkeys(&wreq);
656                                 break;
657                         default:
658                                 break;
659                         }       
660                         printf("\n");
661                 }
662         }
663
664         if (listaps)
665                 wi_printaplist(iface);
666
667         return;
668 }
669
670 static void
671 wi_dumpstats(const char *iface)
672 {
673         struct wi_req           wreq;
674         struct wi_counters      *c;
675
676         if (iface == NULL)
677                 errx(1, "must specify interface name");
678
679         bzero((char *)&wreq, sizeof(wreq));
680         wreq.wi_len = WI_MAX_DATALEN;
681         wreq.wi_type = WI_RID_IFACE_STATS;
682
683         wi_getval(iface, &wreq);
684
685         c = (struct wi_counters *)&wreq.wi_val;
686
687         printf("Transmitted unicast frames:\t\t%d\n",
688             c->wi_tx_unicast_frames);
689         printf("Transmitted multicast frames:\t\t%d\n",
690             c->wi_tx_multicast_frames);
691         printf("Transmitted fragments:\t\t\t%d\n",
692             c->wi_tx_fragments);
693         printf("Transmitted unicast octets:\t\t%d\n",
694             c->wi_tx_unicast_octets);
695         printf("Transmitted multicast octets:\t\t%d\n",
696             c->wi_tx_multicast_octets);
697         printf("Single transmit retries:\t\t%d\n",
698             c->wi_tx_single_retries);
699         printf("Multiple transmit retries:\t\t%d\n",
700             c->wi_tx_multi_retries);
701         printf("Transmit retry limit exceeded:\t\t%d\n",
702             c->wi_tx_retry_limit);
703         printf("Transmit discards:\t\t\t%d\n",
704             c->wi_tx_discards);
705         printf("Transmit discards due to wrong SA:\t%d\n",
706             c->wi_tx_discards_wrong_sa);
707         printf("Received unicast frames:\t\t%d\n",
708             c->wi_rx_unicast_frames);
709         printf("Received multicast frames:\t\t%d\n",
710             c->wi_rx_multicast_frames);
711         printf("Received fragments:\t\t\t%d\n",
712             c->wi_rx_fragments);
713         printf("Received unicast octets:\t\t%d\n",
714             c->wi_rx_unicast_octets);
715         printf("Received multicast octets:\t\t%d\n",
716             c->wi_rx_multicast_octets);
717         printf("Receive FCS errors:\t\t\t%d\n",
718             c->wi_rx_fcs_errors);
719         printf("Receive discards due to no buffer:\t%d\n",
720             c->wi_rx_discards_nobuf);
721         printf("Can't decrypt WEP frame:\t\t%d\n",
722             c->wi_rx_WEP_cant_decrypt);
723         printf("Received message fragments:\t\t%d\n",
724             c->wi_rx_msg_in_msg_frags);
725         printf("Received message bad fragments:\t\t%d\n",
726             c->wi_rx_msg_in_bad_msg_frags);
727
728         return;
729 }
730
731 static void
732 usage(const char *p)
733 {
734         fprintf(stderr, "usage:  %s -i iface\n", p);
735         fprintf(stderr, "\t%s -i iface -o\n", p);
736         fprintf(stderr, "\t%s -i iface -l\n", p);
737         fprintf(stderr, "\t%s -i iface -t tx rate\n", p);
738         fprintf(stderr, "\t%s -i iface -n network name\n", p);
739         fprintf(stderr, "\t%s -i iface -s station name\n", p);
740         fprintf(stderr, "\t%s -i iface -c 0|1\n", p);
741         fprintf(stderr, "\t%s -i iface -q SSID\n", p);
742         fprintf(stderr, "\t%s -i iface -p port type\n", p);
743         fprintf(stderr, "\t%s -i iface -a access point density\n", p);
744         fprintf(stderr, "\t%s -i iface -m mac address\n", p);
745         fprintf(stderr, "\t%s -i iface -d max data length\n", p);
746         fprintf(stderr, "\t%s -i iface -e 0|1\n", p);
747         fprintf(stderr, "\t%s -i iface -k encryption key [-v 1|2|3|4]\n", p);
748         fprintf(stderr, "\t%s -i iface -r RTS threshold\n", p);
749         fprintf(stderr, "\t%s -i iface -f frequency\n", p);
750         fprintf(stderr, "\t%s -i iface -F 0|1\n", p);
751         fprintf(stderr, "\t%s -i iface -P 0|1\n", p);
752         fprintf(stderr, "\t%s -i iface -S max sleep duration\n", p);
753         fprintf(stderr, "\t%s -i iface -T 1|2|3|4\n", p);
754 #ifdef WICACHE
755         fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
756         fprintf(stderr, "\t%s -i iface -C print signal cache\n", p);
757 #endif
758
759         exit(1);
760 }
761
762 static void
763 wi_dumpstations(const char *iface)
764 {
765         struct hostap_getall    reqall;
766         struct hostap_sta       stas[WIHAP_MAX_STATIONS];
767         struct ifreq            ifr;
768         int i, s;
769
770         bzero(&ifr, sizeof(ifr));
771         strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
772         ifr.ifr_data = (caddr_t) & reqall;
773         bzero(&reqall, sizeof(reqall));
774         reqall.size = sizeof(stas);
775         reqall.addr = stas;
776         bzero(&stas, sizeof(stas));
777
778         s = socket(AF_INET, SOCK_DGRAM, 0);
779         if (s == -1)
780                 err(1, "socket");
781
782         if (ioctl(s, SIOCHOSTAP_GETALL, &ifr) < 0)
783                 err(1, "SIOCHOSTAP_GETALL");
784
785         printf("%d station%s:\n", reqall.nstations, reqall.nstations>1?"s":"");
786         for (i = 0; i < reqall.nstations; i++) {
787                 struct hostap_sta *info = &stas[i];
788
789                 printf("%02x:%02x:%02x:%02x:%02x:%02x  asid=%04x",
790                         info->addr[0], info->addr[1], info->addr[2],
791                         info->addr[3], info->addr[4], info->addr[5],
792                         info->asid - 0xc001);
793                 printb(", flags", info->flags, HOSTAP_FLAGS_BITS);
794                 printb(", caps", info->capinfo, IEEE80211_CAPINFO_BITS);
795                 printb(", rates", info->rates, WI_RATES_BITS);
796                 if (info->sig_info)
797                         printf(", sig=%d/%d",
798                             info->sig_info >> 8, info->sig_info & 0xff);
799                 putchar('\n');
800         }
801 }
802
803 #ifdef WICACHE
804 static void
805 wi_zerocache(const char *iface)
806 {
807         struct wi_req           wreq;
808
809         if (iface == NULL)
810                 errx(1, "must specify interface name");
811
812         bzero((char *)&wreq, sizeof(wreq));
813         wreq.wi_len = 0;
814         wreq.wi_type = WI_RID_ZERO_CACHE;
815
816         wi_getval(iface, &wreq);
817 }
818
819 static void
820 wi_readcache(const char *iface)
821 {
822         struct wi_req           wreq;
823         int                     *wi_sigitems;
824         struct wi_sigcache      *sc;
825         char *                  pt;
826         int                     i;
827
828         if (iface == NULL)
829                 errx(1, "must specify interface name");
830
831         bzero((char *)&wreq, sizeof(wreq));
832         wreq.wi_len = WI_MAX_DATALEN;
833         wreq.wi_type = WI_RID_READ_CACHE;
834
835         wi_getval(iface, &wreq);
836
837         wi_sigitems = (int *) &wreq.wi_val; 
838         pt = ((char *) &wreq.wi_val);
839         pt += sizeof(int);
840         sc = (struct wi_sigcache *) pt;
841
842         for (i = 0; i < *wi_sigitems; i++) {
843                 printf("[%d/%d]:", i+1, *wi_sigitems);
844                 printf(" %02x:%02x:%02x:%02x:%02x:%02x,",
845                                         sc->macsrc[0]&0xff,
846                                         sc->macsrc[1]&0xff,
847                                         sc->macsrc[2]&0xff,
848                                         sc->macsrc[3]&0xff,
849                                         sc->macsrc[4]&0xff,
850                                         sc->macsrc[5]&0xff);
851                 printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff),
852                                         ((sc->ipsrc >> 8) & 0xff),
853                                         ((sc->ipsrc >> 16) & 0xff),
854                                         ((sc->ipsrc >> 24) & 0xff));
855                 printf(" sig: %d, noise: %d, qual: %d\n",
856                                         sc->signal,
857                                         sc->noise,
858                                         sc->quality);
859                 sc++;
860         }
861
862         return;
863 }
864 #endif
865
866 int
867 main(int argc, char *argv[])
868 {
869         int                     ch;
870         const char              *iface = NULL;
871         char                    *p = argv[0];
872         char                    *key = NULL;
873         int                     modifier = 0;
874
875         /* Get the interface name */
876         opterr = 0;
877         ch = getopt(argc, argv, "i:");
878         if (ch == 'i') {
879                 iface = optarg;
880         } else {
881                 if (argc > 1 && *argv[1] != '-') {
882                         iface = argv[1];
883                         optind = 2; 
884                 } else {
885                         iface = "wi0";
886                         optind = 1;
887                 }
888                 optreset = 1;
889         }
890         opterr = 1;
891                 
892         while((ch = getopt(argc, argv,
893             "a:hoc:d:e:f:i:k:lp:r:q:t:n:s:m:v:F:LP:S:T:ZC")) != -1) {
894                 switch(ch) {
895                 case 'Z':
896 #ifdef WICACHE
897                         wi_zerocache(iface);
898 #else
899                         printf("WICACHE not available\n");
900 #endif
901                         exit(0);
902                         break;
903                 case 'C':
904 #ifdef WICACHE
905                         wi_readcache(iface);
906 #else
907                         printf("WICACHE not available\n");
908 #endif
909                         exit(0);
910                         break;
911                 case 'o':
912                         wi_dumpstats(iface);
913                         exit(0);
914                         break;
915                 case 'c':
916                         wi_setword(iface, WI_RID_CREATE_IBSS, atoi(optarg));
917                         exit(0);
918                         break;
919                 case 'd':
920                         wi_setword(iface, WI_RID_MAX_DATALEN, atoi(optarg));
921                         exit(0);
922                         break;
923                 case 'e':
924                         wi_setword(iface, WI_RID_ENCRYPTION, atoi(optarg));
925                         exit(0);
926                         break;
927                 case 'f':
928                         wi_setword(iface, WI_RID_OWN_CHNL, atoi(optarg));
929                         exit(0);
930                         break;
931                 case 'F':
932                         wi_setword(iface, WI_RID_PROCFRAME, atoi(optarg));
933                         exit(0);
934                         break;
935                 case 'k':
936                         key = optarg;
937                         break;
938                 case 'L':
939                         listaps = 1;
940                         break;
941                 case 'l':
942                         wi_dumpstations(iface);
943                         exit(0);
944                         break;
945                 case 'p':
946                         wi_setword(iface, WI_RID_PORTTYPE, atoi(optarg));
947                         exit(0);
948                         break;
949                 case 'r':
950                         wi_setword(iface, WI_RID_RTS_THRESH, atoi(optarg));
951                         exit(0);
952                         break;
953                 case 't':
954                         wi_setword(iface, WI_RID_TX_RATE, atoi(optarg));
955                         exit(0);
956                         break;
957                 case 'n':
958                         wi_setstr(iface, WI_RID_DESIRED_SSID, optarg);
959                         exit(0);
960                         break;
961                 case 's':
962                         wi_setstr(iface, WI_RID_NODENAME, optarg);
963                         exit(0);
964                         break;
965                 case 'm':
966                         wi_sethex(iface, WI_RID_MAC_NODE, optarg);
967                         exit(0);
968                         break;
969                 case 'q':
970                         wi_setstr(iface, WI_RID_OWN_SSID, optarg);
971                         exit(0);
972                         break;
973                 case 'S':
974                         wi_setword(iface, WI_RID_MAX_SLEEP, atoi(optarg));
975                         exit(0);
976                         break;
977                 case 'T':
978                         wi_setword(iface,
979                             WI_RID_TX_CRYPT_KEY, atoi(optarg) - 1);
980                         exit(0);
981                         break;
982                 case 'P':
983                         wi_setword(iface, WI_RID_PM_ENABLED, atoi(optarg));
984                         exit(0);
985                         break;
986                 case 'a':
987                         wi_setword(iface, WI_RID_SYSTEM_SCALE, atoi(optarg));
988                         exit(0);
989                         break;
990                 case 'v':
991                         modifier = atoi(optarg);
992                         modifier--;
993                         break;
994                 case 'h':
995                 default:
996                         usage(p);
997                         break;
998                 }
999         }
1000
1001         if (iface == NULL)
1002                 usage(p);
1003
1004         if (key != NULL) {
1005                 wi_setkeys(iface, key, modifier);
1006                 exit(0);
1007         }
1008
1009         wi_dumpinfo(iface);
1010
1011         exit(0);
1012 }