wiconfig.c revision 1.46 1 /* $NetBSD: wiconfig.c,v 1.46 2025/06/15 14:49:32 rillig Exp $ */
2 /*
3 * Copyright (c) 1997, 1998, 1999
4 * Bill Paul <wpaul (at) ctr.columbia.edu>. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Bill Paul.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * From: Id: wicontrol.c,v 1.6 1999/05/22 16:12:49 wpaul Exp $
34 */
35
36 #include <sys/types.h>
37 #include <sys/cdefs.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
41
42 #include <net/if.h>
43 #ifdef __FreeBSD__
44 #include <net/if_var.h>
45 #include <net/ethernet.h>
46
47 #include <machine/if_wavelan_ieee.h>
48 #else
49 #include <netinet/in.h>
50 #include <netinet/if_ether.h>
51 #ifdef __NetBSD__
52 #include <net80211/ieee80211.h>
53 #include <net80211/ieee80211_ioctl.h>
54 #include <dev/ic/wi_ieee.h>
55 #else
56 #include <dev/pcmcia/if_wavelan_ieee.h>
57 #endif
58 #endif
59
60 #include <stdio.h>
61 #include <string.h>
62 #include <ctype.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 #include <errno.h>
66 #include <err.h>
67
68 __COPYRIGHT("@(#) Copyright (c) 1997, 1998, 1999\
69 Bill Paul. All rights reserved.");
70 __RCSID("$NetBSD: wiconfig.c,v 1.46 2025/06/15 14:49:32 rillig Exp $");
71
72 struct wi_table {
73 int wi_type;
74 int wi_code;
75 #define WI_NONE 0x00
76 #define WI_STRING 0x01
77 #define WI_BOOL 0x02
78 #define WI_WORDS 0x03
79 #define WI_HEXBYTES 0x04
80 #define WI_KEYSTRUCT 0x05
81 #define WI_BITS 0x06
82 #define WI_VENDOR 0x07
83 const char *wi_label; /* label used to print info */
84 int wi_opt; /* option character to set this */
85 const char *wi_desc;
86 char *wi_optval;
87 };
88
89 /* already define in wireg.h XXX */
90 #define WI_APRATE_0 0x00 /* NONE */
91 #define WI_APRATE_1 0x0A /* 1 Mbps */
92 #define WI_APRATE_2 0x14 /* 2 Mbps */
93 #define WI_APRATE_5 0x37 /* 5.5 Mbps */
94 #define WI_APRATE_11 0x6E /* 11 Mbps */
95
96 #ifdef WI_RID_SCAN_APS
97 static void wi_apscan(char *);
98 static int get_if_flags(int, const char *);
99 static int set_if_flags(int, const char *, int);
100 #endif
101 static int wi_getval(char *, struct wi_req *);
102 static void wi_setval(char *, struct wi_req *);
103 static void wi_printstr(struct wi_req *);
104 static void wi_setstr(char *, int, char *);
105 static void wi_setbytes(char *, int, char *, int);
106 static void wi_setword(char *, int, int);
107 static void wi_sethex(char *, int, char *);
108 static void wi_printwords(struct wi_req *);
109 static void wi_printbool(struct wi_req *);
110 static void wi_printhex(struct wi_req *);
111 static void wi_printbits(struct wi_req *);
112 static void wi_checkwifi(char *);
113 static void wi_dumpinfo(char *);
114 static void wi_printkeys(struct wi_req *);
115 static void wi_printvendor(struct wi_req *);
116 static void wi_dumpstats(char *);
117 __dead static void usage(void);
118 static struct wi_table *wi_optlookup(struct wi_table *, int);
119
120 #ifdef WI_RID_SCAN_APS
121 static int
122 get_if_flags(int s, const char *name)
123 {
124 struct ifreq ifreq;
125 int flags;
126
127 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
128 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) == -1)
129 err(1, "SIOCGIFFLAGS");
130 flags = ifreq.ifr_flags;
131
132 return flags;
133 }
134
135 static int
136 set_if_flags(int s, const char *name, int flags)
137 {
138 struct ifreq ifreq;
139
140 ifreq.ifr_flags = flags;
141 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
142 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) == -1)
143 err(1, "SIOCSIFFLAGS");
144
145 return 0;
146 }
147
148 static void
149 wi_apscan(char *iface)
150 {
151 struct wi_req wreq;
152 struct ifreq ifr;
153 int s;
154 int naps, rate;
155 int retries = 10;
156 int flags;
157 struct wi_apinfo aps[howmany(WI_MAX_DATALEN,
158 sizeof(struct wi_apinfo))];
159 int i, j;
160
161 if (iface == NULL)
162 errx(1, "must specify interface name");
163
164 s = socket(AF_INET, SOCK_DGRAM, 0);
165 if (s == -1)
166 err(1, "socket");
167 flags = get_if_flags(s, iface);
168 if ((flags & IFF_UP) == 0)
169 flags = set_if_flags(s, iface, flags | IFF_UP);
170
171 memset(&wreq, 0, sizeof(wreq));
172
173 wreq.wi_type = WI_RID_SCAN_APS;
174 wreq.wi_len = 4;
175 /* note chan. 1 is the least significant bit */
176 wreq.wi_val[0] = htole16(0x3fff); /* 1 bit per channel, 1-14 */
177 wreq.wi_val[1] = htole16(0xf); /* tx rate */
178
179 /* write the request */
180 wi_setval(iface, &wreq);
181
182 /* now poll for a result */
183 memset(&wreq, 0, sizeof(wreq));
184
185 wreq.wi_type = WI_RID_READ_APS;
186 wreq.wi_len = WI_MAX_DATALEN;
187
188 /* we have to do this ourself as opposed to
189 * using getval, because we cannot bail if
190 * the ioctl fails
191 */
192 memset(&ifr, 0, sizeof(ifr));
193 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
194 ifr.ifr_data = (caddr_t)&wreq;
195
196 printf("scanning ...");
197 fflush(stdout);
198 while (ioctl(s, SIOCGWAVELAN, &ifr) == -1) {
199 retries--;
200 if (retries >= 0) {
201 printf(".");
202 fflush(stdout);
203 sleep(1);
204 } else
205 break;
206 errno = 0;
207 }
208
209 if (errno) {
210 set_if_flags(s, iface, flags);
211 close(s);
212 err(1, "ioctl");
213 }
214
215 memcpy(&naps, wreq.wi_val, sizeof(int));
216
217 if (naps > 0)
218 printf("\nAP Information\n");
219 else
220 printf("\nNo APs available\n");
221
222 naps = MIN((unsigned)naps,
223 howmany(sizeof(wreq.wi_val) - sizeof(int), sizeof(*aps)));
224 memcpy(aps, (const char *)wreq.wi_val + sizeof(int),
225 (unsigned)naps * sizeof(*aps));
226
227 for (i = 0; i < naps; i++) {
228 const struct wi_apinfo *const w = &aps[i];
229
230 printf("ap[%d]:\n", i);
231 if (w->scanreason) {
232 static const char *scanm[] = {
233 "Host initiated",
234 "Firmware initiated",
235 "Inquiry request from host"
236 };
237 printf("\tScanReason:\t\t\t[ %s ]\n",
238 scanm[w->scanreason - 1]);
239 }
240 printf("\tnetname (SSID):\t\t\t[ ");
241 for (j = 0; j < w->namelen; j++)
242 printf("%c", w->name[j]);
243 printf(" ]\n");
244 printf("\tBSSID:\t\t\t\t[ %02x:%02x:%02x:%02x:%02x:%02x ]\n",
245 w->bssid[0] & 0xff, w->bssid[1] & 0xff,
246 w->bssid[2] & 0xff, w->bssid[3] & 0xff,
247 w->bssid[4] & 0xff, w->bssid[5] & 0xff);
248 printf("\tChannel:\t\t\t[ %d ]\n", w->channel);
249 printf(""
250 "\tQuality/Signal/Noise [signal]:\t[ %d / %d / %d ]\n"
251 "\t [dBm]:\t[ %d / %d / %d ]\n",
252 w->quality, w->signal, w->noise,
253 w->quality, w->signal - 149, w->noise - 149);
254 printf("\tBSS Beacon Interval [msec]:\t[ %d ]\n", w->interval);
255 printf("\tCapinfo:\t\t\t[ ");
256 if (w->capinfo & IEEE80211_CAPINFO_ESS)
257 printf("ESS ");
258 if (w->capinfo & IEEE80211_CAPINFO_PRIVACY)
259 printf("WEP ");
260 printf("]\n");
261
262 switch (w->rate) {
263 case WI_APRATE_1:
264 rate = 1;
265 break;
266 case WI_APRATE_2:
267 rate = 2;
268 break;
269 case WI_APRATE_5:
270 rate = 5;
271 break;
272 case WI_APRATE_11:
273 rate = 11;
274 break;
275 case WI_APRATE_0:
276 default:
277 rate = 0;
278 break;
279 }
280 if (rate)
281 printf("\tDataRate [Mbps]:\t\t[ %d ]\n", rate);
282 }
283
284 set_if_flags(s, iface, flags);
285 close(s);
286 }
287 #endif
288
289 static int
290 wi_getval(char *iface, struct wi_req *wreq)
291 {
292 struct ifreq ifr;
293 int s, error;
294
295 error = 0;
296 memset(&ifr, 0, sizeof(ifr));
297
298 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
299 ifr.ifr_data = (caddr_t)wreq;
300
301 s = socket(AF_INET, SOCK_DGRAM, 0);
302
303 if (s == -1)
304 err(1, "socket");
305
306 if (ioctl(s, SIOCGWAVELAN, &ifr) == -1) {
307 warn("SIOCGWAVELAN(wreq %04x)", wreq->wi_type);
308 error = 1;
309 }
310
311 close(s);
312
313 return error;
314 }
315
316 static void
317 wi_setval(char *iface, struct wi_req *wreq)
318 {
319 struct ifreq ifr;
320 int s;
321
322 memset(&ifr, 0, sizeof(ifr));
323
324 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
325 ifr.ifr_data = (caddr_t)wreq;
326
327 s = socket(AF_INET, SOCK_DGRAM, 0);
328
329 if (s == -1)
330 err(1, "socket");
331
332 if (ioctl(s, SIOCSWAVELAN, &ifr) == -1)
333 err(1, "SIOCSWAVELAN");
334
335 close(s);
336 }
337
338 static void
339 wi_printstr(struct wi_req *wreq)
340 {
341 char *ptr;
342 int i;
343
344 if (wreq->wi_type == WI_RID_SERIALNO) {
345 ptr = (char *)&wreq->wi_val;
346 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
347 if (ptr[i] == '\0')
348 ptr[i] = ' ';
349 }
350 } else {
351 int len = le16toh(wreq->wi_val[0]);
352
353 ptr = (char *)&wreq->wi_val[1];
354 for (i = 0; i < len; i++) {
355 if (ptr[i] == '\0')
356 ptr[i] = ' ';
357 }
358 }
359
360 ptr[i] = '\0';
361 printf("[ %s ]", ptr);
362 }
363
364 static void
365 wi_setstr(char *iface, int code, char *str)
366 {
367 struct wi_req wreq;
368
369 memset(&wreq, 0, sizeof(wreq));
370
371 if (strlen(str) > 30)
372 errx(1, "string too long");
373
374 wreq.wi_type = code;
375 wreq.wi_len = 18;
376 wreq.wi_val[0] = htole16(strlen(str));
377 bcopy(str, (char *)&wreq.wi_val[1], strlen(str));
378
379 wi_setval(iface, &wreq);
380 }
381
382 static void
383 wi_setbytes(char *iface, int code, char *bytes, int len)
384 {
385 struct wi_req wreq;
386
387 memset(&wreq, 0, sizeof(wreq));
388
389 wreq.wi_type = code;
390 wreq.wi_len = (len / 2) + 1;
391 bcopy(bytes, (char *)&wreq.wi_val[0], len);
392
393 wi_setval(iface, &wreq);
394 }
395
396 static void
397 wi_setword(char *iface, int code, int word)
398 {
399 struct wi_req wreq;
400
401 memset(&wreq, 0, sizeof(wreq));
402
403 wreq.wi_type = code;
404 wreq.wi_len = 2;
405 wreq.wi_val[0] = htole16(word);
406
407 wi_setval(iface, &wreq);
408 }
409
410 static void
411 wi_sethex(char *iface, int code, char *str)
412 {
413 struct ether_addr *addr;
414
415 addr = ether_aton(str);
416 if (addr == NULL)
417 errx(1, "badly formatted address");
418
419 wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN);
420 }
421
422 static void
423 wi_printkeys(struct wi_req *wreq)
424 {
425 int i, j, bn;
426 struct wi_key *k;
427 struct wi_ltv_keys *keys;
428 char *ptr;
429
430 keys = (struct wi_ltv_keys *)wreq;
431
432 for (i = 0, bn = 0; i < 4; i++, bn = 0) {
433 k = &keys->wi_keys[i];
434 ptr = (char *)k->wi_keydat;
435 for (j = 0; j < le16toh(k->wi_keylen); j++) {
436 if (!isprint((unsigned char)ptr[j])) {
437 bn = 1;
438 break;
439 }
440 }
441
442 if (bn) {
443 printf("[ 0x");
444 for (j = 0; j < le16toh(k->wi_keylen); j++)
445 printf("%02x", ((unsigned char *)ptr)[j]);
446 printf(" ]");
447 } else {
448 ptr[j] = '\0';
449 printf("[ %s ]", ptr);
450 }
451 }
452 }
453
454 static void
455 wi_printvendor(struct wi_req *wreq)
456 {
457 /* id
458 * vendor
459 * firmware major
460 * minor
461 */
462 #define WI_RID_STA_IDENTITY_LUCENT 0x1
463 #define WI_RID_STA_IDENTITY_PRISMII 0x2
464 #define WI_RID_STA_IDENTITY_SAMSUNG 0x3
465 #define WI_RID_STA_IDENTITY_DLINK 0x6
466
467 const char *vendor = "Unknown";
468
469 if (wreq->wi_len < 4)
470 return;
471
472 switch (le16toh(wreq->wi_val[1])) {
473 case WI_RID_STA_IDENTITY_LUCENT:
474 vendor = "Lucent";
475 break;
476 case WI_RID_STA_IDENTITY_PRISMII:
477 vendor = "generic PRISM II";
478 break;
479 case WI_RID_STA_IDENTITY_SAMSUNG:
480 vendor = "Samsung";
481 break;
482 case WI_RID_STA_IDENTITY_DLINK:
483 vendor = "D-Link";
484 break;
485 }
486 printf("[ %s ID: %d version: %d.%d ]", vendor, le16toh(wreq->wi_val[0]),
487 le16toh(wreq->wi_val[2]), le16toh(wreq->wi_val[3]));
488 }
489
490 static void
491 wi_printwords(struct wi_req *wreq)
492 {
493 int i;
494
495 printf("[ ");
496 for (i = 0; i < wreq->wi_len - 1; i++)
497 printf("%d ", le16toh(wreq->wi_val[i]));
498 printf("]");
499 }
500
501 static void
502 wi_printbool(struct wi_req *wreq)
503 {
504 if (le16toh(wreq->wi_val[0]))
505 printf("[ On ]");
506 else
507 printf("[ Off ]");
508 }
509
510 static void
511 wi_printhex(struct wi_req *wreq)
512 {
513 int i;
514 unsigned char *c;
515
516 c = (unsigned char *)&wreq->wi_val;
517
518 printf("[ ");
519 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
520 printf("%02x", c[i]);
521 if (i < ((wreq->wi_len - 1) * 2) - 1)
522 printf(":");
523 }
524 printf(" ]");
525 }
526
527 static void
528 wi_printbits(struct wi_req *wreq)
529 {
530 int i;
531 int bits = le16toh(wreq->wi_val[0]);
532
533 printf("[");
534 for (i = 0; i < 16; i++) {
535 if (bits & 0x1)
536 printf(" %d", i + 1);
537 bits >>= 1;
538 }
539 printf(" ]");
540 }
541
542 static struct wi_table wi_table[] = {
543 { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t", 0, 0, 0 },
544 { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t",
545 's', "station name", 0, },
546 { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t", 0, 0, 0 },
547 { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t", 0, 0, 0 },
548 { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t", 0, 0, 0 },
549 { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t", 0, 0, 0 },
550 { WI_RID_CHANNEL_LIST, WI_BITS, "Channel list:\t\t\t\t", 0, 0, 0 },
551 { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t", 0, 0, 0 },
552 { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t", 0, 0, 0 },
553 { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t", 0, 0, 0 },
554 { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t", 0, 0, 0 },
555 { WI_RID_PORTTYPE, WI_WORDS, "Port type:\t\t\t\t", 0, 0, 0 },
556 { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t",
557 'm', "MAC address", 0, },
558 { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t", 0, 0, 0 },
559 { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t", 0, 0, 0 },
560 { WI_RID_CUR_BEACON_INT, WI_WORDS, "Beacon Interval (current) [msec]:\t", 0, 0, 0 },
561 { WI_RID_MAX_DATALEN, WI_WORDS, "Maximum data length:\t\t\t",
562 'd', "maximum data length", 0 },
563 { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t",
564 'r', "RTS threshold", 0 },
565 { WI_RID_FRAG_THRESH, WI_WORDS, "fragmentation threshold:\t\t",
566 'g', "fragmentation threshold", 0, },
567 { WI_RID_DBM_ADJUST, WI_WORDS, "RSSI -> dBm adjustment:\t\t\t", 0, 0, 0 },
568 { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t", 0, 0, 0 },
569 { WI_RID_MICROWAVE_OVEN, WI_WORDS, "Microwave oven robustness:\t\t",
570 'M', "microwave oven robustness enabled", 0 },
571 { WI_RID_ROAMING_MODE, WI_WORDS, "Roaming mode(1:firm,3:disable):\t\t",
572 'R', "roaming mode", 0 },
573 { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t",
574 'a', "system scale", 0 },
575 { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t", 0, 0, 0 },
576 { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time (msec):\t\t\t", 0, 0, 0 },
577 { WI_RID_STA_IDENTITY, WI_VENDOR, "Vendor info:\t\t\t\t", 0, 0, 0 },
578 { 0, WI_NONE, 0, 0, 0, 0 }
579 };
580
581 static struct wi_table wi_crypt_table[] = {
582 { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t", 0, 0, 0 },
583 { WI_RID_CNFAUTHMODE, WI_WORDS, "Authentication type \n(1=OpenSys, 2=Shared Key):\t\t",
584 'A', "authentication type", 0 },
585 { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t", 0, 0, 0 },
586 { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t", 0, 0, 0 },
587 { 0, WI_NONE, 0, 0, 0, 0 }
588 };
589
590 static struct wi_table *wi_tables[] = {
591 wi_table,
592 wi_crypt_table,
593 NULL
594 };
595
596 static struct wi_table *
597 wi_optlookup(struct wi_table *table, int opt)
598 {
599 struct wi_table *wt;
600
601 for (wt = table; wt->wi_type != 0; wt++)
602 if (wt->wi_opt == opt)
603 return wt;
604 return NULL;
605 }
606
607 static void
608 wi_checkwifi(char *iface)
609 {
610 struct ifreq ifr;
611 struct ieee80211_nwid nwid;
612 int s;
613
614 memset(&ifr, 0, sizeof(ifr));
615
616 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
617 ifr.ifr_data = (void *)&nwid;
618
619 s = socket(AF_INET, SOCK_DGRAM, 0);
620
621 if (s == -1)
622 err(1, "socket");
623
624 /* Choice of ioctl inspired by ifconfig/ieee80211.c */
625 if (ioctl(s, SIOCG80211NWID, &ifr) == -1)
626 err(1, "SIOCG80211NWID");
627
628 close(s);
629 }
630
631 static void
632 wi_dumpinfo(char *iface)
633 {
634 struct wi_req wreq;
635 int i, has_wep;
636 struct wi_table *w;
637
638 memset(&wreq, 0, sizeof(wreq));
639
640 wreq.wi_len = WI_MAX_DATALEN;
641 wreq.wi_type = WI_RID_WEP_AVAIL;
642
643 wi_getval(iface, &wreq);
644 has_wep = le16toh(wreq.wi_val[0]);
645
646 w = wi_table;
647
648 for (i = 0; w[i].wi_code != WI_NONE; i++) {
649 memset(&wreq, 0, sizeof(wreq));
650
651 wreq.wi_len = WI_MAX_DATALEN;
652 wreq.wi_type = w[i].wi_type;
653
654 printf("%s", w[i].wi_label);
655 if (wi_getval(iface, &wreq)) {
656 printf("[ Unknown ]\n");
657 continue;
658 }
659 switch (w[i].wi_code) {
660 case WI_STRING:
661 wi_printstr(&wreq);
662 break;
663 case WI_WORDS:
664 wi_printwords(&wreq);
665 break;
666 case WI_BOOL:
667 wi_printbool(&wreq);
668 break;
669 case WI_HEXBYTES:
670 wi_printhex(&wreq);
671 break;
672 case WI_BITS:
673 wi_printbits(&wreq);
674 break;
675 case WI_VENDOR:
676 wi_printvendor(&wreq);
677 break;
678 default:
679 break;
680 }
681 printf("\n");
682 }
683
684 if (has_wep) {
685 w = wi_crypt_table;
686 for (i = 0; w[i].wi_code != WI_NONE; i++) {
687 memset(&wreq, 0, sizeof(wreq));
688
689 wreq.wi_len = WI_MAX_DATALEN;
690 wreq.wi_type = w[i].wi_type;
691
692 wi_getval(iface, &wreq);
693 printf("%s", w[i].wi_label);
694 switch (w[i].wi_code) {
695 case WI_STRING:
696 wi_printstr(&wreq);
697 break;
698 case WI_WORDS:
699 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
700 wreq.wi_val[0] =
701 htole16(le16toh(wreq.wi_val[0]) + 1);
702 wi_printwords(&wreq);
703 break;
704 case WI_BOOL:
705 wi_printbool(&wreq);
706 break;
707 case WI_HEXBYTES:
708 wi_printhex(&wreq);
709 break;
710 case WI_KEYSTRUCT:
711 wi_printkeys(&wreq);
712 break;
713 default:
714 break;
715 }
716 printf("\n");
717 }
718 }
719 }
720
721 static void
722 wi_dumpstats(char *iface)
723 {
724 struct wi_req wreq;
725 struct wi_counters *c;
726
727 memset(&wreq, 0, sizeof(wreq));
728 wreq.wi_len = WI_MAX_DATALEN;
729 wreq.wi_type = WI_RID_IFACE_STATS;
730
731 wi_getval(iface, &wreq);
732
733 c = (struct wi_counters *)&wreq.wi_val;
734
735 /* XXX native byte order */
736 printf("Transmitted unicast frames:\t\t%d\n",
737 c->wi_tx_unicast_frames);
738 printf("Transmitted multicast frames:\t\t%d\n",
739 c->wi_tx_multicast_frames);
740 printf("Transmitted fragments:\t\t\t%d\n",
741 c->wi_tx_fragments);
742 printf("Transmitted unicast octets:\t\t%d\n",
743 c->wi_tx_unicast_octets);
744 printf("Transmitted multicast octets:\t\t%d\n",
745 c->wi_tx_multicast_octets);
746 printf("Single transmit retries:\t\t%d\n",
747 c->wi_tx_single_retries);
748 printf("Multiple transmit retries:\t\t%d\n",
749 c->wi_tx_multi_retries);
750 printf("Transmit retry limit exceeded:\t\t%d\n",
751 c->wi_tx_retry_limit);
752 printf("Transmit discards:\t\t\t%d\n",
753 c->wi_tx_discards);
754 printf("Transmit discards due to wrong SA:\t%d\n",
755 c->wi_tx_discards_wrong_sa);
756 printf("Received unicast frames:\t\t%d\n",
757 c->wi_rx_unicast_frames);
758 printf("Received multicast frames:\t\t%d\n",
759 c->wi_rx_multicast_frames);
760 printf("Received fragments:\t\t\t%d\n",
761 c->wi_rx_fragments);
762 printf("Received unicast octets:\t\t%d\n",
763 c->wi_rx_unicast_octets);
764 printf("Received multicast octets:\t\t%d\n",
765 c->wi_rx_multicast_octets);
766 printf("Receive FCS errors:\t\t\t%d\n",
767 c->wi_rx_fcs_errors);
768 printf("Receive discards due to no buffer:\t%d\n",
769 c->wi_rx_discards_nobuf);
770 printf("Can't decrypt WEP frame:\t\t%d\n",
771 c->wi_rx_WEP_cant_decrypt);
772 printf("Received message fragments:\t\t%d\n",
773 c->wi_rx_msg_in_msg_frags);
774 printf("Received message bad fragments:\t\t%d\n",
775 c->wi_rx_msg_in_bad_msg_frags);
776 }
777
778 static void
779 usage(void)
780 {
781
782 fprintf(stderr,
783 "usage: %s interface [-Dho] [-A 1|2] [-a access point density]\n"
784 " [-d max data length] [-g fragmentation threshold] [-M 0|1]\n"
785 " [-m MAC address] [-R 1|3] [-r RTS threshold] [-s station name]\n"
786 ,
787 getprogname());
788 exit(1);
789 }
790
791 int
792 main(int argc, char *argv[])
793 {
794 struct wi_table *wt, **table;
795 char *iface;
796 int ch, dumpinfo, dumpstats, apscan;
797
798 #define SET_OPERAND(opr, desc) do { \
799 if ((opr) == NULL) \
800 (opr) = optarg; \
801 else \
802 warnx("%s is already specified to %s", \
803 desc, (opr)); \
804 } while (0)
805
806 dumpinfo = 1;
807 dumpstats = 0;
808 apscan = 0;
809 iface = NULL;
810
811 if (argc > 1 && argv[1][0] != '-') {
812 iface = argv[1];
813 optind++;
814 }
815
816 /* LINTED 338 "option should be handled in the switch" */
817 while ((ch = getopt(argc, argv,
818 "a:d:g:hi:m:or:s:A:M:R:D")) != -1) {
819 if (ch != 'i')
820 dumpinfo = 0;
821 /*
822 * Lookup generic options and remember operand if found.
823 */
824 wt = NULL; /* XXXGCC -Wuninitialized */
825 for (table = wi_tables; *table != NULL; table++)
826 if ((wt = wi_optlookup(*table, ch)) != NULL) {
827 SET_OPERAND(wt->wi_optval, wt->wi_desc);
828 break;
829 }
830 if (wt == NULL)
831 /*
832 * Handle special options.
833 */
834 switch (ch) {
835 case 'o':
836 dumpstats = 1;
837 break;
838 case 'i':
839 SET_OPERAND(iface, "interface");
840 break;
841 case 'D':
842 apscan = 1;
843 break;
844 case 'h':
845 default:
846 usage();
847 break;
848 }
849 }
850
851 if (iface == NULL)
852 usage();
853
854 /* Check interface is wireless. Will not return on error */
855 wi_checkwifi(iface);
856
857 for (table = wi_tables; *table != NULL; table++)
858 for (wt = *table; wt->wi_code != WI_NONE; wt++)
859 if (wt->wi_optval != NULL) {
860 switch (wt->wi_code) {
861 case WI_BOOL:
862 case WI_WORDS:
863 wi_setword(iface, wt->wi_type,
864 atoi(wt->wi_optval));
865 break;
866 case WI_STRING:
867 wi_setstr(iface, wt->wi_type,
868 wt->wi_optval);
869 break;
870 case WI_HEXBYTES:
871 wi_sethex(iface, wt->wi_type,
872 wt->wi_optval);
873 break;
874 }
875 }
876
877 if (dumpstats)
878 wi_dumpstats(iface);
879 if (dumpinfo)
880 wi_dumpinfo(iface);
881
882 if (apscan)
883 #ifdef WI_RID_SCAN_APS
884 wi_apscan(iface);
885 #else
886 errx(1, "AP scan mode is not available.");
887 #endif
888
889 exit(0);
890 }
891