xref: /freebsd/sbin/ifconfig/ifieee80211.c (revision d056fa046c6a91b90cd98165face0e42a33a5173)
1 /*
2  * Copyright 2001 The Aerospace Corporation.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. The name of The Aerospace Corporation may not be used to endorse or
13  *    promote products derived from this software.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 /*-
31  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32  * All rights reserved.
33  *
34  * This code is derived from software contributed to The NetBSD Foundation
35  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36  * NASA Ames Research Center.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *	This product includes software developed by the NetBSD
49  *	Foundation, Inc. and its contributors.
50  * 4. Neither the name of The NetBSD Foundation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64  * POSSIBILITY OF SUCH DAMAGE.
65  */
66 
67 #include <sys/param.h>
68 #include <sys/ioctl.h>
69 #include <sys/socket.h>
70 #include <sys/sysctl.h>
71 #include <sys/time.h>
72 
73 #include <net/ethernet.h>
74 #include <net/if.h>
75 #include <net/if_dl.h>
76 #include <net/if_types.h>
77 #include <net/if_media.h>
78 #include <net/route.h>
79 
80 #include <net80211/ieee80211.h>
81 #include <net80211/ieee80211_crypto.h>
82 #include <net80211/ieee80211_ioctl.h>
83 
84 #include <ctype.h>
85 #include <err.h>
86 #include <errno.h>
87 #include <fcntl.h>
88 #include <inttypes.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <unistd.h>
93 #include <stdarg.h>
94 
95 #include "ifconfig.h"
96 
97 static void set80211(int s, int type, int val, int len, u_int8_t *data);
98 static const char *get_string(const char *val, const char *sep,
99     u_int8_t *buf, int *lenp);
100 static void print_string(const u_int8_t *buf, int len);
101 
102 static int
103 isanyarg(const char *arg)
104 {
105 	return (strcmp(arg, "-") == 0 ||
106 	    strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
107 }
108 
109 static void
110 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
111 {
112 	int		ssid;
113 	int		len;
114 	u_int8_t	data[IEEE80211_NWID_LEN];
115 
116 	ssid = 0;
117 	len = strlen(val);
118 	if (len > 2 && isdigit(val[0]) && val[1] == ':') {
119 		ssid = atoi(val)-1;
120 		val += 2;
121 	}
122 
123 	bzero(data, sizeof(data));
124 	len = sizeof(data);
125 	if (get_string(val, NULL, data, &len) == NULL)
126 		exit(1);
127 
128 	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
129 }
130 
131 static void
132 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
133 {
134 	int			len;
135 	u_int8_t		data[33];
136 
137 	bzero(data, sizeof(data));
138 	len = sizeof(data);
139 	get_string(val, NULL, data, &len);
140 
141 	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
142 }
143 
144 /*
145  * Convert IEEE channel number to MHz frequency.
146  */
147 static u_int
148 ieee80211_ieee2mhz(u_int chan)
149 {
150 	if (chan == 14)
151 		return 2484;
152 	if (chan < 14)			/* 0-13 */
153 		return 2407 + chan*5;
154 	if (chan < 27)			/* 15-26 */
155 		return 2512 + ((chan-15)*20);
156 	return 5000 + (chan*5);
157 }
158 
159 /*
160  * Convert MHz frequency to IEEE channel number.
161  */
162 static u_int
163 ieee80211_mhz2ieee(u_int freq)
164 {
165 	if (freq == 2484)
166 		return 14;
167 	if (freq < 2484)
168 		return (freq - 2407) / 5;
169 	if (freq < 5000)
170 		return 15 + ((freq - 2512) / 20);
171 	return (freq - 5000) / 5;
172 }
173 
174 static void
175 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
176 {
177 	if (!isanyarg(val)) {
178 		int v = atoi(val);
179 		if (v > 255)		/* treat as frequency */
180 			v = ieee80211_mhz2ieee(v);
181 		set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
182 	} else
183 		set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
184 }
185 
186 static void
187 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
188 {
189 	int	mode;
190 
191 	if (strcasecmp(val, "none") == 0) {
192 		mode = IEEE80211_AUTH_NONE;
193 	} else if (strcasecmp(val, "open") == 0) {
194 		mode = IEEE80211_AUTH_OPEN;
195 	} else if (strcasecmp(val, "shared") == 0) {
196 		mode = IEEE80211_AUTH_SHARED;
197 	} else if (strcasecmp(val, "8021x") == 0) {
198 		mode = IEEE80211_AUTH_8021X;
199 	} else if (strcasecmp(val, "wpa") == 0) {
200 		mode = IEEE80211_AUTH_WPA;
201 	} else {
202 		errx(1, "unknown authmode");
203 	}
204 
205 	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
206 }
207 
208 static void
209 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
210 {
211 	int	mode;
212 
213 	if (strcasecmp(val, "off") == 0) {
214 		mode = IEEE80211_POWERSAVE_OFF;
215 	} else if (strcasecmp(val, "on") == 0) {
216 		mode = IEEE80211_POWERSAVE_ON;
217 	} else if (strcasecmp(val, "cam") == 0) {
218 		mode = IEEE80211_POWERSAVE_CAM;
219 	} else if (strcasecmp(val, "psp") == 0) {
220 		mode = IEEE80211_POWERSAVE_PSP;
221 	} else if (strcasecmp(val, "psp-cam") == 0) {
222 		mode = IEEE80211_POWERSAVE_PSP_CAM;
223 	} else {
224 		errx(1, "unknown powersavemode");
225 	}
226 
227 	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
228 }
229 
230 static void
231 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
232 {
233 	if (d == 0)
234 		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
235 		    0, NULL);
236 	else
237 		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
238 		    0, NULL);
239 }
240 
241 static void
242 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
243 {
244 	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
245 }
246 
247 static void
248 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
249 {
250 	int	mode;
251 
252 	if (strcasecmp(val, "off") == 0) {
253 		mode = IEEE80211_WEP_OFF;
254 	} else if (strcasecmp(val, "on") == 0) {
255 		mode = IEEE80211_WEP_ON;
256 	} else if (strcasecmp(val, "mixed") == 0) {
257 		mode = IEEE80211_WEP_MIXED;
258 	} else {
259 		errx(1, "unknown wep mode");
260 	}
261 
262 	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
263 }
264 
265 static void
266 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
267 {
268 	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
269 }
270 
271 static int
272 isundefarg(const char *arg)
273 {
274 	return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
275 }
276 
277 static void
278 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
279 {
280 	if (isundefarg(val))
281 		set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
282 	else
283 		set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
284 }
285 
286 static void
287 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
288 {
289 	int		key = 0;
290 	int		len;
291 	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
292 
293 	if (isdigit(val[0]) && val[1] == ':') {
294 		key = atoi(val)-1;
295 		val += 2;
296 	}
297 
298 	bzero(data, sizeof(data));
299 	len = sizeof(data);
300 	get_string(val, NULL, data, &len);
301 
302 	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
303 }
304 
305 /*
306  * This function is purely a NetBSD compatability interface.  The NetBSD
307  * interface is too inflexible, but it's there so we'll support it since
308  * it's not all that hard.
309  */
310 static void
311 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
312 {
313 	int		txkey;
314 	int		i, len;
315 	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
316 
317 	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
318 
319 	if (isdigit(val[0]) && val[1] == ':') {
320 		txkey = val[0]-'0'-1;
321 		val += 2;
322 
323 		for (i = 0; i < 4; i++) {
324 			bzero(data, sizeof(data));
325 			len = sizeof(data);
326 			val = get_string(val, ",", data, &len);
327 			if (val == NULL)
328 				exit(1);
329 
330 			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
331 		}
332 	} else {
333 		bzero(data, sizeof(data));
334 		len = sizeof(data);
335 		get_string(val, NULL, data, &len);
336 		txkey = 0;
337 
338 		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
339 
340 		bzero(data, sizeof(data));
341 		for (i = 1; i < 4; i++)
342 			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
343 	}
344 
345 	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
346 }
347 
348 static void
349 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
350 {
351 	set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
352 		isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
353 }
354 
355 static void
356 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
357 {
358 	int	mode;
359 
360 	if (strcasecmp(val, "off") == 0) {
361 		mode = IEEE80211_PROTMODE_OFF;
362 	} else if (strcasecmp(val, "cts") == 0) {
363 		mode = IEEE80211_PROTMODE_CTS;
364 	} else if (strcasecmp(val, "rtscts") == 0) {
365 		mode = IEEE80211_PROTMODE_RTSCTS;
366 	} else {
367 		errx(1, "unknown protection mode");
368 	}
369 
370 	set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
371 }
372 
373 static void
374 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
375 {
376 	set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
377 }
378 
379 #define	IEEE80211_ROAMING_DEVICE	0
380 #define	IEEE80211_ROAMING_AUTO		1
381 #define	IEEE80211_ROAMING_MANUAL	2
382 
383 static void
384 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
385 {
386 	int mode;
387 
388 	if (strcasecmp(val, "device") == 0) {
389 		mode = IEEE80211_ROAMING_DEVICE;
390 	} else if (strcasecmp(val, "auto") == 0) {
391 		mode = IEEE80211_ROAMING_AUTO;
392 	} else if (strcasecmp(val, "manual") == 0) {
393 		mode = IEEE80211_ROAMING_MANUAL;
394 	} else {
395 		errx(1, "unknown roaming mode");
396 	}
397 	set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
398 }
399 
400 static void
401 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
402 {
403 	set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
404 }
405 
406 static void
407 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
408 {
409 	set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
410 }
411 
412 static void
413 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
414 {
415 	set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
416 }
417 
418 static void
419 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
420 {
421 	struct ieee80211req_chanlist chanlist;
422 #define	MAXCHAN	(sizeof(chanlist.ic_channels)*NBBY)
423 	char *temp, *cp, *tp;
424 
425 	temp = malloc(strlen(val) + 1);
426 	if (temp == NULL)
427 		errx(1, "malloc failed");
428 	strcpy(temp, val);
429 	memset(&chanlist, 0, sizeof(chanlist));
430 	cp = temp;
431 	for (;;) {
432 		int first, last, f;
433 
434 		tp = strchr(cp, ',');
435 		if (tp != NULL)
436 			*tp++ = '\0';
437 		switch (sscanf(cp, "%u-%u", &first, &last)) {
438 		case 1:
439 			if (first > MAXCHAN)
440 				errx(-1, "channel %u out of range, max %zu",
441 					first, MAXCHAN);
442 			setbit(chanlist.ic_channels, first);
443 			break;
444 		case 2:
445 			if (first > MAXCHAN)
446 				errx(-1, "channel %u out of range, max %zu",
447 					first, MAXCHAN);
448 			if (last > MAXCHAN)
449 				errx(-1, "channel %u out of range, max %zu",
450 					last, MAXCHAN);
451 			if (first > last)
452 				errx(-1, "void channel range, %u > %u",
453 					first, last);
454 			for (f = first; f <= last; f++)
455 				setbit(chanlist.ic_channels, f);
456 			break;
457 		}
458 		if (tp == NULL)
459 			break;
460 		while (isspace(*tp))
461 			tp++;
462 		if (!isdigit(*tp))
463 			break;
464 		cp = tp;
465 	}
466 	set80211(s, IEEE80211_IOC_CHANLIST, 0,
467 		sizeof(chanlist), (uint8_t *) &chanlist);
468 #undef MAXCHAN
469 }
470 
471 static void
472 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
473 {
474 
475 	if (!isanyarg(val)) {
476 		char *temp;
477 		struct sockaddr_dl sdl;
478 
479 		temp = malloc(strlen(val) + 2); /* ':' and '\0' */
480 		if (temp == NULL)
481 			errx(1, "malloc failed");
482 		temp[0] = ':';
483 		strcpy(temp + 1, val);
484 		sdl.sdl_len = sizeof(sdl);
485 		link_addr(temp, &sdl);
486 		free(temp);
487 		if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
488 			errx(1, "malformed link-level address");
489 		set80211(s, IEEE80211_IOC_BSSID, 0,
490 			IEEE80211_ADDR_LEN, LLADDR(&sdl));
491 	} else {
492 		uint8_t zerobssid[IEEE80211_ADDR_LEN];
493 		memset(zerobssid, 0, sizeof(zerobssid));
494 		set80211(s, IEEE80211_IOC_BSSID, 0,
495 			IEEE80211_ADDR_LEN, zerobssid);
496 	}
497 }
498 
499 static int
500 getac(const char *ac)
501 {
502 	if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
503 		return WME_AC_BE;
504 	if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
505 		return WME_AC_BK;
506 	if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
507 		return WME_AC_VI;
508 	if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
509 		return WME_AC_VO;
510 	errx(1, "unknown wme access class %s", ac);
511 }
512 
513 static
514 DECL_CMD_FUNC2(set80211cwmin, ac, val)
515 {
516 	set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
517 }
518 
519 static
520 DECL_CMD_FUNC2(set80211cwmax, ac, val)
521 {
522 	set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
523 }
524 
525 static
526 DECL_CMD_FUNC2(set80211aifs, ac, val)
527 {
528 	set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
529 }
530 
531 static
532 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
533 {
534 	set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
535 }
536 
537 static
538 DECL_CMD_FUNC(set80211acm, ac, d)
539 {
540 	set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
541 }
542 static
543 DECL_CMD_FUNC(set80211noacm, ac, d)
544 {
545 	set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
546 }
547 
548 static
549 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
550 {
551 	set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
552 }
553 static
554 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
555 {
556 	set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
557 }
558 
559 static
560 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
561 {
562 	set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
563 		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
564 }
565 
566 static
567 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
568 {
569 	set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
570 		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
571 }
572 
573 static
574 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
575 {
576 	set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
577 		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
578 }
579 
580 static
581 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
582 {
583 	set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
584 		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
585 }
586 
587 static
588 DECL_CMD_FUNC(set80211dtimperiod, val, d)
589 {
590 	set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
591 }
592 
593 static
594 DECL_CMD_FUNC(set80211bintval, val, d)
595 {
596 	set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
597 }
598 
599 static void
600 set80211macmac(int s, int op, const char *val)
601 {
602 	char *temp;
603 	struct sockaddr_dl sdl;
604 
605 	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
606 	if (temp == NULL)
607 		errx(1, "malloc failed");
608 	temp[0] = ':';
609 	strcpy(temp + 1, val);
610 	sdl.sdl_len = sizeof(sdl);
611 	link_addr(temp, &sdl);
612 	free(temp);
613 	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
614 		errx(1, "malformed link-level address");
615 	set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
616 }
617 
618 static
619 DECL_CMD_FUNC(set80211addmac, val, d)
620 {
621 	set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
622 }
623 
624 static
625 DECL_CMD_FUNC(set80211delmac, val, d)
626 {
627 	set80211macmac(s, IEEE80211_IOC_DELMAC, val);
628 }
629 
630 static
631 DECL_CMD_FUNC(set80211kickmac, val, d)
632 {
633 	char *temp;
634 	struct sockaddr_dl sdl;
635 	struct ieee80211req_mlme mlme;
636 
637 	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
638 	if (temp == NULL)
639 		errx(1, "malloc failed");
640 	temp[0] = ':';
641 	strcpy(temp + 1, val);
642 	sdl.sdl_len = sizeof(sdl);
643 	link_addr(temp, &sdl);
644 	free(temp);
645 	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
646 		errx(1, "malformed link-level address");
647 	memset(&mlme, 0, sizeof(mlme));
648 	mlme.im_op = IEEE80211_MLME_DEAUTH;
649 	mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
650 	memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
651 	set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
652 }
653 
654 static
655 DECL_CMD_FUNC(set80211maccmd, val, d)
656 {
657 	set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
658 }
659 
660 static void
661 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
662 {
663 	set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
664 }
665 
666 static void
667 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
668 {
669 	set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
670 }
671 
672 static
673 DECL_CMD_FUNC(set80211mcastrate, val, d)
674 {
675 	set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
676 }
677 
678 static
679 DECL_CMD_FUNC(set80211fragthreshold, val, d)
680 {
681 	set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
682 		isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
683 }
684 
685 static int
686 getmaxrate(uint8_t rates[15], uint8_t nrates)
687 {
688 	int i, maxrate = -1;
689 
690 	for (i = 0; i < nrates; i++) {
691 		int rate = rates[i] & IEEE80211_RATE_VAL;
692 		if (rate > maxrate)
693 			maxrate = rate;
694 	}
695 	return maxrate / 2;
696 }
697 
698 static const char *
699 getcaps(int capinfo)
700 {
701 	static char capstring[32];
702 	char *cp = capstring;
703 
704 	if (capinfo & IEEE80211_CAPINFO_ESS)
705 		*cp++ = 'E';
706 	if (capinfo & IEEE80211_CAPINFO_IBSS)
707 		*cp++ = 'I';
708 	if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
709 		*cp++ = 'c';
710 	if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
711 		*cp++ = 'C';
712 	if (capinfo & IEEE80211_CAPINFO_PRIVACY)
713 		*cp++ = 'P';
714 	if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
715 		*cp++ = 'S';
716 	if (capinfo & IEEE80211_CAPINFO_PBCC)
717 		*cp++ = 'B';
718 	if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
719 		*cp++ = 'A';
720 	if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
721 		*cp++ = 's';
722 	if (capinfo & IEEE80211_CAPINFO_RSN)
723 		*cp++ = 'R';
724 	if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
725 		*cp++ = 'D';
726 	*cp = '\0';
727 	return capstring;
728 }
729 
730 static const char *
731 getflags(int flags)
732 {
733 /* XXX need these publicly defined or similar */
734 #define	IEEE80211_NODE_AUTH	0x0001		/* authorized for data */
735 #define	IEEE80211_NODE_QOS	0x0002		/* QoS enabled */
736 #define	IEEE80211_NODE_ERP	0x0004		/* ERP enabled */
737 #define	IEEE80211_NODE_PWR_MGT	0x0010		/* power save mode enabled */
738 	static char flagstring[32];
739 	char *cp = flagstring;
740 
741 	if (flags & IEEE80211_NODE_AUTH)
742 		*cp++ = 'A';
743 	if (flags & IEEE80211_NODE_QOS)
744 		*cp++ = 'Q';
745 	if (flags & IEEE80211_NODE_ERP)
746 		*cp++ = 'E';
747 	if (flags & IEEE80211_NODE_PWR_MGT)
748 		*cp++ = 'P';
749 	*cp = '\0';
750 	return flagstring;
751 #undef IEEE80211_NODE_AUTH
752 #undef IEEE80211_NODE_QOS
753 #undef IEEE80211_NODE_ERP
754 #undef IEEE80211_NODE_PWR_MGT
755 }
756 
757 static void
758 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
759 {
760 	printf("%s", tag);
761 	if (verbose) {
762 		maxlen -= strlen(tag)+2;
763 		if (2*ielen > maxlen)
764 			maxlen--;
765 		printf("<");
766 		for (; ielen > 0; ie++, ielen--) {
767 			if (maxlen-- <= 0)
768 				break;
769 			printf("%02x", *ie);
770 		}
771 		if (ielen != 0)
772 			printf("-");
773 		printf(">");
774 	}
775 }
776 
777 /*
778  * Copy the ssid string contents into buf, truncating to fit.  If the
779  * ssid is entirely printable then just copy intact.  Otherwise convert
780  * to hexadecimal.  If the result is truncated then replace the last
781  * three characters with "...".
782  */
783 static int
784 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
785 {
786 	const u_int8_t *p;
787 	size_t maxlen;
788 	int i;
789 
790 	if (essid_len > bufsize)
791 		maxlen = bufsize;
792 	else
793 		maxlen = essid_len;
794 	/* determine printable or not */
795 	for (i = 0, p = essid; i < maxlen; i++, p++) {
796 		if (*p < ' ' || *p > 0x7e)
797 			break;
798 	}
799 	if (i != maxlen) {		/* not printable, print as hex */
800 		if (bufsize < 3)
801 			return 0;
802 		strlcpy(buf, "0x", bufsize);
803 		bufsize -= 2;
804 		p = essid;
805 		for (i = 0; i < maxlen && bufsize >= 2; i++) {
806 			sprintf(&buf[2+2*i], "%02x", p[i]);
807 			bufsize -= 2;
808 		}
809 		if (i != essid_len)
810 			memcpy(&buf[2+2*i-3], "...", 3);
811 	} else {			/* printable, truncate as needed */
812 		memcpy(buf, essid, maxlen);
813 		if (maxlen != essid_len)
814 			memcpy(&buf[maxlen-3], "...", 3);
815 	}
816 	return maxlen;
817 }
818 
819 /* unaligned little endian access */
820 #define LE_READ_4(p)					\
821 	((u_int32_t)					\
822 	 ((((const u_int8_t *)(p))[0]      ) |		\
823 	  (((const u_int8_t *)(p))[1] <<  8) |		\
824 	  (((const u_int8_t *)(p))[2] << 16) |		\
825 	  (((const u_int8_t *)(p))[3] << 24)))
826 
827 static int __inline
828 iswpaoui(const u_int8_t *frm)
829 {
830 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
831 }
832 
833 static int __inline
834 iswmeoui(const u_int8_t *frm)
835 {
836 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
837 }
838 
839 static int __inline
840 isatherosoui(const u_int8_t *frm)
841 {
842 	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
843 }
844 
845 static void
846 printies(const u_int8_t *vp, int ielen, int maxcols)
847 {
848 	while (ielen > 0) {
849 		switch (vp[0]) {
850 		case IEEE80211_ELEMID_VENDOR:
851 			if (iswpaoui(vp))
852 				printie(" WPA", vp, 2+vp[1], maxcols);
853 			else if (iswmeoui(vp))
854 				printie(" WME", vp, 2+vp[1], maxcols);
855 			else if (isatherosoui(vp))
856 				printie(" ATH", vp, 2+vp[1], maxcols);
857 			else
858 				printie(" VEN", vp, 2+vp[1], maxcols);
859 			break;
860 		case IEEE80211_ELEMID_RSN:
861 			printie(" RSN", vp, 2+vp[1], maxcols);
862 			break;
863 		default:
864 			printie(" ???", vp, 2+vp[1], maxcols);
865 			break;
866 		}
867 		ielen -= 2+vp[1];
868 		vp += 2+vp[1];
869 	}
870 }
871 
872 static void
873 list_scan(int s)
874 {
875 	uint8_t buf[24*1024];
876 	struct ieee80211req ireq;
877 	char ssid[IEEE80211_NWID_LEN+1];
878 	uint8_t *cp;
879 	int len, ssidmax;
880 
881 	(void) memset(&ireq, 0, sizeof(ireq));
882 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
883 	ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
884 	ireq.i_data = buf;
885 	ireq.i_len = sizeof(buf);
886 	if (ioctl(s, SIOCG80211, &ireq) < 0)
887 		errx(1, "unable to get scan results");
888 	len = ireq.i_len;
889 	if (len < sizeof(struct ieee80211req_scan_result))
890 		return;
891 
892 	ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
893 	printf("%-*.*s  %-17.17s  %4s %4s  %-5s %3s %4s\n"
894 		, ssidmax, ssidmax, "SSID"
895 		, "BSSID"
896 		, "CHAN"
897 		, "RATE"
898 		, "S:N"
899 		, "INT"
900 		, "CAPS"
901 	);
902 	cp = buf;
903 	do {
904 		struct ieee80211req_scan_result *sr;
905 		uint8_t *vp;
906 
907 		sr = (struct ieee80211req_scan_result *) cp;
908 		vp = (u_int8_t *)(sr+1);
909 		printf("%-*.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s"
910 			, ssidmax
911 			  , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
912 			  , ssid
913 			, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
914 			, ieee80211_mhz2ieee(sr->isr_freq)
915 			, getmaxrate(sr->isr_rates, sr->isr_nrates)
916 			, sr->isr_rssi, sr->isr_noise
917 			, sr->isr_intval
918 			, getcaps(sr->isr_capinfo)
919 		);
920 		printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
921 		printf("\n");
922 		cp += sr->isr_len, len -= sr->isr_len;
923 	} while (len >= sizeof(struct ieee80211req_scan_result));
924 }
925 
926 #include <net80211/ieee80211_freebsd.h>
927 
928 static void
929 scan_and_wait(int s)
930 {
931 	struct ieee80211req ireq;
932 	int sroute;
933 
934 	sroute = socket(PF_ROUTE, SOCK_RAW, 0);
935 	if (sroute < 0) {
936 		perror("socket(PF_ROUTE,SOCK_RAW)");
937 		return;
938 	}
939 	(void) memset(&ireq, 0, sizeof(ireq));
940 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
941 	ireq.i_type = IEEE80211_IOC_SCAN_REQ;
942 	/* NB: only root can trigger a scan so ignore errors */
943 	if (ioctl(s, SIOCS80211, &ireq) >= 0) {
944 		char buf[2048];
945 		struct if_announcemsghdr *ifan;
946 		struct rt_msghdr *rtm;
947 
948 		do {
949 			if (read(sroute, buf, sizeof(buf)) < 0) {
950 				perror("read(PF_ROUTE)");
951 				break;
952 			}
953 			rtm = (struct rt_msghdr *) buf;
954 			if (rtm->rtm_version != RTM_VERSION)
955 				break;
956 			ifan = (struct if_announcemsghdr *) rtm;
957 		} while (rtm->rtm_type != RTM_IEEE80211 ||
958 		    ifan->ifan_what != RTM_IEEE80211_SCAN);
959 	}
960 	close(sroute);
961 }
962 
963 static
964 DECL_CMD_FUNC(set80211scan, val, d)
965 {
966 	scan_and_wait(s);
967 	list_scan(s);
968 }
969 
970 static void
971 list_stations(int s)
972 {
973 	uint8_t buf[24*1024];
974 	struct ieee80211req ireq;
975 	uint8_t *cp;
976 	int len;
977 
978 	(void) memset(&ireq, 0, sizeof(ireq));
979 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
980 	ireq.i_type = IEEE80211_IOC_STA_INFO;
981 	ireq.i_data = buf;
982 	ireq.i_len = sizeof(buf);
983 	if (ioctl(s, SIOCG80211, &ireq) < 0)
984 		errx(1, "unable to get station information");
985 	len = ireq.i_len;
986 	if (len < sizeof(struct ieee80211req_sta_info))
987 		return;
988 
989 	printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
990 		, "ADDR"
991 		, "AID"
992 		, "CHAN"
993 		, "RATE"
994 		, "RSSI"
995 		, "IDLE"
996 		, "TXSEQ"
997 		, "RXSEQ"
998 		, "CAPS"
999 		, "FLAG"
1000 	);
1001 	cp = buf;
1002 	do {
1003 		struct ieee80211req_sta_info *si;
1004 		uint8_t *vp;
1005 
1006 		si = (struct ieee80211req_sta_info *) cp;
1007 		vp = (u_int8_t *)(si+1);
1008 		printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s"
1009 			, ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1010 			, IEEE80211_AID(si->isi_associd)
1011 			, ieee80211_mhz2ieee(si->isi_freq)
1012 			, (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1013 			, si->isi_rssi
1014 			, si->isi_inact
1015 			, si->isi_txseqs[0]
1016 			, si->isi_rxseqs[0]
1017 			, getcaps(si->isi_capinfo)
1018 			, getflags(si->isi_state)
1019 		);
1020 		printies(vp, si->isi_ie_len, 24);
1021 		printf("\n");
1022 		cp += si->isi_len, len -= si->isi_len;
1023 	} while (len >= sizeof(struct ieee80211req_sta_info));
1024 }
1025 
1026 static void
1027 print_chaninfo(const struct ieee80211_channel *c)
1028 {
1029 #define	IEEE80211_IS_CHAN_PASSIVE(_c) \
1030 	(((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1031 	char buf[14];
1032 
1033 	buf[0] = '\0';
1034 	if (IEEE80211_IS_CHAN_FHSS(c))
1035 		strlcat(buf, " FHSS", sizeof(buf));
1036 	if (IEEE80211_IS_CHAN_A(c))
1037 		strlcat(buf, " 11a", sizeof(buf));
1038 	/* XXX 11g schizophrenia */
1039 	if (IEEE80211_IS_CHAN_G(c) ||
1040 	    IEEE80211_IS_CHAN_PUREG(c))
1041 		strlcat(buf, " 11g", sizeof(buf));
1042 	else if (IEEE80211_IS_CHAN_B(c))
1043 		strlcat(buf, " 11b", sizeof(buf));
1044 	if (IEEE80211_IS_CHAN_T(c))
1045 		strlcat(buf, " Turbo", sizeof(buf));
1046 	printf("Channel %3u : %u%c Mhz%-14.14s",
1047 		ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1048 		IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1049 #undef IEEE80211_IS_CHAN_PASSIVE
1050 }
1051 
1052 static void
1053 list_channels(int s, int allchans)
1054 {
1055 	struct ieee80211req ireq;
1056 	struct ieee80211req_chaninfo chans;
1057 	struct ieee80211req_chaninfo achans;
1058 	const struct ieee80211_channel *c;
1059 	int i, half;
1060 
1061 	(void) memset(&ireq, 0, sizeof(ireq));
1062 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1063 	ireq.i_type = IEEE80211_IOC_CHANINFO;
1064 	ireq.i_data = &chans;
1065 	ireq.i_len = sizeof(chans);
1066 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1067 		errx(1, "unable to get channel information");
1068 	if (!allchans) {
1069 		struct ieee80211req_chanlist active;
1070 
1071 		ireq.i_type = IEEE80211_IOC_CHANLIST;
1072 		ireq.i_data = &active;
1073 		ireq.i_len = sizeof(active);
1074 		if (ioctl(s, SIOCG80211, &ireq) < 0)
1075 			errx(1, "unable to get active channel list");
1076 		memset(&achans, 0, sizeof(achans));
1077 		for (i = 0; i < chans.ic_nchans; i++) {
1078 			c = &chans.ic_chans[i];
1079 			if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1080 				achans.ic_chans[achans.ic_nchans++] = *c;
1081 		}
1082 	} else
1083 		achans = chans;
1084 	half = achans.ic_nchans / 2;
1085 	if (achans.ic_nchans % 2)
1086 		half++;
1087 	for (i = 0; i < achans.ic_nchans / 2; i++) {
1088 		print_chaninfo(&achans.ic_chans[i]);
1089 		print_chaninfo(&achans.ic_chans[half+i]);
1090 		printf("\n");
1091 	}
1092 	if (achans.ic_nchans % 2) {
1093 		print_chaninfo(&achans.ic_chans[i]);
1094 		printf("\n");
1095 	}
1096 }
1097 
1098 static void
1099 list_keys(int s)
1100 {
1101 }
1102 
1103 #define	IEEE80211_C_BITS \
1104 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1105 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1106 "\31WPA2\32BURST\33WME"
1107 
1108 static void
1109 list_capabilities(int s)
1110 {
1111 	struct ieee80211req ireq;
1112 	u_int32_t caps;
1113 
1114 	(void) memset(&ireq, 0, sizeof(ireq));
1115 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1116 	ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1117 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1118 		errx(1, "unable to get driver capabilities");
1119 	caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1120 	printb(name, caps, IEEE80211_C_BITS);
1121 	putchar('\n');
1122 }
1123 
1124 static void
1125 list_wme(int s)
1126 {
1127 	static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1128 	struct ieee80211req ireq;
1129 	int ac;
1130 
1131 	(void) memset(&ireq, 0, sizeof(ireq));
1132 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1133 	ireq.i_len = 0;
1134 	for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1135 again:
1136 		if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1137 			printf("\t%s", "     ");
1138 		else
1139 			printf("\t%s", acnames[ac]);
1140 
1141 		ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1142 
1143 		/* show WME BSS parameters */
1144 		ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1145 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1146 			printf(" cwmin %2u", ireq.i_val);
1147 		ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1148 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1149 			printf(" cwmax %2u", ireq.i_val);
1150 		ireq.i_type = IEEE80211_IOC_WME_AIFS;
1151 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1152 			printf(" aifs %2u", ireq.i_val);
1153 		ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1154 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1155 			printf(" txopLimit %3u", ireq.i_val);
1156 		ireq.i_type = IEEE80211_IOC_WME_ACM;
1157 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1158 			if (ireq.i_val)
1159 				printf(" acm");
1160 			else if (verbose)
1161 				printf(" -acm");
1162 		}
1163 		/* !BSS only */
1164 		if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1165 			ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1166 			if (ioctl(s, SIOCG80211, &ireq) != -1) {
1167 				if (!ireq.i_val)
1168 					printf(" -ack");
1169 				else if (verbose)
1170 					printf(" ack");
1171 			}
1172 		}
1173 		printf("\n");
1174 		if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1175 			ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1176 			goto again;
1177 		} else
1178 			ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1179 	}
1180 }
1181 
1182 static void
1183 list_mac(int s)
1184 {
1185 	struct ieee80211req ireq;
1186 	struct ieee80211req_maclist *acllist;
1187 	int i, nacls, policy;
1188 	char c;
1189 
1190 	(void) memset(&ireq, 0, sizeof(ireq));
1191 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1192 	ireq.i_type = IEEE80211_IOC_MACCMD;
1193 	ireq.i_val = IEEE80211_MACCMD_POLICY;
1194 	if (ioctl(s, SIOCG80211, &ireq) < 0) {
1195 		if (errno == EINVAL) {
1196 			printf("No acl policy loaded\n");
1197 			return;
1198 		}
1199 		err(1, "unable to get mac policy");
1200 	}
1201 	policy = ireq.i_val;
1202 
1203 	ireq.i_val = IEEE80211_MACCMD_LIST;
1204 	ireq.i_len = 0;
1205 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1206 		err(1, "unable to get mac acl list size");
1207 	if (ireq.i_len == 0)		/* NB: no acls */
1208 		return;
1209 
1210 	ireq.i_data = malloc(ireq.i_len);
1211 	if (ireq.i_data == NULL)
1212 		err(1, "out of memory for acl list");
1213 
1214 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1215 		err(1, "unable to get mac acl list");
1216 	if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1217 		if (verbose)
1218 			printf("policy: open\n");
1219 		c = '*';
1220 	} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1221 		if (verbose)
1222 			printf("policy: allow\n");
1223 		c = '+';
1224 	} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1225 		if (verbose)
1226 			printf("policy: deny\n");
1227 		c = '-';
1228 	} else {
1229 		printf("policy: unknown (%u)\n", policy);
1230 		c = '?';
1231 	}
1232 	nacls = ireq.i_len / sizeof(*acllist);
1233 	acllist = (struct ieee80211req_maclist *) ireq.i_data;
1234 	for (i = 0; i < nacls; i++)
1235 		printf("%c%s\n", c, ether_ntoa(
1236 			(const struct ether_addr *) acllist[i].ml_macaddr));
1237 }
1238 
1239 static
1240 DECL_CMD_FUNC(set80211list, arg, d)
1241 {
1242 #define	iseq(a,b)	(strncasecmp(a,b,sizeof(b)-1) == 0)
1243 
1244 	if (iseq(arg, "sta"))
1245 		list_stations(s);
1246 	else if (iseq(arg, "scan") || iseq(arg, "ap"))
1247 		list_scan(s);
1248 	else if (iseq(arg, "chan") || iseq(arg, "freq"))
1249 		list_channels(s, 1);
1250 	else if (iseq(arg, "active"))
1251 		list_channels(s, 0);
1252 	else if (iseq(arg, "keys"))
1253 		list_keys(s);
1254 	else if (iseq(arg, "caps"))
1255 		list_capabilities(s);
1256 	else if (iseq(arg, "wme"))
1257 		list_wme(s);
1258 	else if (iseq(arg, "mac"))
1259 		list_mac(s);
1260 	else
1261 		errx(1, "Don't know how to list %s for %s", arg, name);
1262 #undef iseq
1263 }
1264 
1265 static enum ieee80211_opmode
1266 get80211opmode(int s)
1267 {
1268 	struct ifmediareq ifmr;
1269 
1270 	(void) memset(&ifmr, 0, sizeof(ifmr));
1271 	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1272 
1273 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1274 		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1275 			return IEEE80211_M_IBSS;	/* XXX ahdemo */
1276 		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1277 			return IEEE80211_M_HOSTAP;
1278 		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1279 			return IEEE80211_M_MONITOR;
1280 	}
1281 	return IEEE80211_M_STA;
1282 }
1283 
1284 static const struct ieee80211_channel *
1285 getchaninfo(int s, int chan)
1286 {
1287 	struct ieee80211req ireq;
1288 	static struct ieee80211req_chaninfo chans;
1289 	static struct ieee80211_channel undef;
1290 	const struct ieee80211_channel *c;
1291 	int i, freq;
1292 
1293 	(void) memset(&ireq, 0, sizeof(ireq));
1294 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1295 	ireq.i_type = IEEE80211_IOC_CHANINFO;
1296 	ireq.i_data = &chans;
1297 	ireq.i_len = sizeof(chans);
1298 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1299 		errx(1, "unable to get channel information");
1300 	freq = ieee80211_ieee2mhz(chan);
1301 	for (i = 0; i < chans.ic_nchans; i++) {
1302 		c = &chans.ic_chans[i];
1303 		if (c->ic_freq == freq)
1304 			return c;
1305 	}
1306 	return &undef;
1307 }
1308 
1309 #if 0
1310 static void
1311 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1312 {
1313 	switch (ireq->i_val) {
1314 	case IEEE80211_CIPHER_WEP:
1315 		ireq->i_type = keylenop;
1316 		if (ioctl(s, SIOCG80211, ireq) != -1)
1317 			printf("WEP-%s",
1318 			    ireq->i_len <= 5 ? "40" :
1319 			    ireq->i_len <= 13 ? "104" : "128");
1320 		else
1321 			printf("WEP");
1322 		break;
1323 	case IEEE80211_CIPHER_TKIP:
1324 		printf("TKIP");
1325 		break;
1326 	case IEEE80211_CIPHER_AES_OCB:
1327 		printf("AES-OCB");
1328 		break;
1329 	case IEEE80211_CIPHER_AES_CCM:
1330 		printf("AES-CCM");
1331 		break;
1332 	case IEEE80211_CIPHER_CKIP:
1333 		printf("CKIP");
1334 		break;
1335 	case IEEE80211_CIPHER_NONE:
1336 		printf("NONE");
1337 		break;
1338 	default:
1339 		printf("UNKNOWN (0x%x)", ireq->i_val);
1340 		break;
1341 	}
1342 }
1343 #endif
1344 
1345 #define	MAXCOL	78
1346 static	int col;
1347 static	char spacer;
1348 
1349 static void
1350 LINE_BREAK(void)
1351 {
1352 	if (spacer != '\t') {
1353 		printf("\n");
1354 		spacer = '\t';
1355 	}
1356 	col = 8;	/* 8-col tab */
1357 }
1358 
1359 static void
1360 LINE_CHECK(const char *fmt, ...)
1361 {
1362 	char buf[80];
1363 	va_list ap;
1364 	int n;
1365 
1366 	va_start(ap, fmt);
1367 	n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1368 	va_end(ap);
1369 	col += 1+n;
1370 	if (col > MAXCOL) {
1371 		LINE_BREAK();
1372 		col += n;
1373 	}
1374 	buf[0] = spacer;
1375 	printf("%s", buf);
1376 	spacer = ' ';
1377 }
1378 
1379 static void
1380 printkey(const struct ieee80211req_key *ik)
1381 {
1382 	static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1383 	int keylen = ik->ik_keylen;
1384 	int printcontents;
1385 
1386 	printcontents = printkeys &&
1387 		(memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1388 	if (printcontents)
1389 		LINE_BREAK();
1390 	switch (ik->ik_type) {
1391 	case IEEE80211_CIPHER_WEP:
1392 		/* compatibility */
1393 		LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1394 		    keylen <= 5 ? "40-bit" :
1395 		    keylen <= 13 ? "104-bit" : "128-bit");
1396 		break;
1397 	case IEEE80211_CIPHER_TKIP:
1398 		if (keylen > 128/8)
1399 			keylen -= 128/8;	/* ignore MIC for now */
1400 		LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1401 		break;
1402 	case IEEE80211_CIPHER_AES_OCB:
1403 		LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1404 		break;
1405 	case IEEE80211_CIPHER_AES_CCM:
1406 		LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1407 		break;
1408 	case IEEE80211_CIPHER_CKIP:
1409 		LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1410 		break;
1411 	case IEEE80211_CIPHER_NONE:
1412 		LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1413 		break;
1414 	default:
1415 		LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1416 			ik->ik_type, ik->ik_keyix+1, 8*keylen);
1417 		break;
1418 	}
1419 	if (printcontents) {
1420 		int i;
1421 
1422 		printf(" <");
1423 		for (i = 0; i < keylen; i++)
1424 			printf("%02x", ik->ik_keydata[i]);
1425 		printf(">");
1426 		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1427 		    (ik->ik_keyrsc != 0 || verbose))
1428 			printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1429 		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1430 		    (ik->ik_keytsc != 0 || verbose))
1431 			printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1432 		if (ik->ik_flags != 0 && verbose) {
1433 			const char *sep = " ";
1434 
1435 			if (ik->ik_flags & IEEE80211_KEY_XMIT)
1436 				printf("%stx", sep), sep = "+";
1437 			if (ik->ik_flags & IEEE80211_KEY_RECV)
1438 				printf("%srx", sep), sep = "+";
1439 			if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1440 				printf("%sdef", sep), sep = "+";
1441 		}
1442 		LINE_BREAK();
1443 	}
1444 }
1445 
1446 static void
1447 ieee80211_status(int s)
1448 {
1449 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1450 	enum ieee80211_opmode opmode = get80211opmode(s);
1451 	int i, num, wpa, wme;
1452 	struct ieee80211req ireq;
1453 	u_int8_t data[32];
1454 	const struct ieee80211_channel *c;
1455 
1456 	(void) memset(&ireq, 0, sizeof(ireq));
1457 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1458 	ireq.i_data = &data;
1459 
1460 	wpa = 0;		/* unknown/not set */
1461 
1462 	ireq.i_type = IEEE80211_IOC_SSID;
1463 	ireq.i_val = -1;
1464 	if (ioctl(s, SIOCG80211, &ireq) < 0) {
1465 		/* If we can't get the SSID, this isn't an 802.11 device. */
1466 		return;
1467 	}
1468 	num = 0;
1469 	ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1470 	if (ioctl(s, SIOCG80211, &ireq) >= 0)
1471 		num = ireq.i_val;
1472 	printf("\tssid ");
1473 	if (num > 1) {
1474 		ireq.i_type = IEEE80211_IOC_SSID;
1475 		for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1476 			if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1477 				printf(" %d:", ireq.i_val + 1);
1478 				print_string(data, ireq.i_len);
1479 			}
1480 		}
1481 	} else
1482 		print_string(data, ireq.i_len);
1483 
1484 	ireq.i_type = IEEE80211_IOC_CHANNEL;
1485 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1486 		goto end;
1487 	c = getchaninfo(s, ireq.i_val);
1488 	if (ireq.i_val != -1) {
1489 		printf(" channel %d", ireq.i_val);
1490 		if (verbose)
1491 			printf(" (%u)", c->ic_freq);
1492 	} else if (verbose)
1493 		printf(" channel UNDEF");
1494 
1495 	ireq.i_type = IEEE80211_IOC_BSSID;
1496 	ireq.i_len = IEEE80211_ADDR_LEN;
1497 	if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1498 	    (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1499 		printf(" bssid %s", ether_ntoa(ireq.i_data));
1500 
1501 	ireq.i_type = IEEE80211_IOC_STATIONNAME;
1502 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1503 		printf("\n\tstationname ");
1504 		print_string(data, ireq.i_len);
1505 	}
1506 
1507 	spacer = ' ';		/* force first break */
1508 	LINE_BREAK();
1509 
1510 	ireq.i_type = IEEE80211_IOC_AUTHMODE;
1511 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1512 		switch (ireq.i_val) {
1513 			case IEEE80211_AUTH_NONE:
1514 				LINE_CHECK("authmode NONE");
1515 				break;
1516 			case IEEE80211_AUTH_OPEN:
1517 				LINE_CHECK("authmode OPEN");
1518 				break;
1519 			case IEEE80211_AUTH_SHARED:
1520 				LINE_CHECK("authmode SHARED");
1521 				break;
1522 			case IEEE80211_AUTH_8021X:
1523 				LINE_CHECK("authmode 802.1x");
1524 				break;
1525 			case IEEE80211_AUTH_WPA:
1526 				ireq.i_type = IEEE80211_IOC_WPA;
1527 				if (ioctl(s, SIOCG80211, &ireq) != -1)
1528 					wpa = ireq.i_val;
1529 				if (!wpa)
1530 					wpa = 1;	/* default to WPA1 */
1531 				switch (wpa) {
1532 				case 2:
1533 					LINE_CHECK("authmode WPA2/802.11i");
1534 					break;
1535 				case 3:
1536 					LINE_CHECK("authmode WPA1+WPA2/802.11i");
1537 					break;
1538 				default:
1539 					LINE_CHECK("authmode WPA");
1540 					break;
1541 				}
1542 				break;
1543 			case IEEE80211_AUTH_AUTO:
1544 				LINE_CHECK("authmode AUTO");
1545 				break;
1546 			default:
1547 				LINE_CHECK("authmode UNKNOWN (0x%x)",
1548 					ireq.i_val);
1549 				break;
1550 		}
1551 	}
1552 
1553 	ireq.i_type = IEEE80211_IOC_WEP;
1554 	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1555 	    ireq.i_val != IEEE80211_WEP_NOSUP) {
1556 		int firstkey, wepmode;
1557 
1558 		wepmode = ireq.i_val;
1559 		switch (wepmode) {
1560 			case IEEE80211_WEP_OFF:
1561 				LINE_CHECK("privacy OFF");
1562 				break;
1563 			case IEEE80211_WEP_ON:
1564 				LINE_CHECK("privacy ON");
1565 				break;
1566 			case IEEE80211_WEP_MIXED:
1567 				LINE_CHECK("privacy MIXED");
1568 				break;
1569 			default:
1570 				LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1571 				break;
1572 		}
1573 
1574 		/*
1575 		 * If we get here then we've got WEP support so we need
1576 		 * to print WEP status.
1577 		 */
1578 
1579 		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1580 		if (ioctl(s, SIOCG80211, &ireq) < 0) {
1581 			warn("WEP support, but no tx key!");
1582 			goto end;
1583 		}
1584 		if (ireq.i_val != -1)
1585 			LINE_CHECK("deftxkey %d", ireq.i_val+1);
1586 		else if (wepmode != IEEE80211_WEP_OFF || verbose)
1587 			LINE_CHECK("deftxkey UNDEF");
1588 
1589 		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1590 		if (ioctl(s, SIOCG80211, &ireq) < 0) {
1591 			warn("WEP support, but no NUMWEPKEYS support!");
1592 			goto end;
1593 		}
1594 		num = ireq.i_val;
1595 
1596 		firstkey = 1;
1597 		for (i = 0; i < num; i++) {
1598 			struct ieee80211req_key ik;
1599 
1600 			memset(&ik, 0, sizeof(ik));
1601 			ik.ik_keyix = i;
1602 			ireq.i_type = IEEE80211_IOC_WPAKEY;
1603 			ireq.i_data = &ik;
1604 			ireq.i_len = sizeof(ik);
1605 			if (ioctl(s, SIOCG80211, &ireq) < 0) {
1606 				warn("WEP support, but can get keys!");
1607 				goto end;
1608 			}
1609 			if (ik.ik_keylen != 0) {
1610 				if (verbose)
1611 					LINE_BREAK();
1612 				printkey(&ik);
1613 				firstkey = 0;
1614 			}
1615 		}
1616 	}
1617 
1618 	ireq.i_type = IEEE80211_IOC_POWERSAVE;
1619 	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1620 	    ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1621 		if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1622 			switch (ireq.i_val) {
1623 				case IEEE80211_POWERSAVE_OFF:
1624 					LINE_CHECK("powersavemode OFF");
1625 					break;
1626 				case IEEE80211_POWERSAVE_CAM:
1627 					LINE_CHECK("powersavemode CAM");
1628 					break;
1629 				case IEEE80211_POWERSAVE_PSP:
1630 					LINE_CHECK("powersavemode PSP");
1631 					break;
1632 				case IEEE80211_POWERSAVE_PSP_CAM:
1633 					LINE_CHECK("powersavemode PSP-CAM");
1634 					break;
1635 			}
1636 			ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1637 			if (ioctl(s, SIOCG80211, &ireq) != -1)
1638 				LINE_CHECK("powersavesleep %d", ireq.i_val);
1639 		}
1640 	}
1641 
1642 	ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1643 	if (ioctl(s, SIOCG80211, &ireq) != -1)
1644 		LINE_CHECK("txpowmax %d", ireq.i_val);
1645 
1646 	if (verbose) {
1647 		ireq.i_type = IEEE80211_IOC_TXPOWER;
1648 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1649 			LINE_CHECK("txpower %d", ireq.i_val);
1650 	}
1651 
1652 	ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1653 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1654 		if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1655 			LINE_CHECK("rtsthreshold %d", ireq.i_val);
1656 	}
1657 
1658 	ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1659 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1660 		if (ireq.i_val != 2*1 || verbose) {
1661 			if (ireq.i_val == 11)
1662 				LINE_CHECK("mcastrate 5.5");
1663 			else
1664 				LINE_CHECK("mcastrate %d", ireq.i_val/2);
1665 		}
1666 	}
1667 
1668 	ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1669 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1670 		if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1671 			LINE_CHECK("fragthreshold %d", ireq.i_val);
1672 	}
1673 
1674 	if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1675 		ireq.i_type = IEEE80211_IOC_PUREG;
1676 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1677 			if (ireq.i_val)
1678 				LINE_CHECK("pureg");
1679 			else if (verbose)
1680 				LINE_CHECK("-pureg");
1681 		}
1682 		ireq.i_type = IEEE80211_IOC_PROTMODE;
1683 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1684 			switch (ireq.i_val) {
1685 				case IEEE80211_PROTMODE_OFF:
1686 					LINE_CHECK("protmode OFF");
1687 					break;
1688 				case IEEE80211_PROTMODE_CTS:
1689 					LINE_CHECK("protmode CTS");
1690 					break;
1691 				case IEEE80211_PROTMODE_RTSCTS:
1692 					LINE_CHECK("protmode RTSCTS");
1693 					break;
1694 				default:
1695 					LINE_CHECK("protmode UNKNOWN (0x%x)",
1696 						ireq.i_val);
1697 					break;
1698 			}
1699 		}
1700 	}
1701 
1702 	ireq.i_type = IEEE80211_IOC_WME;
1703 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1704 		wme = ireq.i_val;
1705 		if (wme)
1706 			LINE_CHECK("wme");
1707 		else if (verbose)
1708 			LINE_CHECK("-wme");
1709 	} else
1710 		wme = 0;
1711 
1712 	ireq.i_type = IEEE80211_IOC_BURST;
1713 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1714 		if (ireq.i_val)
1715 			LINE_CHECK("burst");
1716 		else if (verbose)
1717 			LINE_CHECK("-burst");
1718 	}
1719 
1720 	if (opmode == IEEE80211_M_HOSTAP) {
1721 		ireq.i_type = IEEE80211_IOC_HIDESSID;
1722 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1723 			if (ireq.i_val)
1724 				LINE_CHECK("ssid HIDE");
1725 			else if (verbose)
1726 				LINE_CHECK("ssid SHOW");
1727 		}
1728 
1729 		ireq.i_type = IEEE80211_IOC_APBRIDGE;
1730 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1731 			if (!ireq.i_val)
1732 				LINE_CHECK("-apbridge");
1733 			else if (verbose)
1734 				LINE_CHECK("apbridge");
1735 		}
1736 
1737 		ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1738 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1739 			LINE_CHECK("dtimperiod %u", ireq.i_val);
1740 	} else {
1741 		ireq.i_type = IEEE80211_IOC_ROAMING;
1742 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1743 			if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1744 				switch (ireq.i_val) {
1745 				case IEEE80211_ROAMING_DEVICE:
1746 					LINE_CHECK("roaming DEVICE");
1747 					break;
1748 				case IEEE80211_ROAMING_AUTO:
1749 					LINE_CHECK("roaming AUTO");
1750 					break;
1751 				case IEEE80211_ROAMING_MANUAL:
1752 					LINE_CHECK("roaming MANUAL");
1753 					break;
1754 				default:
1755 					LINE_CHECK("roaming UNKNOWN (0x%x)",
1756 						ireq.i_val);
1757 					break;
1758 				}
1759 			}
1760 		}
1761 	}
1762 	ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1763 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1764 		if (ireq.i_val)
1765 			LINE_CHECK("bintval %u", ireq.i_val);
1766 		else if (verbose)
1767 			LINE_CHECK("bintval %u", ireq.i_val);
1768 	}
1769 
1770 	if (wme && verbose) {
1771 		LINE_BREAK();
1772 		list_wme(s);
1773 	}
1774 
1775 	if (wpa) {
1776 		ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1777 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1778 			if (ireq.i_val)
1779 				LINE_CHECK("countermeasures");
1780 			else if (verbose)
1781 				LINE_CHECK("-countermeasures");
1782 		}
1783 #if 0
1784 		/* XXX not interesting with WPA done in user space */
1785 		ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1786 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1787 		}
1788 
1789 		ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1790 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1791 			LINE_CHECK("mcastcipher ");
1792 			printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1793 			spacer = ' ';
1794 		}
1795 
1796 		ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1797 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1798 			LINE_CHECK("ucastcipher ");
1799 			printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1800 		}
1801 
1802 		if (wpa & 2) {
1803 			ireq.i_type = IEEE80211_IOC_RSNCAPS;
1804 			if (ioctl(s, SIOCG80211, &ireq) != -1) {
1805 				LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1806 				spacer = ' ';
1807 			}
1808 		}
1809 
1810 		ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1811 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1812 		}
1813 #endif
1814 		LINE_BREAK();
1815 	}
1816 	LINE_BREAK();
1817 
1818 end:
1819 	return;
1820 }
1821 
1822 static void
1823 set80211(int s, int type, int val, int len, u_int8_t *data)
1824 {
1825 	struct ieee80211req	ireq;
1826 
1827 	(void) memset(&ireq, 0, sizeof(ireq));
1828 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1829 	ireq.i_type = type;
1830 	ireq.i_val = val;
1831 	ireq.i_len = len;
1832 	ireq.i_data = data;
1833 	if (ioctl(s, SIOCS80211, &ireq) < 0)
1834 		err(1, "SIOCS80211");
1835 }
1836 
1837 static const char *
1838 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1839 {
1840 	int len;
1841 	int hexstr;
1842 	u_int8_t *p;
1843 
1844 	len = *lenp;
1845 	p = buf;
1846 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1847 	if (hexstr)
1848 		val += 2;
1849 	for (;;) {
1850 		if (*val == '\0')
1851 			break;
1852 		if (sep != NULL && strchr(sep, *val) != NULL) {
1853 			val++;
1854 			break;
1855 		}
1856 		if (hexstr) {
1857 			if (!isxdigit((u_char)val[0])) {
1858 				warnx("bad hexadecimal digits");
1859 				return NULL;
1860 			}
1861 			if (!isxdigit((u_char)val[1])) {
1862 				warnx("odd count hexadecimal digits");
1863 				return NULL;
1864 			}
1865 		}
1866 		if (p >= buf + len) {
1867 			if (hexstr)
1868 				warnx("hexadecimal digits too long");
1869 			else
1870 				warnx("string too long");
1871 			return NULL;
1872 		}
1873 		if (hexstr) {
1874 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1875 			*p++ = (tohex((u_char)val[0]) << 4) |
1876 			    tohex((u_char)val[1]);
1877 #undef tohex
1878 			val += 2;
1879 		} else
1880 			*p++ = *val++;
1881 	}
1882 	len = p - buf;
1883 	/* The string "-" is treated as the empty string. */
1884 	if (!hexstr && len == 1 && buf[0] == '-')
1885 		len = 0;
1886 	if (len < *lenp)
1887 		memset(p, 0, *lenp - len);
1888 	*lenp = len;
1889 	return val;
1890 }
1891 
1892 static void
1893 print_string(const u_int8_t *buf, int len)
1894 {
1895 	int i;
1896 	int hasspc;
1897 
1898 	i = 0;
1899 	hasspc = 0;
1900 	for (; i < len; i++) {
1901 		if (!isprint(buf[i]) && buf[i] != '\0')
1902 			break;
1903 		if (isspace(buf[i]))
1904 			hasspc++;
1905 	}
1906 	if (i == len) {
1907 		if (hasspc || len == 0 || buf[0] == '\0')
1908 			printf("\"%.*s\"", len, buf);
1909 		else
1910 			printf("%.*s", len, buf);
1911 	} else {
1912 		printf("0x");
1913 		for (i = 0; i < len; i++)
1914 			printf("%02x", buf[i]);
1915 	}
1916 }
1917 
1918 static struct cmd ieee80211_cmds[] = {
1919 	DEF_CMD_ARG("ssid",		set80211ssid),
1920 	DEF_CMD_ARG("nwid",		set80211ssid),
1921 	DEF_CMD_ARG("stationname",	set80211stationname),
1922 	DEF_CMD_ARG("station",		set80211stationname),	/* BSD/OS */
1923 	DEF_CMD_ARG("channel",		set80211channel),
1924 	DEF_CMD_ARG("authmode",		set80211authmode),
1925 	DEF_CMD_ARG("powersavemode",	set80211powersavemode),
1926 	DEF_CMD("powersave",	1,	set80211powersave),
1927 	DEF_CMD("-powersave",	0,	set80211powersave),
1928 	DEF_CMD_ARG("powersavesleep", 	set80211powersavesleep),
1929 	DEF_CMD_ARG("wepmode",		set80211wepmode),
1930 	DEF_CMD("wep",		1,	set80211wep),
1931 	DEF_CMD("-wep",		0,	set80211wep),
1932 	DEF_CMD_ARG("deftxkey",		set80211weptxkey),
1933 	DEF_CMD_ARG("weptxkey",		set80211weptxkey),
1934 	DEF_CMD_ARG("wepkey",		set80211wepkey),
1935 	DEF_CMD_ARG("nwkey",		set80211nwkey),		/* NetBSD */
1936 	DEF_CMD("-nwkey",	0,	set80211wep),		/* NetBSD */
1937 	DEF_CMD_ARG("rtsthreshold",	set80211rtsthreshold),
1938 	DEF_CMD_ARG("protmode",		set80211protmode),
1939 	DEF_CMD_ARG("txpower",		set80211txpower),
1940 	DEF_CMD_ARG("roaming",		set80211roaming),
1941 	DEF_CMD("wme",		1,	set80211wme),
1942 	DEF_CMD("-wme",		0,	set80211wme),
1943 	DEF_CMD("hidessid",	1,	set80211hidessid),
1944 	DEF_CMD("-hidessid",	0,	set80211hidessid),
1945 	DEF_CMD("apbridge",	1,	set80211apbridge),
1946 	DEF_CMD("-apbridge",	0,	set80211apbridge),
1947 	DEF_CMD_ARG("chanlist",		set80211chanlist),
1948 	DEF_CMD_ARG("bssid",		set80211bssid),
1949 	DEF_CMD_ARG("ap",		set80211bssid),
1950 	DEF_CMD("scan",	0,		set80211scan),
1951 	DEF_CMD_ARG("list",		set80211list),
1952 	DEF_CMD_ARG2("cwmin",		set80211cwmin),
1953 	DEF_CMD_ARG2("cwmax",		set80211cwmax),
1954 	DEF_CMD_ARG2("aifs",		set80211aifs),
1955 	DEF_CMD_ARG2("txoplimit",	set80211txoplimit),
1956 	DEF_CMD_ARG("acm",		set80211acm),
1957 	DEF_CMD_ARG("-acm",		set80211noacm),
1958 	DEF_CMD_ARG("ack",		set80211ackpolicy),
1959 	DEF_CMD_ARG("-ack",		set80211noackpolicy),
1960 	DEF_CMD_ARG2("bss:cwmin",	set80211bsscwmin),
1961 	DEF_CMD_ARG2("bss:cwmax",	set80211bsscwmax),
1962 	DEF_CMD_ARG2("bss:aifs",	set80211bssaifs),
1963 	DEF_CMD_ARG2("bss:txoplimit",	set80211bsstxoplimit),
1964 	DEF_CMD_ARG("dtimperiod",	set80211dtimperiod),
1965 	DEF_CMD_ARG("bintval",		set80211bintval),
1966 	DEF_CMD("mac:open",	IEEE80211_MACCMD_POLICY_OPEN,	set80211maccmd),
1967 	DEF_CMD("mac:allow",	IEEE80211_MACCMD_POLICY_ALLOW,	set80211maccmd),
1968 	DEF_CMD("mac:deny",	IEEE80211_MACCMD_POLICY_DENY,	set80211maccmd),
1969 	DEF_CMD("mac:flush",	IEEE80211_MACCMD_FLUSH,		set80211maccmd),
1970 	DEF_CMD("mac:detach",	IEEE80211_MACCMD_DETACH,	set80211maccmd),
1971 	DEF_CMD_ARG("mac:add",		set80211addmac),
1972 	DEF_CMD_ARG("mac:del",		set80211delmac),
1973 	DEF_CMD_ARG("mac:kick",		set80211kickmac),
1974 	DEF_CMD("pureg",	1,	set80211pureg),
1975 	DEF_CMD("-pureg",	0,	set80211pureg),
1976 	DEF_CMD_ARG("mcastrate",	set80211mcastrate),
1977 	DEF_CMD_ARG("fragthreshold",	set80211fragthreshold),
1978 	DEF_CMD("burst",	1,	set80211burst),
1979 	DEF_CMD("-burst",	0,	set80211burst),
1980 };
1981 static struct afswtch af_ieee80211 = {
1982 	.af_name	= "af_ieee80211",
1983 	.af_af		= AF_UNSPEC,
1984 	.af_other_status = ieee80211_status,
1985 };
1986 
1987 static __constructor void
1988 ieee80211_ctor(void)
1989 {
1990 #define	N(a)	(sizeof(a) / sizeof(a[0]))
1991 	int i;
1992 
1993 	for (i = 0; i < N(ieee80211_cmds);  i++)
1994 		cmd_register(&ieee80211_cmds[i]);
1995 	af_register(&af_ieee80211);
1996 #undef N
1997 }
1998