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