xref: /freebsd/sbin/ifconfig/ifieee80211.c (revision 87569f75a91f298c52a71823c04d41cf53c88889)
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 void
731 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
732 {
733 	printf("%s", tag);
734 	if (verbose) {
735 		maxlen -= strlen(tag)+2;
736 		if (2*ielen > maxlen)
737 			maxlen--;
738 		printf("<");
739 		for (; ielen > 0; ie++, ielen--) {
740 			if (maxlen-- <= 0)
741 				break;
742 			printf("%02x", *ie);
743 		}
744 		if (ielen != 0)
745 			printf("-");
746 		printf(">");
747 	}
748 }
749 
750 /*
751  * Copy the ssid string contents into buf, truncating to fit.  If the
752  * ssid is entirely printable then just copy intact.  Otherwise convert
753  * to hexadecimal.  If the result is truncated then replace the last
754  * three characters with "...".
755  */
756 static int
757 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
758 {
759 	const u_int8_t *p;
760 	size_t maxlen;
761 	int i;
762 
763 	if (essid_len > bufsize)
764 		maxlen = bufsize;
765 	else
766 		maxlen = essid_len;
767 	/* determine printable or not */
768 	for (i = 0, p = essid; i < maxlen; i++, p++) {
769 		if (*p < ' ' || *p > 0x7e)
770 			break;
771 	}
772 	if (i != maxlen) {		/* not printable, print as hex */
773 		if (bufsize < 3)
774 			return 0;
775 		strlcpy(buf, "0x", bufsize);
776 		bufsize -= 2;
777 		p = essid;
778 		for (i = 0; i < maxlen && bufsize >= 2; i++) {
779 			sprintf(&buf[2+2*i], "%02x", p[i]);
780 			bufsize -= 2;
781 		}
782 		if (i != essid_len)
783 			memcpy(&buf[2+2*i-3], "...", 3);
784 	} else {			/* printable, truncate as needed */
785 		memcpy(buf, essid, maxlen);
786 		if (maxlen != essid_len)
787 			memcpy(&buf[maxlen-3], "...", 3);
788 	}
789 	return maxlen;
790 }
791 
792 /* unaligned little endian access */
793 #define LE_READ_4(p)					\
794 	((u_int32_t)					\
795 	 ((((const u_int8_t *)(p))[0]      ) |		\
796 	  (((const u_int8_t *)(p))[1] <<  8) |		\
797 	  (((const u_int8_t *)(p))[2] << 16) |		\
798 	  (((const u_int8_t *)(p))[3] << 24)))
799 
800 static int __inline
801 iswpaoui(const u_int8_t *frm)
802 {
803 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
804 }
805 
806 static int __inline
807 iswmeoui(const u_int8_t *frm)
808 {
809 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
810 }
811 
812 static int __inline
813 isatherosoui(const u_int8_t *frm)
814 {
815 	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
816 }
817 
818 static void
819 printies(const u_int8_t *vp, int ielen, int maxcols)
820 {
821 	while (ielen > 0) {
822 		switch (vp[0]) {
823 		case IEEE80211_ELEMID_VENDOR:
824 			if (iswpaoui(vp))
825 				printie(" WPA", vp, 2+vp[1], maxcols);
826 			else if (iswmeoui(vp))
827 				printie(" WME", vp, 2+vp[1], maxcols);
828 			else if (isatherosoui(vp))
829 				printie(" ATH", vp, 2+vp[1], maxcols);
830 			else
831 				printie(" VEN", vp, 2+vp[1], maxcols);
832 			break;
833 		case IEEE80211_ELEMID_RSN:
834 			printie(" RSN", vp, 2+vp[1], maxcols);
835 			break;
836 		default:
837 			printie(" ???", vp, 2+vp[1], maxcols);
838 			break;
839 		}
840 		ielen -= 2+vp[1];
841 		vp += 2+vp[1];
842 	}
843 }
844 
845 static void
846 list_scan(int s)
847 {
848 	uint8_t buf[24*1024];
849 	struct ieee80211req ireq;
850 	char ssid[IEEE80211_NWID_LEN+1];
851 	uint8_t *cp;
852 	int len, ssidmax;
853 
854 	(void) memset(&ireq, 0, sizeof(ireq));
855 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
856 	ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
857 	ireq.i_data = buf;
858 	ireq.i_len = sizeof(buf);
859 	if (ioctl(s, SIOCG80211, &ireq) < 0)
860 		errx(1, "unable to get scan results");
861 	len = ireq.i_len;
862 	if (len < sizeof(struct ieee80211req_scan_result))
863 		return;
864 
865 	ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
866 	printf("%-*.*s  %-17.17s  %4s %4s  %-5s %3s %4s\n"
867 		, ssidmax, ssidmax, "SSID"
868 		, "BSSID"
869 		, "CHAN"
870 		, "RATE"
871 		, "S:N"
872 		, "INT"
873 		, "CAPS"
874 	);
875 	cp = buf;
876 	do {
877 		struct ieee80211req_scan_result *sr;
878 		uint8_t *vp;
879 
880 		sr = (struct ieee80211req_scan_result *) cp;
881 		vp = (u_int8_t *)(sr+1);
882 		printf("%-*.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s"
883 			, ssidmax
884 			  , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
885 			  , ssid
886 			, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
887 			, ieee80211_mhz2ieee(sr->isr_freq)
888 			, getmaxrate(sr->isr_rates, sr->isr_nrates)
889 			, sr->isr_rssi, sr->isr_noise
890 			, sr->isr_intval
891 			, getcaps(sr->isr_capinfo)
892 		);
893 		printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
894 		printf("\n");
895 		cp += sr->isr_len, len -= sr->isr_len;
896 	} while (len >= sizeof(struct ieee80211req_scan_result));
897 }
898 
899 #include <net80211/ieee80211_freebsd.h>
900 
901 static void
902 scan_and_wait(int s)
903 {
904 	struct ieee80211req ireq;
905 	int sroute;
906 
907 	sroute = socket(PF_ROUTE, SOCK_RAW, 0);
908 	if (sroute < 0) {
909 		perror("socket(PF_ROUTE,SOCK_RAW)");
910 		return;
911 	}
912 	(void) memset(&ireq, 0, sizeof(ireq));
913 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
914 	ireq.i_type = IEEE80211_IOC_SCAN_REQ;
915 	/* NB: only root can trigger a scan so ignore errors */
916 	if (ioctl(s, SIOCS80211, &ireq) >= 0) {
917 		char buf[2048];
918 		struct if_announcemsghdr *ifan;
919 		struct rt_msghdr *rtm;
920 
921 		do {
922 			if (read(sroute, buf, sizeof(buf)) < 0) {
923 				perror("read(PF_ROUTE)");
924 				break;
925 			}
926 			rtm = (struct rt_msghdr *) buf;
927 			if (rtm->rtm_version != RTM_VERSION)
928 				break;
929 			ifan = (struct if_announcemsghdr *) rtm;
930 		} while (rtm->rtm_type != RTM_IEEE80211 ||
931 		    ifan->ifan_what != RTM_IEEE80211_SCAN);
932 	}
933 	close(sroute);
934 }
935 
936 static
937 DECL_CMD_FUNC(set80211scan, val, d)
938 {
939 	scan_and_wait(s);
940 	list_scan(s);
941 }
942 
943 static void
944 list_stations(int s)
945 {
946 	uint8_t buf[24*1024];
947 	struct ieee80211req ireq;
948 	uint8_t *cp;
949 	int len;
950 
951 	(void) memset(&ireq, 0, sizeof(ireq));
952 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
953 	ireq.i_type = IEEE80211_IOC_STA_INFO;
954 	ireq.i_data = buf;
955 	ireq.i_len = sizeof(buf);
956 	if (ioctl(s, SIOCG80211, &ireq) < 0)
957 		errx(1, "unable to get station information");
958 	len = ireq.i_len;
959 	if (len < sizeof(struct ieee80211req_sta_info))
960 		return;
961 
962 	printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
963 		, "ADDR"
964 		, "AID"
965 		, "CHAN"
966 		, "RATE"
967 		, "RSSI"
968 		, "IDLE"
969 		, "TXSEQ"
970 		, "RXSEQ"
971 		, "CAPS"
972 		, "ERP"
973 	);
974 	cp = buf;
975 	do {
976 		struct ieee80211req_sta_info *si;
977 		uint8_t *vp;
978 
979 		si = (struct ieee80211req_sta_info *) cp;
980 		vp = (u_int8_t *)(si+1);
981 		printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
982 			, ether_ntoa((const struct ether_addr*) si->isi_macaddr)
983 			, IEEE80211_AID(si->isi_associd)
984 			, ieee80211_mhz2ieee(si->isi_freq)
985 			, (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
986 			, si->isi_rssi
987 			, si->isi_inact
988 			, si->isi_txseqs[0]
989 			, si->isi_rxseqs[0]
990 			, getcaps(si->isi_capinfo)
991 			, si->isi_erp
992 		);
993 		printies(vp, si->isi_ie_len, 24);
994 		printf("\n");
995 		cp += si->isi_len, len -= si->isi_len;
996 	} while (len >= sizeof(struct ieee80211req_sta_info));
997 }
998 
999 static void
1000 print_chaninfo(const struct ieee80211_channel *c)
1001 {
1002 #define	IEEE80211_IS_CHAN_PASSIVE(_c) \
1003 	(((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1004 	char buf[14];
1005 
1006 	buf[0] = '\0';
1007 	if (IEEE80211_IS_CHAN_FHSS(c))
1008 		strlcat(buf, " FHSS", sizeof(buf));
1009 	if (IEEE80211_IS_CHAN_A(c))
1010 		strlcat(buf, " 11a", sizeof(buf));
1011 	/* XXX 11g schizophrenia */
1012 	if (IEEE80211_IS_CHAN_G(c) ||
1013 	    IEEE80211_IS_CHAN_PUREG(c))
1014 		strlcat(buf, " 11g", sizeof(buf));
1015 	else if (IEEE80211_IS_CHAN_B(c))
1016 		strlcat(buf, " 11b", sizeof(buf));
1017 	if (IEEE80211_IS_CHAN_T(c))
1018 		strlcat(buf, " Turbo", sizeof(buf));
1019 	printf("Channel %3u : %u%c Mhz%-14.14s",
1020 		ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1021 		IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1022 #undef IEEE80211_IS_CHAN_PASSIVE
1023 }
1024 
1025 static void
1026 list_channels(int s, int allchans)
1027 {
1028 	struct ieee80211req ireq;
1029 	struct ieee80211req_chaninfo chans;
1030 	struct ieee80211req_chaninfo achans;
1031 	const struct ieee80211_channel *c;
1032 	int i, half;
1033 
1034 	(void) memset(&ireq, 0, sizeof(ireq));
1035 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1036 	ireq.i_type = IEEE80211_IOC_CHANINFO;
1037 	ireq.i_data = &chans;
1038 	ireq.i_len = sizeof(chans);
1039 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1040 		errx(1, "unable to get channel information");
1041 	if (!allchans) {
1042 		struct ieee80211req_chanlist active;
1043 
1044 		ireq.i_type = IEEE80211_IOC_CHANLIST;
1045 		ireq.i_data = &active;
1046 		ireq.i_len = sizeof(active);
1047 		if (ioctl(s, SIOCG80211, &ireq) < 0)
1048 			errx(1, "unable to get active channel list");
1049 		memset(&achans, 0, sizeof(achans));
1050 		for (i = 0; i < chans.ic_nchans; i++) {
1051 			c = &chans.ic_chans[i];
1052 			if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1053 				achans.ic_chans[achans.ic_nchans++] = *c;
1054 		}
1055 	} else
1056 		achans = chans;
1057 	half = achans.ic_nchans / 2;
1058 	if (achans.ic_nchans % 2)
1059 		half++;
1060 	for (i = 0; i < achans.ic_nchans / 2; i++) {
1061 		print_chaninfo(&achans.ic_chans[i]);
1062 		print_chaninfo(&achans.ic_chans[half+i]);
1063 		printf("\n");
1064 	}
1065 	if (achans.ic_nchans % 2) {
1066 		print_chaninfo(&achans.ic_chans[i]);
1067 		printf("\n");
1068 	}
1069 }
1070 
1071 static void
1072 list_keys(int s)
1073 {
1074 }
1075 
1076 #define	IEEE80211_C_BITS \
1077 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1078 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1079 "\31WPA2\32BURST\33WME"
1080 
1081 static void
1082 list_capabilities(int s)
1083 {
1084 	struct ieee80211req ireq;
1085 	u_int32_t caps;
1086 
1087 	(void) memset(&ireq, 0, sizeof(ireq));
1088 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1089 	ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1090 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1091 		errx(1, "unable to get driver capabilities");
1092 	caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1093 	printb(name, caps, IEEE80211_C_BITS);
1094 	putchar('\n');
1095 }
1096 
1097 static void
1098 list_wme(int s)
1099 {
1100 	static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1101 	struct ieee80211req ireq;
1102 	int ac;
1103 
1104 	(void) memset(&ireq, 0, sizeof(ireq));
1105 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1106 	ireq.i_len = 0;
1107 	for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1108 again:
1109 		if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1110 			printf("\t%s", "     ");
1111 		else
1112 			printf("\t%s", acnames[ac]);
1113 
1114 		ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1115 
1116 		/* show WME BSS parameters */
1117 		ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1118 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1119 			printf(" cwmin %2u", ireq.i_val);
1120 		ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1121 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1122 			printf(" cwmax %2u", ireq.i_val);
1123 		ireq.i_type = IEEE80211_IOC_WME_AIFS;
1124 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1125 			printf(" aifs %2u", ireq.i_val);
1126 		ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1127 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1128 			printf(" txopLimit %3u", ireq.i_val);
1129 		ireq.i_type = IEEE80211_IOC_WME_ACM;
1130 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1131 			if (ireq.i_val)
1132 				printf(" acm");
1133 			else if (verbose)
1134 				printf(" -acm");
1135 		}
1136 		/* !BSS only */
1137 		if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1138 			ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1139 			if (ioctl(s, SIOCG80211, &ireq) != -1) {
1140 				if (!ireq.i_val)
1141 					printf(" -ack");
1142 				else if (verbose)
1143 					printf(" ack");
1144 			}
1145 		}
1146 		printf("\n");
1147 		if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1148 			ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1149 			goto again;
1150 		} else
1151 			ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1152 	}
1153 }
1154 
1155 static void
1156 list_mac(int s)
1157 {
1158 	struct ieee80211req ireq;
1159 	struct ieee80211req_maclist *acllist;
1160 	int i, nacls, policy;
1161 	char c;
1162 
1163 	(void) memset(&ireq, 0, sizeof(ireq));
1164 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1165 	ireq.i_type = IEEE80211_IOC_MACCMD;
1166 	ireq.i_val = IEEE80211_MACCMD_POLICY;
1167 	if (ioctl(s, SIOCG80211, &ireq) < 0) {
1168 		if (errno == EINVAL) {
1169 			printf("No acl policy loaded\n");
1170 			return;
1171 		}
1172 		err(1, "unable to get mac policy");
1173 	}
1174 	policy = ireq.i_val;
1175 
1176 	ireq.i_val = IEEE80211_MACCMD_LIST;
1177 	ireq.i_len = 0;
1178 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1179 		err(1, "unable to get mac acl list size");
1180 	if (ireq.i_len == 0)		/* NB: no acls */
1181 		return;
1182 
1183 	ireq.i_data = malloc(ireq.i_len);
1184 	if (ireq.i_data == NULL)
1185 		err(1, "out of memory for acl list");
1186 
1187 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1188 		err(1, "unable to get mac acl list");
1189 	if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1190 		if (verbose)
1191 			printf("policy: open\n");
1192 		c = '*';
1193 	} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1194 		if (verbose)
1195 			printf("policy: allow\n");
1196 		c = '+';
1197 	} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1198 		if (verbose)
1199 			printf("policy: deny\n");
1200 		c = '-';
1201 	} else {
1202 		printf("policy: unknown (%u)\n", policy);
1203 		c = '?';
1204 	}
1205 	nacls = ireq.i_len / sizeof(*acllist);
1206 	acllist = (struct ieee80211req_maclist *) ireq.i_data;
1207 	for (i = 0; i < nacls; i++)
1208 		printf("%c%s\n", c, ether_ntoa(
1209 			(const struct ether_addr *) acllist[i].ml_macaddr));
1210 }
1211 
1212 static
1213 DECL_CMD_FUNC(set80211list, arg, d)
1214 {
1215 #define	iseq(a,b)	(strncasecmp(a,b,sizeof(b)-1) == 0)
1216 
1217 	if (iseq(arg, "sta"))
1218 		list_stations(s);
1219 	else if (iseq(arg, "scan") || iseq(arg, "ap"))
1220 		list_scan(s);
1221 	else if (iseq(arg, "chan") || iseq(arg, "freq"))
1222 		list_channels(s, 1);
1223 	else if (iseq(arg, "active"))
1224 		list_channels(s, 0);
1225 	else if (iseq(arg, "keys"))
1226 		list_keys(s);
1227 	else if (iseq(arg, "caps"))
1228 		list_capabilities(s);
1229 	else if (iseq(arg, "wme"))
1230 		list_wme(s);
1231 	else if (iseq(arg, "mac"))
1232 		list_mac(s);
1233 	else
1234 		errx(1, "Don't know how to list %s for %s", arg, name);
1235 #undef iseq
1236 }
1237 
1238 static enum ieee80211_opmode
1239 get80211opmode(int s)
1240 {
1241 	struct ifmediareq ifmr;
1242 
1243 	(void) memset(&ifmr, 0, sizeof(ifmr));
1244 	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1245 
1246 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1247 		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1248 			return IEEE80211_M_IBSS;	/* XXX ahdemo */
1249 		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1250 			return IEEE80211_M_HOSTAP;
1251 		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1252 			return IEEE80211_M_MONITOR;
1253 	}
1254 	return IEEE80211_M_STA;
1255 }
1256 
1257 static const struct ieee80211_channel *
1258 getchaninfo(int s, int chan)
1259 {
1260 	struct ieee80211req ireq;
1261 	static struct ieee80211req_chaninfo chans;
1262 	static struct ieee80211_channel undef;
1263 	const struct ieee80211_channel *c;
1264 	int i, freq;
1265 
1266 	(void) memset(&ireq, 0, sizeof(ireq));
1267 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1268 	ireq.i_type = IEEE80211_IOC_CHANINFO;
1269 	ireq.i_data = &chans;
1270 	ireq.i_len = sizeof(chans);
1271 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1272 		errx(1, "unable to get channel information");
1273 	freq = ieee80211_ieee2mhz(chan);
1274 	for (i = 0; i < chans.ic_nchans; i++) {
1275 		c = &chans.ic_chans[i];
1276 		if (c->ic_freq == freq)
1277 			return c;
1278 	}
1279 	return &undef;
1280 }
1281 
1282 #if 0
1283 static void
1284 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1285 {
1286 	switch (ireq->i_val) {
1287 	case IEEE80211_CIPHER_WEP:
1288 		ireq->i_type = keylenop;
1289 		if (ioctl(s, SIOCG80211, ireq) != -1)
1290 			printf("WEP-%s",
1291 			    ireq->i_len <= 5 ? "40" :
1292 			    ireq->i_len <= 13 ? "104" : "128");
1293 		else
1294 			printf("WEP");
1295 		break;
1296 	case IEEE80211_CIPHER_TKIP:
1297 		printf("TKIP");
1298 		break;
1299 	case IEEE80211_CIPHER_AES_OCB:
1300 		printf("AES-OCB");
1301 		break;
1302 	case IEEE80211_CIPHER_AES_CCM:
1303 		printf("AES-CCM");
1304 		break;
1305 	case IEEE80211_CIPHER_CKIP:
1306 		printf("CKIP");
1307 		break;
1308 	case IEEE80211_CIPHER_NONE:
1309 		printf("NONE");
1310 		break;
1311 	default:
1312 		printf("UNKNOWN (0x%x)", ireq->i_val);
1313 		break;
1314 	}
1315 }
1316 #endif
1317 
1318 #define	MAXCOL	78
1319 static	int col;
1320 static	char spacer;
1321 
1322 static void
1323 LINE_BREAK(void)
1324 {
1325 	if (spacer != '\t') {
1326 		printf("\n");
1327 		spacer = '\t';
1328 	}
1329 	col = 8;	/* 8-col tab */
1330 }
1331 
1332 static void
1333 LINE_CHECK(const char *fmt, ...)
1334 {
1335 	char buf[80];
1336 	va_list ap;
1337 	int n;
1338 
1339 	va_start(ap, fmt);
1340 	n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1341 	va_end(ap);
1342 	col += 1+n;
1343 	if (col > MAXCOL) {
1344 		LINE_BREAK();
1345 		col += n;
1346 	}
1347 	buf[0] = spacer;
1348 	printf("%s", buf);
1349 	spacer = ' ';
1350 }
1351 
1352 static void
1353 printkey(const struct ieee80211req_key *ik)
1354 {
1355 	static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1356 	int keylen = ik->ik_keylen;
1357 	int printcontents;
1358 
1359 	printcontents = printkeys &&
1360 		(memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1361 	if (printcontents)
1362 		LINE_BREAK();
1363 	switch (ik->ik_type) {
1364 	case IEEE80211_CIPHER_WEP:
1365 		/* compatibility */
1366 		LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1367 		    keylen <= 5 ? "40-bit" :
1368 		    keylen <= 13 ? "104-bit" : "128-bit");
1369 		break;
1370 	case IEEE80211_CIPHER_TKIP:
1371 		if (keylen > 128/8)
1372 			keylen -= 128/8;	/* ignore MIC for now */
1373 		LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1374 		break;
1375 	case IEEE80211_CIPHER_AES_OCB:
1376 		LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1377 		break;
1378 	case IEEE80211_CIPHER_AES_CCM:
1379 		LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1380 		break;
1381 	case IEEE80211_CIPHER_CKIP:
1382 		LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1383 		break;
1384 	case IEEE80211_CIPHER_NONE:
1385 		LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1386 		break;
1387 	default:
1388 		LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1389 			ik->ik_type, ik->ik_keyix+1, 8*keylen);
1390 		break;
1391 	}
1392 	if (printcontents) {
1393 		int i;
1394 
1395 		printf(" <");
1396 		for (i = 0; i < keylen; i++)
1397 			printf("%02x", ik->ik_keydata[i]);
1398 		printf(">");
1399 		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1400 		    (ik->ik_keyrsc != 0 || verbose))
1401 			printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1402 		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1403 		    (ik->ik_keytsc != 0 || verbose))
1404 			printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1405 		if (ik->ik_flags != 0 && verbose) {
1406 			const char *sep = " ";
1407 
1408 			if (ik->ik_flags & IEEE80211_KEY_XMIT)
1409 				printf("%stx", sep), sep = "+";
1410 			if (ik->ik_flags & IEEE80211_KEY_RECV)
1411 				printf("%srx", sep), sep = "+";
1412 			if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1413 				printf("%sdef", sep), sep = "+";
1414 		}
1415 		LINE_BREAK();
1416 	}
1417 }
1418 
1419 static void
1420 ieee80211_status(int s)
1421 {
1422 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1423 	enum ieee80211_opmode opmode = get80211opmode(s);
1424 	int i, num, wpa, wme;
1425 	struct ieee80211req ireq;
1426 	u_int8_t data[32];
1427 	const struct ieee80211_channel *c;
1428 
1429 	(void) memset(&ireq, 0, sizeof(ireq));
1430 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1431 	ireq.i_data = &data;
1432 
1433 	wpa = 0;		/* unknown/not set */
1434 
1435 	ireq.i_type = IEEE80211_IOC_SSID;
1436 	ireq.i_val = -1;
1437 	if (ioctl(s, SIOCG80211, &ireq) < 0) {
1438 		/* If we can't get the SSID, this isn't an 802.11 device. */
1439 		return;
1440 	}
1441 	num = 0;
1442 	ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1443 	if (ioctl(s, SIOCG80211, &ireq) >= 0)
1444 		num = ireq.i_val;
1445 	printf("\tssid ");
1446 	if (num > 1) {
1447 		ireq.i_type = IEEE80211_IOC_SSID;
1448 		for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1449 			if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1450 				printf(" %d:", ireq.i_val + 1);
1451 				print_string(data, ireq.i_len);
1452 			}
1453 		}
1454 	} else
1455 		print_string(data, ireq.i_len);
1456 
1457 	ireq.i_type = IEEE80211_IOC_CHANNEL;
1458 	if (ioctl(s, SIOCG80211, &ireq) < 0)
1459 		goto end;
1460 	c = getchaninfo(s, ireq.i_val);
1461 	if (ireq.i_val != -1) {
1462 		printf(" channel %d", ireq.i_val);
1463 		if (verbose)
1464 			printf(" (%u)", c->ic_freq);
1465 	} else if (verbose)
1466 		printf(" channel UNDEF");
1467 
1468 	ireq.i_type = IEEE80211_IOC_BSSID;
1469 	ireq.i_len = IEEE80211_ADDR_LEN;
1470 	if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1471 	    (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1472 		printf(" bssid %s", ether_ntoa(ireq.i_data));
1473 
1474 	ireq.i_type = IEEE80211_IOC_STATIONNAME;
1475 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1476 		printf("\n\tstationname ");
1477 		print_string(data, ireq.i_len);
1478 	}
1479 
1480 	spacer = ' ';		/* force first break */
1481 	LINE_BREAK();
1482 
1483 	ireq.i_type = IEEE80211_IOC_AUTHMODE;
1484 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1485 		switch (ireq.i_val) {
1486 			case IEEE80211_AUTH_NONE:
1487 				LINE_CHECK("authmode NONE");
1488 				break;
1489 			case IEEE80211_AUTH_OPEN:
1490 				LINE_CHECK("authmode OPEN");
1491 				break;
1492 			case IEEE80211_AUTH_SHARED:
1493 				LINE_CHECK("authmode SHARED");
1494 				break;
1495 			case IEEE80211_AUTH_8021X:
1496 				LINE_CHECK("authmode 802.1x");
1497 				break;
1498 			case IEEE80211_AUTH_WPA:
1499 				ireq.i_type = IEEE80211_IOC_WPA;
1500 				if (ioctl(s, SIOCG80211, &ireq) != -1)
1501 					wpa = ireq.i_val;
1502 				if (!wpa)
1503 					wpa = 1;	/* default to WPA1 */
1504 				switch (wpa) {
1505 				case 2:
1506 					LINE_CHECK("authmode WPA2/802.11i");
1507 					break;
1508 				case 3:
1509 					LINE_CHECK("authmode WPA1+WPA2/802.11i");
1510 					break;
1511 				default:
1512 					LINE_CHECK("authmode WPA");
1513 					break;
1514 				}
1515 				break;
1516 			case IEEE80211_AUTH_AUTO:
1517 				LINE_CHECK("authmode AUTO");
1518 				break;
1519 			default:
1520 				LINE_CHECK("authmode UNKNOWN (0x%x)",
1521 					ireq.i_val);
1522 				break;
1523 		}
1524 	}
1525 
1526 	ireq.i_type = IEEE80211_IOC_WEP;
1527 	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1528 	    ireq.i_val != IEEE80211_WEP_NOSUP) {
1529 		int firstkey, wepmode;
1530 
1531 		wepmode = ireq.i_val;
1532 		switch (wepmode) {
1533 			case IEEE80211_WEP_OFF:
1534 				LINE_CHECK("privacy OFF");
1535 				break;
1536 			case IEEE80211_WEP_ON:
1537 				LINE_CHECK("privacy ON");
1538 				break;
1539 			case IEEE80211_WEP_MIXED:
1540 				LINE_CHECK("privacy MIXED");
1541 				break;
1542 			default:
1543 				LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1544 				break;
1545 		}
1546 
1547 		/*
1548 		 * If we get here then we've got WEP support so we need
1549 		 * to print WEP status.
1550 		 */
1551 
1552 		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1553 		if (ioctl(s, SIOCG80211, &ireq) < 0) {
1554 			warn("WEP support, but no tx key!");
1555 			goto end;
1556 		}
1557 		if (ireq.i_val != -1)
1558 			LINE_CHECK("deftxkey %d", ireq.i_val+1);
1559 		else if (wepmode != IEEE80211_WEP_OFF || verbose)
1560 			LINE_CHECK("deftxkey UNDEF");
1561 
1562 		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1563 		if (ioctl(s, SIOCG80211, &ireq) < 0) {
1564 			warn("WEP support, but no NUMWEPKEYS support!");
1565 			goto end;
1566 		}
1567 		num = ireq.i_val;
1568 
1569 		firstkey = 1;
1570 		for (i = 0; i < num; i++) {
1571 			struct ieee80211req_key ik;
1572 
1573 			memset(&ik, 0, sizeof(ik));
1574 			ik.ik_keyix = i;
1575 			ireq.i_type = IEEE80211_IOC_WPAKEY;
1576 			ireq.i_data = &ik;
1577 			ireq.i_len = sizeof(ik);
1578 			if (ioctl(s, SIOCG80211, &ireq) < 0) {
1579 				warn("WEP support, but can get keys!");
1580 				goto end;
1581 			}
1582 			if (ik.ik_keylen != 0) {
1583 				if (verbose)
1584 					LINE_BREAK();
1585 				printkey(&ik);
1586 				firstkey = 0;
1587 			}
1588 		}
1589 	}
1590 
1591 	ireq.i_type = IEEE80211_IOC_POWERSAVE;
1592 	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1593 	    ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1594 		if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1595 			switch (ireq.i_val) {
1596 				case IEEE80211_POWERSAVE_OFF:
1597 					LINE_CHECK("powersavemode OFF");
1598 					break;
1599 				case IEEE80211_POWERSAVE_CAM:
1600 					LINE_CHECK("powersavemode CAM");
1601 					break;
1602 				case IEEE80211_POWERSAVE_PSP:
1603 					LINE_CHECK("powersavemode PSP");
1604 					break;
1605 				case IEEE80211_POWERSAVE_PSP_CAM:
1606 					LINE_CHECK("powersavemode PSP-CAM");
1607 					break;
1608 			}
1609 			ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1610 			if (ioctl(s, SIOCG80211, &ireq) != -1)
1611 				LINE_CHECK("powersavesleep %d", ireq.i_val);
1612 		}
1613 	}
1614 
1615 	ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1616 	if (ioctl(s, SIOCG80211, &ireq) != -1)
1617 		LINE_CHECK("txpowmax %d", ireq.i_val);
1618 
1619 	if (verbose) {
1620 		ireq.i_type = IEEE80211_IOC_TXPOWER;
1621 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1622 			LINE_CHECK("txpower %d", ireq.i_val);
1623 	}
1624 
1625 	ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1626 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1627 		if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1628 			LINE_CHECK("rtsthreshold %d", ireq.i_val);
1629 	}
1630 
1631 	ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1632 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1633 		if (ireq.i_val != 2*1 || verbose) {
1634 			if (ireq.i_val == 11)
1635 				LINE_CHECK("mcastrate 5.5");
1636 			else
1637 				LINE_CHECK("mcastrate %d", ireq.i_val/2);
1638 		}
1639 	}
1640 
1641 	ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1642 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1643 		if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1644 			LINE_CHECK("fragthreshold %d", ireq.i_val);
1645 	}
1646 
1647 	if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1648 		ireq.i_type = IEEE80211_IOC_PUREG;
1649 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1650 			if (ireq.i_val)
1651 				LINE_CHECK("pureg");
1652 			else if (verbose)
1653 				LINE_CHECK("-pureg");
1654 		}
1655 		ireq.i_type = IEEE80211_IOC_PROTMODE;
1656 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1657 			switch (ireq.i_val) {
1658 				case IEEE80211_PROTMODE_OFF:
1659 					LINE_CHECK("protmode OFF");
1660 					break;
1661 				case IEEE80211_PROTMODE_CTS:
1662 					LINE_CHECK("protmode CTS");
1663 					break;
1664 				case IEEE80211_PROTMODE_RTSCTS:
1665 					LINE_CHECK("protmode RTSCTS");
1666 					break;
1667 				default:
1668 					LINE_CHECK("protmode UNKNOWN (0x%x)",
1669 						ireq.i_val);
1670 					break;
1671 			}
1672 		}
1673 	}
1674 
1675 	ireq.i_type = IEEE80211_IOC_WME;
1676 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1677 		wme = ireq.i_val;
1678 		if (wme)
1679 			LINE_CHECK("wme");
1680 		else if (verbose)
1681 			LINE_CHECK("-wme");
1682 	} else
1683 		wme = 0;
1684 
1685 	ireq.i_type = IEEE80211_IOC_BURST;
1686 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1687 		if (ireq.i_val)
1688 			LINE_CHECK("burst");
1689 		else if (verbose)
1690 			LINE_CHECK("-burst");
1691 	}
1692 
1693 	if (opmode == IEEE80211_M_HOSTAP) {
1694 		ireq.i_type = IEEE80211_IOC_HIDESSID;
1695 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1696 			if (ireq.i_val)
1697 				LINE_CHECK("ssid HIDE");
1698 			else if (verbose)
1699 				LINE_CHECK("ssid SHOW");
1700 		}
1701 
1702 		ireq.i_type = IEEE80211_IOC_APBRIDGE;
1703 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1704 			if (!ireq.i_val)
1705 				LINE_CHECK("-apbridge");
1706 			else if (verbose)
1707 				LINE_CHECK("apbridge");
1708 		}
1709 
1710 		ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1711 		if (ioctl(s, SIOCG80211, &ireq) != -1)
1712 			LINE_CHECK("dtimperiod %u", ireq.i_val);
1713 	} else {
1714 		ireq.i_type = IEEE80211_IOC_ROAMING;
1715 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1716 			if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1717 				switch (ireq.i_val) {
1718 				case IEEE80211_ROAMING_DEVICE:
1719 					LINE_CHECK("roaming DEVICE");
1720 					break;
1721 				case IEEE80211_ROAMING_AUTO:
1722 					LINE_CHECK("roaming AUTO");
1723 					break;
1724 				case IEEE80211_ROAMING_MANUAL:
1725 					LINE_CHECK("roaming MANUAL");
1726 					break;
1727 				default:
1728 					LINE_CHECK("roaming UNKNOWN (0x%x)",
1729 						ireq.i_val);
1730 					break;
1731 				}
1732 			}
1733 		}
1734 	}
1735 	ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1736 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
1737 		if (ireq.i_val)
1738 			LINE_CHECK("bintval %u", ireq.i_val);
1739 		else if (verbose)
1740 			LINE_CHECK("bintval %u", ireq.i_val);
1741 	}
1742 
1743 	if (wme && verbose) {
1744 		LINE_BREAK();
1745 		list_wme(s);
1746 	}
1747 
1748 	if (wpa) {
1749 		ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1750 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1751 			if (ireq.i_val)
1752 				LINE_CHECK("countermeasures");
1753 			else if (verbose)
1754 				LINE_CHECK("-countermeasures");
1755 		}
1756 #if 0
1757 		/* XXX not interesting with WPA done in user space */
1758 		ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1759 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1760 		}
1761 
1762 		ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1763 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1764 			LINE_CHECK("mcastcipher ");
1765 			printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1766 			spacer = ' ';
1767 		}
1768 
1769 		ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1770 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1771 			LINE_CHECK("ucastcipher ");
1772 			printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1773 		}
1774 
1775 		if (wpa & 2) {
1776 			ireq.i_type = IEEE80211_IOC_RSNCAPS;
1777 			if (ioctl(s, SIOCG80211, &ireq) != -1) {
1778 				LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1779 				spacer = ' ';
1780 			}
1781 		}
1782 
1783 		ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1784 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
1785 		}
1786 #endif
1787 		LINE_BREAK();
1788 	}
1789 	LINE_BREAK();
1790 
1791 end:
1792 	return;
1793 }
1794 
1795 static void
1796 set80211(int s, int type, int val, int len, u_int8_t *data)
1797 {
1798 	struct ieee80211req	ireq;
1799 
1800 	(void) memset(&ireq, 0, sizeof(ireq));
1801 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1802 	ireq.i_type = type;
1803 	ireq.i_val = val;
1804 	ireq.i_len = len;
1805 	ireq.i_data = data;
1806 	if (ioctl(s, SIOCS80211, &ireq) < 0)
1807 		err(1, "SIOCS80211");
1808 }
1809 
1810 static const char *
1811 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1812 {
1813 	int len;
1814 	int hexstr;
1815 	u_int8_t *p;
1816 
1817 	len = *lenp;
1818 	p = buf;
1819 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1820 	if (hexstr)
1821 		val += 2;
1822 	for (;;) {
1823 		if (*val == '\0')
1824 			break;
1825 		if (sep != NULL && strchr(sep, *val) != NULL) {
1826 			val++;
1827 			break;
1828 		}
1829 		if (hexstr) {
1830 			if (!isxdigit((u_char)val[0])) {
1831 				warnx("bad hexadecimal digits");
1832 				return NULL;
1833 			}
1834 			if (!isxdigit((u_char)val[1])) {
1835 				warnx("odd count hexadecimal digits");
1836 				return NULL;
1837 			}
1838 		}
1839 		if (p >= buf + len) {
1840 			if (hexstr)
1841 				warnx("hexadecimal digits too long");
1842 			else
1843 				warnx("string too long");
1844 			return NULL;
1845 		}
1846 		if (hexstr) {
1847 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1848 			*p++ = (tohex((u_char)val[0]) << 4) |
1849 			    tohex((u_char)val[1]);
1850 #undef tohex
1851 			val += 2;
1852 		} else
1853 			*p++ = *val++;
1854 	}
1855 	len = p - buf;
1856 	/* The string "-" is treated as the empty string. */
1857 	if (!hexstr && len == 1 && buf[0] == '-')
1858 		len = 0;
1859 	if (len < *lenp)
1860 		memset(p, 0, *lenp - len);
1861 	*lenp = len;
1862 	return val;
1863 }
1864 
1865 static void
1866 print_string(const u_int8_t *buf, int len)
1867 {
1868 	int i;
1869 	int hasspc;
1870 
1871 	i = 0;
1872 	hasspc = 0;
1873 	for (; i < len; i++) {
1874 		if (!isprint(buf[i]) && buf[i] != '\0')
1875 			break;
1876 		if (isspace(buf[i]))
1877 			hasspc++;
1878 	}
1879 	if (i == len) {
1880 		if (hasspc || len == 0 || buf[0] == '\0')
1881 			printf("\"%.*s\"", len, buf);
1882 		else
1883 			printf("%.*s", len, buf);
1884 	} else {
1885 		printf("0x");
1886 		for (i = 0; i < len; i++)
1887 			printf("%02x", buf[i]);
1888 	}
1889 }
1890 
1891 static struct cmd ieee80211_cmds[] = {
1892 	DEF_CMD_ARG("ssid",		set80211ssid),
1893 	DEF_CMD_ARG("nwid",		set80211ssid),
1894 	DEF_CMD_ARG("stationname",	set80211stationname),
1895 	DEF_CMD_ARG("station",		set80211stationname),	/* BSD/OS */
1896 	DEF_CMD_ARG("channel",		set80211channel),
1897 	DEF_CMD_ARG("authmode",		set80211authmode),
1898 	DEF_CMD_ARG("powersavemode",	set80211powersavemode),
1899 	DEF_CMD("powersave",	1,	set80211powersave),
1900 	DEF_CMD("-powersave",	0,	set80211powersave),
1901 	DEF_CMD_ARG("powersavesleep", 	set80211powersavesleep),
1902 	DEF_CMD_ARG("wepmode",		set80211wepmode),
1903 	DEF_CMD("wep",		1,	set80211wep),
1904 	DEF_CMD("-wep",		0,	set80211wep),
1905 	DEF_CMD_ARG("deftxkey",		set80211weptxkey),
1906 	DEF_CMD_ARG("weptxkey",		set80211weptxkey),
1907 	DEF_CMD_ARG("wepkey",		set80211wepkey),
1908 	DEF_CMD_ARG("nwkey",		set80211nwkey),		/* NetBSD */
1909 	DEF_CMD("-nwkey",	0,	set80211wep),		/* NetBSD */
1910 	DEF_CMD_ARG("rtsthreshold",	set80211rtsthreshold),
1911 	DEF_CMD_ARG("protmode",		set80211protmode),
1912 	DEF_CMD_ARG("txpower",		set80211txpower),
1913 	DEF_CMD_ARG("roaming",		set80211roaming),
1914 	DEF_CMD("wme",		1,	set80211wme),
1915 	DEF_CMD("-wme",		0,	set80211wme),
1916 	DEF_CMD("hidessid",	1,	set80211hidessid),
1917 	DEF_CMD("-hidessid",	0,	set80211hidessid),
1918 	DEF_CMD("apbridge",	1,	set80211apbridge),
1919 	DEF_CMD("-apbridge",	0,	set80211apbridge),
1920 	DEF_CMD_ARG("chanlist",		set80211chanlist),
1921 	DEF_CMD_ARG("bssid",		set80211bssid),
1922 	DEF_CMD_ARG("ap",		set80211bssid),
1923 	DEF_CMD("scan",	0,		set80211scan),
1924 	DEF_CMD_ARG("list",		set80211list),
1925 	DEF_CMD_ARG2("cwmin",		set80211cwmin),
1926 	DEF_CMD_ARG2("cwmax",		set80211cwmax),
1927 	DEF_CMD_ARG2("aifs",		set80211aifs),
1928 	DEF_CMD_ARG2("txoplimit",	set80211txoplimit),
1929 	DEF_CMD_ARG("acm",		set80211acm),
1930 	DEF_CMD_ARG("-acm",		set80211noacm),
1931 	DEF_CMD_ARG("ack",		set80211ackpolicy),
1932 	DEF_CMD_ARG("-ack",		set80211noackpolicy),
1933 	DEF_CMD_ARG2("bss:cwmin",	set80211bsscwmin),
1934 	DEF_CMD_ARG2("bss:cwmax",	set80211bsscwmax),
1935 	DEF_CMD_ARG2("bss:aifs",	set80211bssaifs),
1936 	DEF_CMD_ARG2("bss:txoplimit",	set80211bsstxoplimit),
1937 	DEF_CMD_ARG("dtimperiod",	set80211dtimperiod),
1938 	DEF_CMD_ARG("bintval",		set80211bintval),
1939 	DEF_CMD("mac:open",	IEEE80211_MACCMD_POLICY_OPEN,	set80211maccmd),
1940 	DEF_CMD("mac:allow",	IEEE80211_MACCMD_POLICY_ALLOW,	set80211maccmd),
1941 	DEF_CMD("mac:deny",	IEEE80211_MACCMD_POLICY_DENY,	set80211maccmd),
1942 	DEF_CMD("mac:flush",	IEEE80211_MACCMD_FLUSH,		set80211maccmd),
1943 	DEF_CMD("mac:detach",	IEEE80211_MACCMD_DETACH,	set80211maccmd),
1944 	DEF_CMD_ARG("mac:add",		set80211addmac),
1945 	DEF_CMD_ARG("mac:del",		set80211delmac),
1946 	DEF_CMD_ARG("mac:kick",		set80211kickmac),
1947 	DEF_CMD("pureg",	1,	set80211pureg),
1948 	DEF_CMD("-pureg",	0,	set80211pureg),
1949 	DEF_CMD_ARG("mcastrate",	set80211mcastrate),
1950 	DEF_CMD_ARG("fragthreshold",	set80211fragthreshold),
1951 	DEF_CMD("burst",	1,	set80211burst),
1952 	DEF_CMD("-burst",	0,	set80211burst),
1953 };
1954 static struct afswtch af_ieee80211 = {
1955 	.af_name	= "af_ieee80211",
1956 	.af_af		= AF_UNSPEC,
1957 	.af_other_status = ieee80211_status,
1958 };
1959 
1960 static __constructor void
1961 ieee80211_ctor(void)
1962 {
1963 #define	N(a)	(sizeof(a) / sizeof(a[0]))
1964 	int i;
1965 
1966 	for (i = 0; i < N(ieee80211_cmds);  i++)
1967 		cmd_register(&ieee80211_cmds[i]);
1968 	af_register(&af_ieee80211);
1969 #undef N
1970 }
1971