1/*	$NetBSD: wiconfig.c,v 1.42 2009/04/19 01:52:09 lukem 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.42 2009/04/19 01:52:09 lukem Exp $");
72#endif
73
74struct 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
99static void wi_apscan(char *);
100static int  get_if_flags(int, const char *);
101static int  set_if_flags(int, const char *, int);
102#endif
103static int  wi_getval(char *, struct wi_req *);
104static void wi_setval(char *, struct wi_req *);
105static void wi_printstr(struct wi_req *);
106static void wi_setstr(char *, int, char *);
107static void wi_setbytes(char *, int, char *, int);
108static void wi_setword(char *, int, int);
109static void wi_sethex(char *, int, char *);
110static void wi_printwords(struct wi_req *);
111static void wi_printbool(struct wi_req *);
112static void wi_printhex(struct wi_req *);
113static void wi_printbits(struct wi_req *);
114static void wi_checkwifi(char *);
115static void wi_dumpinfo(char *);
116static void wi_printkeys(struct wi_req *);
117static void wi_printvendor(struct wi_req *);
118static void wi_dumpstats(char *);
119__dead static void usage(void);
120static struct wi_table *wi_optlookup(struct wi_table *, int);
121
122#ifdef WI_RID_SCAN_APS
123static int
124get_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
137static int
138set_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
150static void
151wi_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.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
282static int
283wi_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
309static void
310wi_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
333static void
334wi_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
361static void
362wi_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
381static void
382wi_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
397static void
398wi_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
413static void
414wi_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
427static void
428wi_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
461static void
462wi_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
498static void
499wi_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
511static void
512wi_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
522static void
523wi_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
541static void
542wi_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
558static 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
597static 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
606static struct wi_table *wi_tables[] = {
607	wi_table,
608	wi_crypt_table,
609	NULL
610};
611
612static struct wi_table *
613wi_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
623static void
624wi_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
647static void
648wi_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
739static void
740wi_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
798static void
799usage(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
811int
812main(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