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