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