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