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