xref: /dragonfly/sbin/ifconfig/ifieee80211.c (revision 35e996c9)
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: head/sbin/ifconfig/ifieee80211.c 203970 2010-02-16 21:39:20Z imp $
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  *
47  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57  * POSSIBILITY OF SUCH DAMAGE.
58  */
59 
60 #include <sys/param.h>
61 #include <sys/ioctl.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
64 #include <sys/time.h>
65 
66 #include <net/ethernet.h>
67 #include <net/if.h>
68 #include <net/if_dl.h>
69 #include <net/if_types.h>
70 #include <net/if_media.h>
71 #include <net/route.h>
72 
73 #include <netproto/802_11/ieee80211_ioctl.h>
74 #include <netproto/802_11/ieee80211_dragonfly.h>
75 #include <netproto/802_11/ieee80211_superg.h>
76 #include <netproto/802_11/ieee80211_tdma.h>
77 #include <netproto/802_11/ieee80211_mesh.h>
78 #include <netproto/802_11/ieee80211_wps.h>
79 
80 #include <assert.h>
81 #include <ctype.h>
82 #include <err.h>
83 #include <errno.h>
84 #include <fcntl.h>
85 #include <inttypes.h>
86 #include <langinfo.h>
87 #include <locale.h>
88 #include <stdarg.h>
89 #include <stdbool.h>
90 #include <stddef.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <unistd.h>
95 
96 #include "ifconfig.h"
97 #include "regdomain.h"
98 
99 #ifndef IEEE80211_FIXED_RATE_NONE
100 #define	IEEE80211_FIXED_RATE_NONE	0xff
101 #endif
102 
103 /* XXX need these publicly defined or similar */
104 #ifndef IEEE80211_NODE_AUTH
105 #define	IEEE80211_NODE_AUTH	0x000001	/* authorized for data */
106 #define	IEEE80211_NODE_QOS	0x000002	/* QoS enabled */
107 #define	IEEE80211_NODE_ERP	0x000004	/* ERP enabled */
108 #define	IEEE80211_NODE_PWR_MGT	0x000010	/* power save mode enabled */
109 #define	IEEE80211_NODE_AREF	0x000020	/* authentication ref held */
110 #define	IEEE80211_NODE_HT	0x000040	/* HT enabled */
111 #define	IEEE80211_NODE_HTCOMPAT	0x000080	/* HT setup w/ vendor OUI's */
112 #define	IEEE80211_NODE_WPS	0x000100	/* WPS association */
113 #define	IEEE80211_NODE_TSN	0x000200	/* TSN association */
114 #define	IEEE80211_NODE_AMPDU_RX	0x000400	/* AMPDU rx enabled */
115 #define	IEEE80211_NODE_AMPDU_TX	0x000800	/* AMPDU tx enabled */
116 #define	IEEE80211_NODE_MIMO_PS	0x001000	/* MIMO power save enabled */
117 #define	IEEE80211_NODE_MIMO_RTS	0x002000	/* send RTS in MIMO PS */
118 #define	IEEE80211_NODE_RIFS	0x004000	/* RIFS enabled */
119 #define	IEEE80211_NODE_SGI20	0x008000	/* Short GI in HT20 enabled */
120 #define	IEEE80211_NODE_SGI40	0x010000	/* Short GI in HT40 enabled */
121 #define	IEEE80211_NODE_ASSOCID	0x020000	/* xmit requires associd */
122 #define	IEEE80211_NODE_AMSDU_RX	0x040000	/* AMSDU rx enabled */
123 #define	IEEE80211_NODE_AMSDU_TX	0x080000	/* AMSDU tx enabled */
124 #endif
125 
126 #define	MAXCHAN	1536		/* max 1.5K channels */
127 
128 #define	MAXCOL	78
129 static	int col;
130 static	char spacer;
131 
132 static void LINE_INIT(char c);
133 static void LINE_BREAK(void);
134 static void LINE_CHECK(const char *fmt, ...) __printflike(1, 2);
135 
136 static const char *modename[IEEE80211_MODE_MAX] = {
137 	[IEEE80211_MODE_AUTO]	  = "auto",
138 	[IEEE80211_MODE_11A]	  = "11a",
139 	[IEEE80211_MODE_11B]	  = "11b",
140 	[IEEE80211_MODE_11G]	  = "11g",
141 	[IEEE80211_MODE_FH]	  = "fh",
142 	[IEEE80211_MODE_TURBO_A]  = "turboA",
143 	[IEEE80211_MODE_TURBO_G]  = "turboG",
144 	[IEEE80211_MODE_STURBO_A] = "sturbo",
145 	[IEEE80211_MODE_11NA]	  = "11na",
146 	[IEEE80211_MODE_11NG]	  = "11ng",
147 	[IEEE80211_MODE_HALF]	  = "half",
148 	[IEEE80211_MODE_QUARTER]  = "quarter"
149 };
150 
151 static void set80211(int s, int type, int val, int len, void *data);
152 static int get80211(int s, int type, void *data, int len);
153 static int get80211len(int s, int type, void *data, size_t len, size_t *plen);
154 static int get80211val(int s, int type, int *val);
155 static const char *get_string(const char *val, const char *sep,
156     u_int8_t *buf, int *lenp);
157 static void print_string(const u_int8_t *buf, int len);
158 static void print_regdomain(const struct ieee80211_regdomain *, int);
159 static void print_channels(int, const struct ieee80211req_chaninfo *,
160     bool allchans, bool verbose);
161 static void regdomain_makechannels(struct ieee80211_regdomain_req *,
162     const struct ieee80211_devcaps_req *);
163 static const char *mesh_linkstate_string(uint8_t state);
164 
165 static struct ieee80211req_chaninfo *chaninfo;
166 static struct ieee80211_regdomain regdomain;
167 static int gotregdomain = 0;
168 static struct ieee80211_roamparams_req roamparams;
169 static int gotroam = 0;
170 static struct ieee80211_txparams_req txparams;
171 static int gottxparams = 0;
172 static struct ieee80211_channel curchan;
173 static int gotcurchan = 0;
174 static struct ifmediareq *ifmedia;
175 static int htconf = 0;
176 static int gothtconf = 0;
177 
178 static int
179 iseq(const char *a, const char *b)
180 {
181 	return (strcasecmp(a, b) == 0);
182 }
183 
184 static int
185 ismatch(const char *a, const char *b)
186 {
187 	return (strncasecmp(a, b, strlen(b)) == 0);
188 }
189 
190 static void
191 gethtconf(int s)
192 {
193 	if (gothtconf)
194 		return;
195 	if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0)
196 		warn("unable to get HT configuration information");
197 	gothtconf = 1;
198 }
199 
200 /*
201  * Collect channel info from the kernel.  We use this (mostly)
202  * to handle mapping between frequency and IEEE channel number.
203  */
204 static void
205 getchaninfo(int s)
206 {
207 	if (chaninfo != NULL)
208 		return;
209 	chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
210 	if (chaninfo == NULL)
211 		errx(1, "no space for channel list");
212 	if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo,
213 		     IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
214 		err(1, "unable to get channel information");
215 	ifmedia = ifmedia_getstate(s);
216 	gethtconf(s);
217 }
218 
219 static struct regdata *
220 getregdata(void)
221 {
222 	static struct regdata *rdp = NULL;
223 
224 	if (rdp == NULL) {
225 		rdp = lib80211_alloc_regdata();
226 		if (rdp == NULL)
227 			errx(-1, "missing or corrupted regdomain database");
228 	}
229 	return rdp;
230 }
231 
232 /*
233  * Given the channel at index i with attributes from,
234  * check if there is a channel with attributes to in
235  * the channel table.  With suitable attributes this
236  * allows the caller to look for promotion; e.g. from
237  * 11b > 11g.
238  */
239 static int
240 canpromote(u_int i, uint32_t from, uint32_t to)
241 {
242 	const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
243 	u_int j;
244 
245 	if ((fc->ic_flags & from) != from)
246 		return i;
247 	/* NB: quick check exploiting ordering of chans w/ same frequency */
248 	if (i+1 < chaninfo->ic_nchans &&
249 	    chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
250 	    (chaninfo->ic_chans[i+1].ic_flags & to) == to)
251 		return i+1;
252 	/* brute force search in case channel list is not ordered */
253 	for (j = 0; j < chaninfo->ic_nchans; j++) {
254 		const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
255 		if (j != i &&
256 		    tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
257 		return j;
258 	}
259 	return i;
260 }
261 
262 /*
263  * Handle channel promotion.  When a channel is specified with
264  * only a frequency we want to promote it to the ``best'' channel
265  * available.  The channel list has separate entries for 11b, 11g,
266  * 11a, and 11n[ga] channels so specifying a frequency w/o any
267  * attributes requires we upgrade, e.g. from 11b -> 11g.  This
268  * gets complicated when the channel is specified on the same
269  * command line with a media request that constrains the available
270  * channe list (e.g. mode 11a); we want to honor that to avoid
271  * confusing behaviour.
272  */
273 static int
274 promote(int i)
275 {
276 	/*
277 	 * Query the current mode of the interface in case it's
278 	 * constrained (e.g. to 11a).  We must do this carefully
279 	 * as there may be a pending ifmedia request in which case
280 	 * asking the kernel will give us the wrong answer.  This
281 	 * is an unfortunate side-effect of the way ifconfig is
282 	 * structure for modularity (yech).
283 	 *
284 	 * NB: ifmedia is actually setup in getchaninfo (above); we
285 	 *     assume it's called coincident with to this call so
286 	 *     we have a ``current setting''; otherwise we must pass
287 	 *     the socket descriptor down to here so we can make
288 	 *     the ifmedia_getstate call ourselves.
289 	 */
290 	int chanmode = (ifmedia != NULL ?
291 			IFM_MODE(ifmedia->ifm_current) :
292 			IFM_AUTO);
293 
294 	/* when ambiguous promote to ``best'' */
295 	/* NB: we abitrarily pick HT40+ over HT40- */
296 	if (chanmode != IFM_IEEE80211_11B)
297 		i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
298 	if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
299 		i = canpromote(i, IEEE80211_CHAN_G,
300 			IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
301 		if (htconf & 2) {
302 			i = canpromote(i, IEEE80211_CHAN_G,
303 				IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
304 			i = canpromote(i, IEEE80211_CHAN_G,
305 				IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
306 		}
307 	}
308 	if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
309 		i = canpromote(i, IEEE80211_CHAN_A,
310 			IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
311 		if (htconf & 2) {
312 			i = canpromote(i, IEEE80211_CHAN_A,
313 				IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
314 			i = canpromote(i, IEEE80211_CHAN_A,
315 				IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
316 		}
317 	}
318 	return i;
319 }
320 
321 static void
322 mapfreq(struct ieee80211_channel *chan, uint16_t freq, uint32_t flags)
323 {
324 	u_int i;
325 
326 	for (i = 0; i < chaninfo->ic_nchans; i++) {
327 		const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
328 
329 		if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
330 			if (flags == 0) {
331 				/* when ambiguous promote to ``best'' */
332 				c = &chaninfo->ic_chans[promote(i)];
333 			}
334 			*chan = *c;
335 			return;
336 		}
337 	}
338 	errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
339 }
340 
341 static void
342 mapchan(struct ieee80211_channel *chan, uint8_t ieee, uint32_t flags)
343 {
344 	u_int i;
345 
346 	for (i = 0; i < chaninfo->ic_nchans; i++) {
347 		const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
348 
349 		if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
350 			if (flags == 0) {
351 				/* when ambiguous promote to ``best'' */
352 				c = &chaninfo->ic_chans[promote(i)];
353 			}
354 			*chan = *c;
355 			return;
356 		}
357 	}
358 	errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
359 }
360 
361 static const struct ieee80211_channel *
362 getcurchan(int s)
363 {
364 	if (gotcurchan)
365 		return &curchan;
366 	if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
367 		int val;
368 		/* fall back to legacy ioctl */
369 		if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
370 			err(-1, "cannot figure out current channel");
371 		getchaninfo(s);
372 		mapchan(&curchan, val, 0);
373 	}
374 	gotcurchan = 1;
375 	return &curchan;
376 }
377 
378 static enum ieee80211_phymode
379 chan2mode(const struct ieee80211_channel *c)
380 {
381 	if (IEEE80211_IS_CHAN_HTA(c))
382 		return IEEE80211_MODE_11NA;
383 	if (IEEE80211_IS_CHAN_HTG(c))
384 		return IEEE80211_MODE_11NG;
385 	if (IEEE80211_IS_CHAN_108A(c))
386 		return IEEE80211_MODE_TURBO_A;
387 	if (IEEE80211_IS_CHAN_108G(c))
388 		return IEEE80211_MODE_TURBO_G;
389 	if (IEEE80211_IS_CHAN_ST(c))
390 		return IEEE80211_MODE_STURBO_A;
391 	if (IEEE80211_IS_CHAN_FHSS(c))
392 		return IEEE80211_MODE_FH;
393 	if (IEEE80211_IS_CHAN_HALF(c))
394 		return IEEE80211_MODE_HALF;
395 	if (IEEE80211_IS_CHAN_QUARTER(c))
396 		return IEEE80211_MODE_QUARTER;
397 	if (IEEE80211_IS_CHAN_A(c))
398 		return IEEE80211_MODE_11A;
399 	if (IEEE80211_IS_CHAN_ANYG(c))
400 		return IEEE80211_MODE_11G;
401 	if (IEEE80211_IS_CHAN_B(c))
402 		return IEEE80211_MODE_11B;
403 	return IEEE80211_MODE_AUTO;
404 }
405 
406 static void
407 getroam(int s)
408 {
409 	if (gotroam)
410 		return;
411 	if (get80211(s, IEEE80211_IOC_ROAM,
412 	    &roamparams, sizeof(roamparams)) < 0)
413 		err(1, "unable to get roaming parameters");
414 	gotroam = 1;
415 }
416 
417 static void
418 setroam_cb(int s, void *arg)
419 {
420 	struct ieee80211_roamparams_req *roam = arg;
421 	set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam);
422 }
423 
424 static void
425 gettxparams(int s)
426 {
427 	if (gottxparams)
428 		return;
429 	if (get80211(s, IEEE80211_IOC_TXPARAMS,
430 	    &txparams, sizeof(txparams)) < 0)
431 		err(1, "unable to get transmit parameters");
432 	gottxparams = 1;
433 }
434 
435 static void
436 settxparams_cb(int s, void *arg)
437 {
438 	struct ieee80211_txparams_req *txp = arg;
439 	set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp);
440 }
441 
442 static void
443 getregdomain(int s)
444 {
445 	if (gotregdomain)
446 		return;
447 	if (get80211(s, IEEE80211_IOC_REGDOMAIN,
448 	    &regdomain, sizeof(regdomain)) < 0)
449 		err(1, "unable to get regulatory domain info");
450 	gotregdomain = 1;
451 }
452 
453 static void
454 getdevcaps(int s, struct ieee80211_devcaps_req *dc)
455 {
456 	if (get80211(s, IEEE80211_IOC_DEVCAPS, dc,
457 	    IEEE80211_DEVCAPS_SPACE(dc)) < 0)
458 		err(1, "unable to get device capabilities");
459 }
460 
461 static void
462 setregdomain_cb(int s, void *arg)
463 {
464 	struct ieee80211_regdomain_req *req;
465 	struct ieee80211_regdomain *rd = arg;
466 	struct ieee80211_devcaps_req *dc;
467 	struct regdata *rdp = getregdata();
468 
469 	if (rd->country != NO_COUNTRY) {
470 		const struct country *cc;
471 		/*
472 		 * Check current country seting to make sure it's
473 		 * compatible with the new regdomain.  If not, then
474 		 * override it with any default country for this
475 		 * SKU.  If we cannot arrange a match, then abort.
476 		 */
477 		cc = lib80211_country_findbycc(rdp, rd->country);
478 		if (cc == NULL)
479 			errx(1, "unknown ISO country code %d", rd->country);
480 		if (cc->rd->sku != rd->regdomain) {
481 			const struct regdomain *rp;
482 			/*
483 			 * Check if country is incompatible with regdomain.
484 			 * To enable multiple regdomains for a country code
485 			 * we permit a mismatch between the regdomain and
486 			 * the country's associated regdomain when the
487 			 * regdomain is setup w/o a default country.  For
488 			 * example, US is bound to the FCC regdomain but
489 			 * we allow US to be combined with FCC3 because FCC3
490 			 * has not default country.  This allows bogus
491 			 * combinations like FCC3+DK which are resolved when
492 			 * constructing the channel list by deferring to the
493 			 * regdomain to construct the channel list.
494 			 */
495 			rp = lib80211_regdomain_findbysku(rdp, rd->regdomain);
496 			if (rp == NULL)
497 				errx(1, "country %s (%s) is not usable with "
498 				    "regdomain %d", cc->isoname, cc->name,
499 				    rd->regdomain);
500 			else if (rp->cc != NULL && rp->cc != cc)
501 				errx(1, "country %s (%s) is not usable with "
502 				   "regdomain %s", cc->isoname, cc->name,
503 				   rp->name);
504 		}
505 	}
506 	/*
507 	 * Fetch the device capabilities and calculate the
508 	 * full set of netbands for which we request a new
509 	 * channel list be constructed.  Once that's done we
510 	 * push the regdomain info + channel list to the kernel.
511 	 */
512 	dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
513 	if (dc == NULL)
514 		errx(1, "no space for device capabilities");
515 	dc->dc_chaninfo.ic_nchans = MAXCHAN;
516 	getdevcaps(s, dc);
517 #if 0
518 	if (verbose) {
519 		printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
520 		printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
521 		printf("htcaps    : 0x%x\n", dc->dc_htcaps);
522 		memcpy(chaninfo, &dc->dc_chaninfo,
523 		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
524 		print_channels(s, &dc->dc_chaninfo, true /* allchans */,
525 		    true /* verbose */);
526 	}
527 #endif
528 	req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
529 	if (req == NULL)
530 		errx(1, "no space for regdomain request");
531 	req->rd = *rd;
532 	regdomain_makechannels(req, dc);
533 	if (verbose) {
534 		LINE_INIT(':');
535 		print_regdomain(rd, 1/*verbose*/);
536 		LINE_BREAK();
537 		/* blech, reallocate channel list for new data */
538 		if (chaninfo != NULL)
539 			free(chaninfo);
540 		chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
541 		if (chaninfo == NULL)
542 			errx(1, "no space for channel list");
543 		memcpy(chaninfo, &req->chaninfo,
544 		    IEEE80211_CHANINFO_SPACE(&req->chaninfo));
545 		print_channels(s, &req->chaninfo, true /* allchans */,
546 		    true /* verbose */);
547 	}
548 	if (req->chaninfo.ic_nchans == 0)
549 		errx(1, "no channels calculated");
550 	set80211(s, IEEE80211_IOC_REGDOMAIN, 0,
551 	    IEEE80211_REGDOMAIN_SPACE(req), req);
552 	free(req);
553 	free(dc);
554 }
555 
556 static int
557 ieee80211_mhz2ieee(int freq, int flags)
558 {
559 	struct ieee80211_channel chan;
560 	mapfreq(&chan, freq, flags);
561 	return chan.ic_ieee;
562 }
563 
564 static int
565 isanyarg(const char *arg)
566 {
567 	return (ismatch(arg, "-") ||
568 		ismatch(arg, "any") ||
569 		ismatch(arg, "off"));
570 }
571 
572 static void
573 set80211ssid(const char *val, int d __unused, int s,
574 	     const struct afswtch *rafp __unused)
575 {
576 	int		ssid;
577 	int		len;
578 	u_int8_t	data[IEEE80211_NWID_LEN];
579 
580 	ssid = 0;
581 	len = strlen(val);
582 	if (len > 2 && isdigit((int)val[0]) && val[1] == ':') {
583 		ssid = atoi(val)-1;
584 		val += 2;
585 	}
586 
587 	memset(data, 0, sizeof(data));
588 	len = (int)sizeof(data);
589 	if (get_string(val, NULL, data, &len) == NULL)
590 		exit(1);
591 
592 	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
593 }
594 
595 static void
596 set80211meshid(const char *val, int d __unused, int s,
597 	       const struct afswtch *rafp __unused)
598 {
599 	int		len;
600 	u_int8_t	data[IEEE80211_NWID_LEN];
601 
602 	memset(data, 0, sizeof(data));
603 	len = sizeof(data);
604 	if (get_string(val, NULL, data, &len) == NULL)
605 		exit(1);
606 
607 	set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data);
608 }
609 
610 static void
611 set80211stationname(const char *val, int d __unused, int s,
612 		    const struct afswtch *rafp __unused)
613 {
614 	int		len;
615 	u_int8_t	data[33];
616 
617 	memset(data, 0, sizeof(data));
618 	len = (int)sizeof(data);
619 	get_string(val, NULL, data, &len);
620 
621 	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
622 }
623 
624 /*
625  * Parse a channel specification for attributes/flags.
626  * The syntax is:
627  *	freq/xx		channel width (5,10,20,40,40+,40-)
628  *	freq:mode	channel mode (a,b,g,h,n,t,s,d)
629  *
630  * These can be combined in either order; e.g. 2437:ng/40.
631  * Modes are case insensitive.
632  *
633  * The result is not validated here; it's assumed to be
634  * checked against the channel table fetched from the kernel.
635  */
636 static int
637 getchannelflags(const char *val, int freq)
638 {
639 #define	_CHAN_HT	0x80000000
640 	const char *cp;
641 	int flags;
642 
643 	flags = 0;
644 
645 	cp = strchr(val, ':');
646 	if (cp != NULL) {
647 		for (cp++; isalpha((int) *cp); cp++) {
648 			/* accept mixed case */
649 			int c = *cp;
650 			if (isupper(c))
651 				c = tolower(c);
652 			switch (c) {
653 			case 'a':		/* 802.11a */
654 				flags |= IEEE80211_CHAN_A;
655 				break;
656 			case 'b':		/* 802.11b */
657 				flags |= IEEE80211_CHAN_B;
658 				break;
659 			case 'g':		/* 802.11g */
660 				flags |= IEEE80211_CHAN_G;
661 				break;
662 			case 'h':		/* ht = 802.11n */
663 			case 'n':		/* 802.11n */
664 				flags |= _CHAN_HT;	/* NB: private */
665 				break;
666 			case 'd':		/* dt = Atheros Dynamic Turbo */
667 				flags |= IEEE80211_CHAN_TURBO;
668 				break;
669 			case 't':		/* ht, dt, st, t */
670 				/* dt and unadorned t specify Dynamic Turbo */
671 				if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
672 					flags |= IEEE80211_CHAN_TURBO;
673 				break;
674 			case 's':		/* st = Atheros Static Turbo */
675 				flags |= IEEE80211_CHAN_STURBO;
676 				break;
677 			default:
678 				errx(-1, "%s: Invalid channel attribute %c\n",
679 				    val, *cp);
680 			}
681 		}
682 	}
683 	cp = strchr(val, '/');
684 	if (cp != NULL) {
685 		char *ep;
686 		u_long cw = strtoul(cp+1, &ep, 10);
687 
688 		switch (cw) {
689 		case 5:
690 			flags |= IEEE80211_CHAN_QUARTER;
691 			break;
692 		case 10:
693 			flags |= IEEE80211_CHAN_HALF;
694 			break;
695 		case 20:
696 			/* NB: this may be removed below */
697 			flags |= IEEE80211_CHAN_HT20;
698 			break;
699 		case 40:
700 			if (ep != NULL && *ep == '+')
701 				flags |= IEEE80211_CHAN_HT40U;
702 			else if (ep != NULL && *ep == '-')
703 				flags |= IEEE80211_CHAN_HT40D;
704 			break;
705 		default:
706 			errx(-1, "%s: Invalid channel width\n", val);
707 		}
708 	}
709 	/*
710 	 * Cleanup specifications.
711 	 */
712 	if ((flags & _CHAN_HT) == 0) {
713 		/*
714 		 * If user specified freq/20 or freq/40 quietly remove
715 		 * HT cw attributes depending on channel use.  To give
716 		 * an explicit 20/40 width for an HT channel you must
717 		 * indicate it is an HT channel since all HT channels
718 		 * are also usable for legacy operation; e.g. freq:n/40.
719 		 */
720 		flags &= ~IEEE80211_CHAN_HT;
721 	} else {
722 		/*
723 		 * Remove private indicator that this is an HT channel
724 		 * and if no explicit channel width has been given
725 		 * provide the default settings.
726 		 */
727 		flags &= ~_CHAN_HT;
728 		if ((flags & IEEE80211_CHAN_HT) == 0) {
729 			struct ieee80211_channel chan;
730 			/*
731 			 * Consult the channel list to see if we can use
732 			 * HT40+ or HT40- (if both the map routines choose).
733 			 */
734 			if (freq > 255)
735 				mapfreq(&chan, freq, 0);
736 			else
737 				mapchan(&chan, freq, 0);
738 			flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
739 		}
740 	}
741 	return flags;
742 #undef _CHAN_HT
743 }
744 
745 static void
746 getchannel(int s, struct ieee80211_channel *chan, const char *val)
747 {
748 	int v, flags;
749 	char *eptr;
750 
751 	memset(chan, 0, sizeof(*chan));
752 	if (isanyarg(val)) {
753 		chan->ic_freq = IEEE80211_CHAN_ANY;
754 		return;
755 	}
756 	getchaninfo(s);
757 	errno = 0;
758 	v = strtol(val, &eptr, 10);
759 	if (val[0] == '\0' || val == eptr || errno == ERANGE ||
760 	    /* channel may be suffixed with nothing, :flag, or /width */
761 	    (eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/'))
762 		errx(1, "invalid channel specification%s",
763 		    errno == ERANGE ? " (out of range)" : "");
764 	flags = getchannelflags(val, v);
765 	if (v > 255) {		/* treat as frequency */
766 		mapfreq(chan, v, flags);
767 	} else {
768 		mapchan(chan, v, flags);
769 	}
770 }
771 
772 static void
773 set80211channel(const char *val, int d __unused, int s,
774 		const struct afswtch *rafp __unused)
775 {
776 	struct ieee80211_channel chan;
777 
778 	getchannel(s, &chan, val);
779 	set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
780 }
781 
782 static void
783 set80211chanswitch(const char *val, int d __unused, int s,
784 		   const struct afswtch *rafp __unused)
785 {
786 	struct ieee80211_chanswitch_req csr;
787 
788 	getchannel(s, &csr.csa_chan, val);
789 	csr.csa_mode = 1;
790 	csr.csa_count = 5;
791 	set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr);
792 }
793 
794 static void
795 set80211authmode(const char *val, int d __unused, int s,
796 		 const struct afswtch *rafp __unused)
797 {
798 	int	mode;
799 
800 	if (iseq(val, "none")) {
801 		mode = IEEE80211_AUTH_NONE;
802 	} else if (iseq(val, "open")) {
803 		mode = IEEE80211_AUTH_OPEN;
804 	} else if (iseq(val, "shared")) {
805 		mode = IEEE80211_AUTH_SHARED;
806 	} else if (iseq(val, "8021x")) {
807 		mode = IEEE80211_AUTH_8021X;
808 	} else if (iseq(val, "wpa")) {
809 		mode = IEEE80211_AUTH_WPA;
810 	} else {
811 		errx(1, "unknown authmode");
812 	}
813 
814 	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
815 }
816 
817 static void
818 set80211powersavemode(const char *val, int d __unused, int s,
819 		      const struct afswtch *rafp __unused)
820 {
821 	int	mode;
822 
823 	if (iseq(val, "off")) {
824 		mode = IEEE80211_POWERSAVE_OFF;
825 	} else if (iseq(val, "on")) {
826 		mode = IEEE80211_POWERSAVE_ON;
827 	} else if (iseq(val, "cam")) {
828 		mode = IEEE80211_POWERSAVE_CAM;
829 	} else if (iseq(val, "psp")) {
830 		mode = IEEE80211_POWERSAVE_PSP;
831 	} else if (iseq(val, "psp-cam")) {
832 		mode = IEEE80211_POWERSAVE_PSP_CAM;
833 	} else {
834 		errx(1, "unknown powersavemode");
835 	}
836 
837 	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
838 }
839 
840 static void
841 set80211powersave(const char *val __unused, int d, int s,
842 		  const struct afswtch *rafp __unused)
843 {
844 	set80211(s, IEEE80211_IOC_POWERSAVE,
845 		 (d == 0 ? IEEE80211_POWERSAVE_OFF : IEEE80211_POWERSAVE_ON),
846 		 0, NULL);
847 }
848 
849 static void
850 set80211powersavesleep(const char *val, int d __unused, int s,
851 		       const struct afswtch *rafp __unused)
852 {
853 	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
854 }
855 
856 static void
857 set80211wepmode(const char *val, int d __unused, int s,
858 		const struct afswtch *rafp __unused)
859 {
860 	int	mode;
861 
862 	if (iseq(val, "off")) {
863 		mode = IEEE80211_WEP_OFF;
864 	} else if (iseq(val, "on")) {
865 		mode = IEEE80211_WEP_ON;
866 	} else if (iseq(val, "mixed")) {
867 		mode = IEEE80211_WEP_MIXED;
868 	} else {
869 		errx(1, "unknown wep mode");
870 	}
871 
872 	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
873 }
874 
875 static void
876 set80211wep(const char *val __unused, int d, int s,
877 	    const struct afswtch *rafp __unused)
878 {
879 	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
880 }
881 
882 static int
883 isundefarg(const char *arg)
884 {
885 	return (strcmp(arg, "-") == 0 || ismatch(arg, "undef"));
886 }
887 
888 static void
889 set80211weptxkey(const char *val, int d __unused, int s,
890 		 const struct afswtch *rafp __unused)
891 {
892 	set80211(s, IEEE80211_IOC_WEPTXKEY,
893 		 (isundefarg(val) ? IEEE80211_KEYIX_NONE : atoi(val)-1),
894 		 0, NULL);
895 }
896 
897 static void
898 set80211wepkey(const char *val, int d __unused, int s,
899 	       const struct afswtch *rafp __unused)
900 {
901 	int		key = 0;
902 	int		len;
903 	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
904 
905 	if (isdigit((int)val[0]) && val[1] == ':') {
906 		key = atoi(val)-1;
907 		val += 2;
908 	}
909 
910 	memset(data, 0, sizeof(data));
911 	len = (int)sizeof(data);
912 	get_string(val, NULL, data, &len);
913 
914 	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
915 }
916 
917 /*
918  * This function is purely a NetBSD compatibility interface.  The NetBSD
919  * interface is too inflexible, but it's there so we'll support it since
920  * it's not all that hard.
921  */
922 static void
923 set80211nwkey(const char *val, int d __unused, int s,
924 	      const struct afswtch *rafp __unused)
925 {
926 	int		txkey;
927 	int		i, len;
928 	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
929 
930 	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
931 
932 	if (isdigit((int)val[0]) && val[1] == ':') {
933 		txkey = val[0]-'0'-1;
934 		val += 2;
935 
936 		for (i = 0; i < 4; i++) {
937 			memset(data, 0, sizeof(data));
938 			len = (int)sizeof(data);
939 			val = get_string(val, ",", data, &len);
940 			if (val == NULL)
941 				exit(1);
942 
943 			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
944 		}
945 	} else {
946 		memset(data, 0, sizeof(data));
947 		len = (int)sizeof(data);
948 		get_string(val, NULL, data, &len);
949 		txkey = 0;
950 
951 		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
952 
953 		memset(data, 0, sizeof(data));
954 		for (i = 1; i < 4; i++)
955 			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
956 	}
957 
958 	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
959 }
960 
961 static void
962 set80211rtsthreshold(const char *val, int d __unused, int s,
963 		     const struct afswtch *rafp __unused)
964 {
965 	set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
966 		 (isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val)),
967 		 0, NULL);
968 }
969 
970 static void
971 set80211protmode(const char *val, int d __unused, int s,
972 		 const struct afswtch *rafp __unused)
973 {
974 	int	mode;
975 
976 	if (iseq(val, "off")) {
977 		mode = IEEE80211_PROTMODE_OFF;
978 	} else if (iseq(val, "cts")) {
979 		mode = IEEE80211_PROTMODE_CTS;
980 	} else if (ismatch(val, "rts")) {
981 		mode = IEEE80211_PROTMODE_RTSCTS;
982 	} else {
983 		errx(1, "unknown protection mode");
984 	}
985 
986 	set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
987 }
988 
989 static void
990 set80211htprotmode(const char *val, int d __unused, int s,
991 		   const struct afswtch *rafp __unused)
992 {
993 	int	mode;
994 
995 	if (iseq(val, "off")) {
996 		mode = IEEE80211_PROTMODE_OFF;
997 	} else if (ismatch(val, "rts")) {
998 		mode = IEEE80211_PROTMODE_RTSCTS;
999 	} else {
1000 		errx(1, "unknown protection mode");
1001 	}
1002 
1003 	set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
1004 }
1005 
1006 static void
1007 set80211txpower(const char *val, int d __unused, int s,
1008 		const struct afswtch *rafp __unused)
1009 {
1010 	double v = atof(val);
1011 	int txpow;
1012 
1013 	txpow = (int) (2*v);
1014 	if (txpow != 2*v)
1015 		errx(-1, "invalid tx power (must be .5 dBm units)");
1016 	set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
1017 }
1018 
1019 #define	IEEE80211_ROAMING_DEVICE	0
1020 #define	IEEE80211_ROAMING_AUTO		1
1021 #define	IEEE80211_ROAMING_MANUAL	2
1022 
1023 static void
1024 set80211roaming(const char *val, int d __unused, int s,
1025 		const struct afswtch *rafp __unused)
1026 {
1027 	int mode;
1028 
1029 	if (iseq(val, "device")) {
1030 		mode = IEEE80211_ROAMING_DEVICE;
1031 	} else if (iseq(val, "auto")) {
1032 		mode = IEEE80211_ROAMING_AUTO;
1033 	} else if (iseq(val, "manual")) {
1034 		mode = IEEE80211_ROAMING_MANUAL;
1035 	} else {
1036 		errx(1, "unknown roaming mode");
1037 	}
1038 	set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
1039 }
1040 
1041 static void
1042 set80211wme(const char *val __unused, int d, int s,
1043 	    const struct afswtch *rafp __unused)
1044 {
1045 	set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
1046 }
1047 
1048 static void
1049 set80211hidessid(const char *val __unused, int d, int s,
1050 		 const struct afswtch *rafp __unused)
1051 {
1052 	set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
1053 }
1054 
1055 static void
1056 set80211apbridge(const char *val __unused, int d, int s,
1057 		 const struct afswtch *rafp __unused)
1058 {
1059 	set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
1060 }
1061 
1062 static void
1063 set80211fastframes(const char *val __unused, int d __unused, int s,
1064 		   const struct afswtch *rafp __unused)
1065 {
1066 	set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
1067 }
1068 
1069 static void
1070 set80211dturbo(const char *val __unused, int d, int s,
1071 	       const struct afswtch *rafp __unused)
1072 {
1073 	set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
1074 }
1075 
1076 static void
1077 set80211chanlist(const char *val, int d __unused, int s,
1078 		 const struct afswtch *rafp __unused)
1079 {
1080 	struct ieee80211req_chanlist chanlist;
1081 	char *temp, *cp, *tp;
1082 
1083 	temp = strdup(val);
1084 	if (temp == NULL)
1085 		errx(1, "strdup failed");
1086 	memset(&chanlist, 0, sizeof(chanlist));
1087 	cp = temp;
1088 	for (;;) {
1089 		int first, last, f, c;
1090 
1091 		tp = strchr(cp, ',');
1092 		if (tp != NULL)
1093 			*tp++ = '\0';
1094 		switch (sscanf(cp, "%u-%u", &first, &last)) {
1095 		case 1:
1096 			if (first > IEEE80211_CHAN_MAX)
1097 				errx(-1, "channel %u out of range, max %u",
1098 					first, IEEE80211_CHAN_MAX);
1099 			setbit(chanlist.ic_channels, first);
1100 			break;
1101 		case 2:
1102 			if (first > IEEE80211_CHAN_MAX)
1103 				errx(-1, "channel %u out of range, max %u",
1104 					first, IEEE80211_CHAN_MAX);
1105 			if (last > IEEE80211_CHAN_MAX)
1106 				errx(-1, "channel %u out of range, max %u",
1107 					last, IEEE80211_CHAN_MAX);
1108 			if (first > last)
1109 				errx(-1, "void channel range, %u > %u",
1110 					first, last);
1111 			for (f = first; f <= last; f++)
1112 				setbit(chanlist.ic_channels, f);
1113 			break;
1114 		}
1115 		if (tp == NULL)
1116 			break;
1117 		c = *tp;
1118 		while (isspace(c))
1119 			tp++;
1120 		if (!isdigit(c))
1121 			break;
1122 		cp = tp;
1123 	}
1124 	set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
1125 }
1126 
1127 static void
1128 set80211bssid(const char *val, int d __unused, int s,
1129 	      const struct afswtch *rafp __unused)
1130 {
1131 	if (!isanyarg(val)) {
1132 		char *temp;
1133 		struct sockaddr_dl sdl;
1134 
1135 		temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1136 		if (temp == NULL)
1137 			errx(1, "malloc failed");
1138 		temp[0] = ':';
1139 		strcpy(temp + 1, val);
1140 		sdl.sdl_len = sizeof(sdl);
1141 		link_addr(temp, &sdl);
1142 		free(temp);
1143 		if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1144 			errx(1, "malformed link-level address");
1145 		set80211(s, IEEE80211_IOC_BSSID, 0,
1146 			IEEE80211_ADDR_LEN, LLADDR(&sdl));
1147 	} else {
1148 		uint8_t zerobssid[IEEE80211_ADDR_LEN];
1149 		memset(zerobssid, 0, sizeof(zerobssid));
1150 		set80211(s, IEEE80211_IOC_BSSID, 0,
1151 			IEEE80211_ADDR_LEN, zerobssid);
1152 	}
1153 }
1154 
1155 static int
1156 getac(const char *ac)
1157 {
1158 	if (iseq(ac, "ac_be") || iseq(ac, "be"))
1159 		return WME_AC_BE;
1160 	if (iseq(ac, "ac_bk") || iseq(ac, "bk"))
1161 		return WME_AC_BK;
1162 	if (iseq(ac, "ac_vi") || iseq(ac, "vi"))
1163 		return WME_AC_VI;
1164 	if (iseq(ac, "ac_vo") || iseq(ac, "vo"))
1165 		return WME_AC_VO;
1166 	errx(1, "unknown wme access class %s", ac);
1167 }
1168 
1169 static void
1170 set80211cwmin(const char *ac, const char *val, int s,
1171 	      const struct afswtch *afp __unused)
1172 {
1173 	set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
1174 }
1175 
1176 static void
1177 set80211cwmax(const char *ac, const char *val, int s,
1178 	      const struct afswtch *afp __unused)
1179 {
1180 	set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
1181 }
1182 
1183 static void
1184 set80211aifs(const char *ac, const char *val, int s,
1185 	     const struct afswtch *afp __unused)
1186 {
1187 	set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
1188 }
1189 
1190 static void
1191 set80211txoplimit(const char *ac, const char *val, int s,
1192 		  const struct afswtch *afp __unused)
1193 {
1194 	set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
1195 }
1196 
1197 static void
1198 set80211acm(const char *ac, int d __unused, int s,
1199 	    const struct afswtch *afp __unused)
1200 {
1201 	set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
1202 }
1203 
1204 static void
1205 set80211noacm(const char *ac, int d __unused, int s,
1206 	      const struct afswtch *afp __unused)
1207 {
1208 	set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
1209 }
1210 
1211 static void
1212 set80211ackpolicy(const char *ac, int d __unused, int s,
1213 		  const struct afswtch *afp __unused)
1214 {
1215 	set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
1216 }
1217 
1218 static void
1219 set80211noackpolicy(const char *ac, int d __unused, int s,
1220 		    const struct afswtch *afp __unused)
1221 {
1222 	set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
1223 }
1224 
1225 static void
1226 set80211bsscwmin(const char *ac, const char *val, int s,
1227 		 const struct afswtch *afp __unused)
1228 {
1229 	set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
1230 		 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1231 }
1232 
1233 static void
1234 set80211bsscwmax(const char *ac, const char *val, int s,
1235 		 const struct afswtch *afp __unused)
1236 {
1237 	set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
1238 		 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1239 }
1240 
1241 static void
1242 set80211bssaifs(const char *ac, const char *val, int s,
1243 		const struct afswtch *afp __unused)
1244 {
1245 	set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
1246 		 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1247 }
1248 
1249 static void
1250 set80211bsstxoplimit(const char *ac, const char *val, int s,
1251 		     const struct afswtch *afp __unused)
1252 {
1253 	set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
1254 		 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1255 }
1256 
1257 static void
1258 set80211dtimperiod(const char *val, int d __unused, int s,
1259 		   const struct afswtch *afp __unused)
1260 {
1261 	set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
1262 }
1263 
1264 static void
1265 set80211bintval(const char *val, int d __unused, int s,
1266 		const struct afswtch *afp __unused)
1267 {
1268 	set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
1269 }
1270 
1271 static void
1272 set80211macmac(int s, int op, const char *val)
1273 {
1274 	char *temp;
1275 	struct sockaddr_dl sdl;
1276 
1277 	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1278 	if (temp == NULL)
1279 		errx(1, "malloc failed");
1280 	temp[0] = ':';
1281 	strcpy(temp + 1, val);
1282 	sdl.sdl_len = sizeof(sdl);
1283 	link_addr(temp, &sdl);
1284 	free(temp);
1285 	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1286 		errx(1, "malformed link-level address");
1287 	set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
1288 }
1289 
1290 static void
1291 set80211addmac(const char *val, int d __unused, int s,
1292 	       const struct afswtch *afp __unused)
1293 {
1294 	set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
1295 }
1296 
1297 static void
1298 set80211delmac(const char *val, int d __unused, int s,
1299 	       const struct afswtch *afp __unused)
1300 {
1301 	set80211macmac(s, IEEE80211_IOC_DELMAC, val);
1302 }
1303 
1304 static void
1305 set80211kickmac(const char *val, int d __unused, int s,
1306 		const struct afswtch *afp __unused)
1307 {
1308 	char *temp;
1309 	struct sockaddr_dl sdl;
1310 	struct ieee80211req_mlme mlme;
1311 
1312 	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1313 	if (temp == NULL)
1314 		errx(1, "malloc failed");
1315 	temp[0] = ':';
1316 	strcpy(temp + 1, val);
1317 	sdl.sdl_len = sizeof(sdl);
1318 	link_addr(temp, &sdl);
1319 	free(temp);
1320 	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1321 		errx(1, "malformed link-level address");
1322 	memset(&mlme, 0, sizeof(mlme));
1323 	mlme.im_op = IEEE80211_MLME_DEAUTH;
1324 	mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
1325 	memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
1326 	set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
1327 }
1328 
1329 static void
1330 set80211maccmd(const char *val __unused, int d, int s,
1331 	       const struct afswtch *afp __unused)
1332 {
1333 	set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
1334 }
1335 
1336 static void
1337 set80211meshrtmac(int s, int req, const char *val)
1338 {
1339 	char *temp;
1340 	struct sockaddr_dl sdl;
1341 
1342 	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1343 	if (temp == NULL)
1344 		errx(1, "malloc failed");
1345 	temp[0] = ':';
1346 	strcpy(temp + 1, val);
1347 	sdl.sdl_len = sizeof(sdl);
1348 	link_addr(temp, &sdl);
1349 	free(temp);
1350 	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1351 		errx(1, "malformed link-level address");
1352 	set80211(s, IEEE80211_IOC_MESH_RTCMD, req,
1353 	    IEEE80211_ADDR_LEN, LLADDR(&sdl));
1354 }
1355 
1356 static void
1357 set80211addmeshrt(const char *val, int d __unused, int s,
1358 		  const struct afswtch *afp __unused)
1359 {
1360 	set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val);
1361 }
1362 
1363 static void
1364 set80211delmeshrt(const char *val, int d __unused, int s,
1365 		  const struct afswtch *afp __unused)
1366 {
1367 	set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val);
1368 }
1369 
1370 static void
1371 set80211meshrtcmd(const char *val __unused, int d, int s,
1372 		  const struct afswtch *afp __unused)
1373 {
1374 	set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL);
1375 }
1376 
1377 static void
1378 set80211hwmprootmode(const char *val, int d __unused, int s,
1379 		     const struct afswtch *afp __unused)
1380 {
1381 	int mode;
1382 
1383 	if (iseq(val, "normal"))
1384 		mode = IEEE80211_HWMP_ROOTMODE_NORMAL;
1385 	else if (iseq(val, "proactive"))
1386 		mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
1387 	else if (iseq(val, "rann"))
1388 		mode = IEEE80211_HWMP_ROOTMODE_RANN;
1389 	else
1390 		mode = IEEE80211_HWMP_ROOTMODE_DISABLED;
1391 	set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL);
1392 }
1393 
1394 static void
1395 set80211hwmpmaxhops(const char *val, int d __unused, int s,
1396 		    const struct afswtch *afp __unused)
1397 {
1398 	set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL);
1399 }
1400 
1401 static void
1402 set80211pureg(const char *val __unused, int d, int s,
1403 	      const struct afswtch *rafp __unused)
1404 {
1405 	set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
1406 }
1407 
1408 static void
1409 set80211bgscan(const char *val __unused, int d, int s,
1410 	       const struct afswtch *rafp __unused)
1411 {
1412 	set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
1413 }
1414 
1415 static void
1416 set80211bgscanidle(const char *val, int d __unused, int s,
1417 		   const struct afswtch *afp __unused)
1418 {
1419 	set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
1420 }
1421 
1422 static void
1423 set80211bgscanintvl(const char *val, int d __unused, int s,
1424 		    const struct afswtch *afp __unused)
1425 {
1426 	set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
1427 }
1428 
1429 static void
1430 set80211scanvalid(const char *val, int d __unused, int s,
1431 		  const struct afswtch *afp __unused)
1432 {
1433 	set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
1434 }
1435 
1436 /*
1437  * Parse an optional trailing specification of which netbands
1438  * to apply a parameter to.  This is basically the same syntax
1439  * as used for channels but you can concatenate to specify
1440  * multiple.  For example:
1441  *	14:abg		apply to 11a, 11b, and 11g
1442  *	6:ht		apply to 11na and 11ng
1443  * We don't make a big effort to catch silly things; this is
1444  * really a convenience mechanism.
1445  */
1446 static int
1447 getmodeflags(const char *val)
1448 {
1449 	const char *cp;
1450 	int flags;
1451 
1452 	flags = 0;
1453 
1454 	cp = strchr(val, ':');
1455 	if (cp != NULL) {
1456 		for (cp++; isalpha((int) *cp); cp++) {
1457 			/* accept mixed case */
1458 			int c = *cp;
1459 			if (isupper(c))
1460 				c = tolower(c);
1461 			switch (c) {
1462 			case 'a':		/* 802.11a */
1463 				flags |= IEEE80211_CHAN_A;
1464 				break;
1465 			case 'b':		/* 802.11b */
1466 				flags |= IEEE80211_CHAN_B;
1467 				break;
1468 			case 'g':		/* 802.11g */
1469 				flags |= IEEE80211_CHAN_G;
1470 				break;
1471 			case 'n':		/* 802.11n */
1472 				flags |= IEEE80211_CHAN_HT;
1473 				break;
1474 			case 'd':		/* dt = Atheros Dynamic Turbo */
1475 				flags |= IEEE80211_CHAN_TURBO;
1476 				break;
1477 			case 't':		/* ht, dt, st, t */
1478 				/* dt and unadorned t specify Dynamic Turbo */
1479 				if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0)
1480 					flags |= IEEE80211_CHAN_TURBO;
1481 				break;
1482 			case 's':		/* st = Atheros Static Turbo */
1483 				flags |= IEEE80211_CHAN_STURBO;
1484 				break;
1485 			case 'h':		/* 1/2-width channels */
1486 				flags |= IEEE80211_CHAN_HALF;
1487 				break;
1488 			case 'q':		/* 1/4-width channels */
1489 				flags |= IEEE80211_CHAN_QUARTER;
1490 				break;
1491 			default:
1492 				errx(-1, "%s: Invalid mode attribute %c\n",
1493 				    val, *cp);
1494 			}
1495 		}
1496 	}
1497 	return flags;
1498 }
1499 
1500 #define	_APPLY(_flags, _base, _param, _v) do {				\
1501     if (_flags & IEEE80211_CHAN_HT) {					\
1502 	    if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1503 		    _base.params[IEEE80211_MODE_11NA]._param = _v;	\
1504 		    _base.params[IEEE80211_MODE_11NG]._param = _v;	\
1505 	    } else if (_flags & IEEE80211_CHAN_5GHZ)			\
1506 		    _base.params[IEEE80211_MODE_11NA]._param = _v;	\
1507 	    else							\
1508 		    _base.params[IEEE80211_MODE_11NG]._param = _v;	\
1509     }									\
1510     if (_flags & IEEE80211_CHAN_TURBO) {				\
1511 	    if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1512 		    _base.params[IEEE80211_MODE_TURBO_A]._param = _v;	\
1513 		    _base.params[IEEE80211_MODE_TURBO_G]._param = _v;	\
1514 	    } else if (_flags & IEEE80211_CHAN_5GHZ)			\
1515 		    _base.params[IEEE80211_MODE_TURBO_A]._param = _v;	\
1516 	    else							\
1517 		    _base.params[IEEE80211_MODE_TURBO_G]._param = _v;	\
1518     }									\
1519     if (_flags & IEEE80211_CHAN_STURBO)					\
1520 	    _base.params[IEEE80211_MODE_STURBO_A]._param = _v;		\
1521     if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)		\
1522 	    _base.params[IEEE80211_MODE_11A]._param = _v;		\
1523     if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)		\
1524 	    _base.params[IEEE80211_MODE_11G]._param = _v;		\
1525     if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)		\
1526 	    _base.params[IEEE80211_MODE_11B]._param = _v;		\
1527     if (_flags & IEEE80211_CHAN_HALF)					\
1528 	    _base.params[IEEE80211_MODE_HALF]._param = _v;		\
1529     if (_flags & IEEE80211_CHAN_QUARTER)				\
1530 	    _base.params[IEEE80211_MODE_QUARTER]._param = _v;		\
1531 } while (0)
1532 #define	_APPLY1(_flags, _base, _param, _v) do {				\
1533     if (_flags & IEEE80211_CHAN_HT) {					\
1534 	    if (_flags & IEEE80211_CHAN_5GHZ)				\
1535 		    _base.params[IEEE80211_MODE_11NA]._param = _v;	\
1536 	    else							\
1537 		    _base.params[IEEE80211_MODE_11NG]._param = _v;	\
1538     } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)	\
1539 	    _base.params[IEEE80211_MODE_TURBO_A]._param = _v;		\
1540     else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)	\
1541 	    _base.params[IEEE80211_MODE_TURBO_G]._param = _v;		\
1542     else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)		\
1543 	    _base.params[IEEE80211_MODE_STURBO_A]._param = _v;		\
1544     else if (_flags & IEEE80211_CHAN_HALF)				\
1545 	    _base.params[IEEE80211_MODE_HALF]._param = _v;		\
1546     else if (_flags & IEEE80211_CHAN_QUARTER)				\
1547 	    _base.params[IEEE80211_MODE_QUARTER]._param = _v;		\
1548     else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)		\
1549 	    _base.params[IEEE80211_MODE_11A]._param = _v;		\
1550     else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)		\
1551 	    _base.params[IEEE80211_MODE_11G]._param = _v;		\
1552     else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)		\
1553 	    _base.params[IEEE80211_MODE_11B]._param = _v;		\
1554 } while (0)
1555 #define	_APPLY_RATE(_flags, _base, _param, _v) do {			\
1556     if (_flags & IEEE80211_CHAN_HT) {					\
1557 	(_v) = (_v / 2) | IEEE80211_RATE_MCS;				\
1558     }									\
1559     _APPLY(_flags, _base, _param, _v);					\
1560 } while (0)
1561 #define	_APPLY_RATE1(_flags, _base, _param, _v) do {			\
1562     if (_flags & IEEE80211_CHAN_HT) {					\
1563 	(_v) = (_v / 2) | IEEE80211_RATE_MCS;				\
1564     }									\
1565     _APPLY1(_flags, _base, _param, _v);					\
1566 } while (0)
1567 
1568 static void
1569 set80211roamrssi(const char *val, int d __unused, int s,
1570 		 const struct afswtch *afp __unused)
1571 {
1572 	double v = atof(val);
1573 	int rssi, flags;
1574 
1575 	rssi = (int) (2*v);
1576 	if (rssi != 2*v)
1577 		errx(-1, "invalid rssi (must be .5 dBm units)");
1578 	flags = getmodeflags(val);
1579 	getroam(s);
1580 	if (flags == 0) {		/* NB: no flags => current channel */
1581 		flags = getcurchan(s)->ic_flags;
1582 		_APPLY1(flags, roamparams, rssi, rssi);
1583 	} else
1584 		_APPLY(flags, roamparams, rssi, rssi);
1585 	callback_register(setroam_cb, &roamparams);
1586 }
1587 
1588 static int
1589 getrate(const char *val, const char *tag)
1590 {
1591 	double v = atof(val);
1592 	int rate;
1593 
1594 	rate = (int) (2*v);
1595 	if (rate != 2*v)
1596 		errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag);
1597 	return rate;		/* NB: returns 2x the specified value */
1598 }
1599 
1600 static void
1601 set80211roamrate(const char *val, int d __unused, int s,
1602 		 const struct afswtch *afp __unused)
1603 {
1604 	int rate, flags;
1605 
1606 	rate = getrate(val, "roam");
1607 	flags = getmodeflags(val);
1608 	getroam(s);
1609 	if (flags == 0) {		/* NB: no flags => current channel */
1610 		flags = getcurchan(s)->ic_flags;
1611 		_APPLY_RATE1(flags, roamparams, rate, rate);
1612 	} else
1613 		_APPLY_RATE(flags, roamparams, rate, rate);
1614 	callback_register(setroam_cb, &roamparams);
1615 }
1616 
1617 static void
1618 set80211mcastrate(const char *val, int d __unused, int s,
1619 		  const struct afswtch *afp __unused)
1620 {
1621 	int rate, flags;
1622 
1623 	rate = getrate(val, "mcast");
1624 	flags = getmodeflags(val);
1625 	gettxparams(s);
1626 	if (flags == 0) {		/* NB: no flags => current channel */
1627 		flags = getcurchan(s)->ic_flags;
1628 		_APPLY_RATE1(flags, txparams, mcastrate, rate);
1629 	} else
1630 		_APPLY_RATE(flags, txparams, mcastrate, rate);
1631 	callback_register(settxparams_cb, &txparams);
1632 }
1633 
1634 static void
1635 set80211mgtrate(const char *val, int d __unused, int s,
1636 		const struct afswtch *afp __unused)
1637 {
1638 	int rate, flags;
1639 
1640 	rate = getrate(val, "mgmt");
1641 	flags = getmodeflags(val);
1642 	gettxparams(s);
1643 	if (flags == 0) {		/* NB: no flags => current channel */
1644 		flags = getcurchan(s)->ic_flags;
1645 		_APPLY_RATE1(flags, txparams, mgmtrate, rate);
1646 	} else
1647 		_APPLY_RATE(flags, txparams, mgmtrate, rate);
1648 	callback_register(settxparams_cb, &txparams);
1649 }
1650 
1651 static void
1652 set80211ucastrate(const char *val, int d __unused, int s,
1653 		  const struct afswtch *afp __unused)
1654 {
1655 	int rate, flags;
1656 
1657 	gettxparams(s);
1658 	flags = getmodeflags(val);
1659 	if (isanyarg(val)) {
1660 		if (flags == 0) {	/* NB: no flags => current channel */
1661 			flags = getcurchan(s)->ic_flags;
1662 			_APPLY1(flags, txparams, ucastrate,
1663 			    IEEE80211_FIXED_RATE_NONE);
1664 		} else
1665 			_APPLY(flags, txparams, ucastrate,
1666 			    IEEE80211_FIXED_RATE_NONE);
1667 	} else {
1668 		rate = getrate(val, "ucast");
1669 		if (flags == 0) {	/* NB: no flags => current channel */
1670 			flags = getcurchan(s)->ic_flags;
1671 			_APPLY_RATE1(flags, txparams, ucastrate, rate);
1672 		} else
1673 			_APPLY_RATE(flags, txparams, ucastrate, rate);
1674 	}
1675 	callback_register(settxparams_cb, &txparams);
1676 }
1677 
1678 static void
1679 set80211maxretry(const char *val, int d __unused, int s,
1680 		 const struct afswtch *afp __unused)
1681 {
1682 	int v = atoi(val), flags;
1683 
1684 	flags = getmodeflags(val);
1685 	gettxparams(s);
1686 	if (flags == 0) {		/* NB: no flags => current channel */
1687 		flags = getcurchan(s)->ic_flags;
1688 		_APPLY1(flags, txparams, maxretry, v);
1689 	} else
1690 		_APPLY(flags, txparams, maxretry, v);
1691 	callback_register(settxparams_cb, &txparams);
1692 }
1693 #undef _APPLY_RATE
1694 #undef _APPLY
1695 
1696 static void
1697 set80211fragthreshold(const char *val, int d __unused, int s,
1698 		      const struct afswtch *afp __unused)
1699 {
1700 	set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
1701 		 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val),
1702 		 0, NULL);
1703 }
1704 
1705 static void
1706 set80211bmissthreshold(const char *val, int d __unused, int s,
1707 		       const struct afswtch *afp __unused)
1708 {
1709 	set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
1710 		 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val),
1711 		 0, NULL);
1712 }
1713 
1714 static void
1715 set80211burst(const char *val __unused, int d, int s,
1716 	      const struct afswtch *rafp __unused)
1717 {
1718 	set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
1719 }
1720 
1721 static void
1722 set80211doth(const char *val __unused, int d, int s,
1723 	     const struct afswtch *rafp __unused)
1724 {
1725 	set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
1726 }
1727 
1728 static void
1729 set80211dfs(const char *val __unused, int d, int s,
1730 	    const struct afswtch *rafp __unused)
1731 {
1732 	set80211(s, IEEE80211_IOC_DFS, d, 0, NULL);
1733 }
1734 
1735 static void
1736 set80211shortgi(const char *val __unused, int d, int s,
1737 		const struct afswtch *rafp __unused)
1738 {
1739 	set80211(s, IEEE80211_IOC_SHORTGI,
1740 		 d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
1741 		 0, NULL);
1742 }
1743 
1744 static void
1745 set80211ampdu(const char *val __unused, int d, int s,
1746 	      const struct afswtch *rafp __unused)
1747 {
1748 	int ampdu;
1749 
1750 	if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
1751 		errx(-1, "cannot get AMPDU setting");
1752 	if (d < 0) {
1753 		d = -d;
1754 		ampdu &= ~d;
1755 	} else
1756 		ampdu |= d;
1757 	set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
1758 }
1759 
1760 static void
1761 set80211ampdulimit(const char *val, int d __unused, int s,
1762 		   const struct afswtch *afp __unused)
1763 {
1764 	int v;
1765 
1766 	switch (atoi(val)) {
1767 	case 8:
1768 	case 8*1024:
1769 		v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
1770 		break;
1771 	case 16:
1772 	case 16*1024:
1773 		v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
1774 		break;
1775 	case 32:
1776 	case 32*1024:
1777 		v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
1778 		break;
1779 	case 64:
1780 	case 64*1024:
1781 		v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
1782 		break;
1783 	default:
1784 		errx(-1, "invalid A-MPDU limit %s", val);
1785 	}
1786 	set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
1787 }
1788 
1789 static void
1790 set80211ampdudensity(const char *val, int d __unused, int s,
1791 		     const struct afswtch *afp __unused)
1792 {
1793 	int v;
1794 
1795 	if (isanyarg(val) || iseq(val, "na"))
1796 		v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1797 	else switch ((int)(atof(val)*4)) {
1798 	case 0:
1799 		v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1800 		break;
1801 	case 1:
1802 		v = IEEE80211_HTCAP_MPDUDENSITY_025;
1803 		break;
1804 	case 2:
1805 		v = IEEE80211_HTCAP_MPDUDENSITY_05;
1806 		break;
1807 	case 4:
1808 		v = IEEE80211_HTCAP_MPDUDENSITY_1;
1809 		break;
1810 	case 8:
1811 		v = IEEE80211_HTCAP_MPDUDENSITY_2;
1812 		break;
1813 	case 16:
1814 		v = IEEE80211_HTCAP_MPDUDENSITY_4;
1815 		break;
1816 	case 32:
1817 		v = IEEE80211_HTCAP_MPDUDENSITY_8;
1818 		break;
1819 	case 64:
1820 		v = IEEE80211_HTCAP_MPDUDENSITY_16;
1821 		break;
1822 	default:
1823 		errx(-1, "invalid A-MPDU density %s", val);
1824 	}
1825 	set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
1826 }
1827 
1828 static void
1829 set80211amsdu(const char *val __unused, int d, int s,
1830 	      const struct afswtch *rafp __unused)
1831 {
1832 	int amsdu;
1833 
1834 	if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
1835 		err(-1, "cannot get AMSDU setting");
1836 	if (d < 0) {
1837 		d = -d;
1838 		amsdu &= ~d;
1839 	} else
1840 		amsdu |= d;
1841 	set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
1842 }
1843 
1844 static void
1845 set80211amsdulimit(const char *val, int d __unused, int s,
1846 		   const struct afswtch *afp __unused)
1847 {
1848 	set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
1849 }
1850 
1851 static void
1852 set80211puren(const char *val __unused, int d, int s,
1853 	      const struct afswtch *rafp __unused)
1854 {
1855 	set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
1856 }
1857 
1858 static void
1859 set80211htcompat(const char *val __unused, int d, int s,
1860 		 const struct afswtch *rafp __unused)
1861 {
1862 	set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
1863 }
1864 
1865 static void
1866 set80211htconf(const char *val __unused, int d, int s,
1867 	       const struct afswtch *rafp __unused)
1868 {
1869 	set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
1870 	htconf = d;
1871 }
1872 
1873 static void
1874 set80211dwds(const char *val __unused, int d, int s,
1875 	     const struct afswtch *rafp __unused)
1876 {
1877 	set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL);
1878 }
1879 
1880 static void
1881 set80211inact(const char *val __unused, int d, int s,
1882 	      const struct afswtch *rafp __unused)
1883 {
1884 	set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
1885 }
1886 
1887 static void
1888 set80211tsn(const char *val __unused, int d, int s,
1889 	    const struct afswtch *rafp __unused)
1890 {
1891 	set80211(s, IEEE80211_IOC_TSN, d, 0, NULL);
1892 }
1893 
1894 static void
1895 set80211dotd(const char *val __unused, int d, int s,
1896 	     const struct afswtch *rafp __unused)
1897 {
1898 	set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL);
1899 }
1900 
1901 static void
1902 set80211smps(const char *val __unused, int d, int s,
1903 	     const struct afswtch *rafp __unused)
1904 {
1905 	set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL);
1906 }
1907 
1908 static void
1909 set80211rifs(const char *val __unused, int d, int s,
1910 	     const struct afswtch *rafp __unused)
1911 {
1912 	set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
1913 }
1914 
1915 static void
1916 set80211tdmaslot(const char *val, int d __unused, int s,
1917 		 const struct afswtch *afp __unused)
1918 {
1919 	set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
1920 }
1921 
1922 static void
1923 set80211tdmaslotcnt(const char *val, int d __unused, int s,
1924 		    const struct afswtch *afp __unused)
1925 {
1926 	set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
1927 }
1928 
1929 static void
1930 set80211tdmaslotlen(const char *val, int d __unused, int s,
1931 		    const struct afswtch *afp __unused)
1932 {
1933 	set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
1934 }
1935 
1936 static void
1937 set80211tdmabintval(const char *val, int d __unused, int s,
1938 		    const struct afswtch *afp __unused)
1939 {
1940 	set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
1941 }
1942 
1943 static void
1944 set80211meshttl(const char *val, int d __unused, int s,
1945 		const struct afswtch *afp __unused)
1946 {
1947 	set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
1948 }
1949 
1950 static void
1951 set80211meshforward(const char *val, int d __unused, int s,
1952 		    const struct afswtch *afp __unused)
1953 {
1954 	set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL);
1955 }
1956 
1957 static void
1958 set80211meshpeering(const char *val, int d __unused, int s,
1959 		    const struct afswtch *afp __unused)
1960 {
1961 	set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL);
1962 }
1963 
1964 static void
1965 set80211meshmetric(const char *val, int d __unused, int s,
1966 		   const struct afswtch *afp __unused)
1967 {
1968 	char v[12];
1969 
1970 	memcpy(v, val, sizeof(v));
1971 	set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
1972 }
1973 
1974 static void
1975 set80211meshpath(const char *val, int d __unused, int s,
1976 		 const struct afswtch *afp __unused)
1977 {
1978 	char v[12];
1979 
1980 	memcpy(v, val, sizeof(v));
1981 	set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
1982 }
1983 
1984 static int
1985 regdomain_sort(const void *a, const void *b)
1986 {
1987 #define	CHAN_ALL \
1988 	(IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)
1989 	const struct ieee80211_channel *ca = a;
1990 	const struct ieee80211_channel *cb = b;
1991 
1992 	return ca->ic_freq == cb->ic_freq ?
1993 	    ((int)ca->ic_flags & CHAN_ALL) - ((int)cb->ic_flags & CHAN_ALL) :
1994 	    ca->ic_freq - cb->ic_freq;
1995 #undef CHAN_ALL
1996 }
1997 
1998 static const struct ieee80211_channel *
1999 chanlookup(const struct ieee80211_channel chans[], int nchans,
2000 	int freq, int flags)
2001 {
2002 	int i;
2003 
2004 	flags &= IEEE80211_CHAN_ALLTURBO;
2005 	for (i = 0; i < nchans; i++) {
2006 		const struct ieee80211_channel *c = &chans[i];
2007 		if (c->ic_freq == freq &&
2008 		    ((int)c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
2009 			return c;
2010 	}
2011 	return NULL;
2012 }
2013 
2014 static int
2015 chanfind(const struct ieee80211_channel chans[], int nchans, int flags)
2016 {
2017 	int i;
2018 
2019 	for (i = 0; i < nchans; i++) {
2020 		const struct ieee80211_channel *c = &chans[i];
2021 		if (((int)c->ic_flags & flags) == flags)
2022 			return 1;
2023 	}
2024 	return 0;
2025 }
2026 
2027 /*
2028  * Check channel compatibility.
2029  */
2030 static int
2031 checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags)
2032 {
2033 	flags &= ~REQ_FLAGS;
2034 	/*
2035 	 * Check if exact channel is in the calibration table;
2036 	 * everything below is to deal with channels that we
2037 	 * want to include but that are not explicitly listed.
2038 	 */
2039 	if (flags & IEEE80211_CHAN_HT40) {
2040 		/* NB: we use an HT40 channel center that matches HT20 */
2041 		flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20;
2042 	}
2043 	if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL)
2044 		return 1;
2045 	if (flags & IEEE80211_CHAN_GSM) {
2046 		/*
2047 		 * XXX GSM frequency mapping is handled in the kernel
2048 		 * so we cannot find them in the calibration table;
2049 		 * just accept the channel and the kernel will reject
2050 		 * the channel list if it's wrong.
2051 		 */
2052 		return 1;
2053 	}
2054 	/*
2055 	 * If this is a 1/2 or 1/4 width channel allow it if a full
2056 	 * width channel is present for this frequency, and the device
2057 	 * supports fractional channels on this band.  This is a hack
2058 	 * that avoids bloating the calibration table; it may be better
2059 	 * by per-band attributes though (we are effectively calculating
2060 	 * this attribute by scanning the channel list ourself).
2061 	 */
2062 	if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0)
2063 		return 0;
2064 	if (chanlookup(avail->ic_chans, avail->ic_nchans, freq,
2065 	    flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL)
2066 		return 0;
2067 	if (flags & IEEE80211_CHAN_HALF) {
2068 		return chanfind(avail->ic_chans, avail->ic_nchans,
2069 		    IEEE80211_CHAN_HALF |
2070 		       (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
2071 	} else {
2072 		return chanfind(avail->ic_chans, avail->ic_nchans,
2073 		    IEEE80211_CHAN_QUARTER |
2074 			(flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
2075 	}
2076 }
2077 
2078 static void
2079 regdomain_addchans(struct ieee80211req_chaninfo *ci,
2080 	const netband_head *bands,
2081 	const struct ieee80211_regdomain *reg,
2082 	uint32_t chanFlags,
2083 	const struct ieee80211req_chaninfo *avail)
2084 {
2085 	const struct netband *nb;
2086 	const struct freqband *b;
2087 	struct ieee80211_channel *c, *prev;
2088 	int freq, hi_adj, lo_adj, channelSep;
2089 	uint32_t flags;
2090 
2091 	hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
2092 	lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
2093 	channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
2094 	LIST_FOREACH(nb, bands, next) {
2095 		b = nb->band;
2096 		if (verbose) {
2097 			printf("%s:", __func__);
2098 			printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
2099 			printb(" bandFlags", nb->flags | b->flags,
2100 			    IEEE80211_CHAN_BITS);
2101 			putchar('\n');
2102 		}
2103 		prev = NULL;
2104 		for (freq = b->freqStart + lo_adj;
2105 		     freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
2106 			/*
2107 			 * Construct flags for the new channel.  We take
2108 			 * the attributes from the band descriptions except
2109 			 * for HT40 which is enabled generically (i.e. +/-
2110 			 * extension channel) in the band description and
2111 			 * then constrained according by channel separation.
2112 			 */
2113 			flags = nb->flags | b->flags;
2114 			if (flags & IEEE80211_CHAN_HT) {
2115 				/*
2116 				 * HT channels are generated specially; we're
2117 				 * called to add HT20, HT40+, and HT40- chan's
2118 				 * so we need to expand only band specs for
2119 				 * the HT channel type being added.
2120 				 */
2121 				if ((chanFlags & IEEE80211_CHAN_HT20) &&
2122 				    (flags & IEEE80211_CHAN_HT20) == 0) {
2123 					if (verbose)
2124 						printf("%u: skip, not an "
2125 						    "HT20 channel\n", freq);
2126 					continue;
2127 				}
2128 				if ((chanFlags & IEEE80211_CHAN_HT40) &&
2129 				    (flags & IEEE80211_CHAN_HT40) == 0) {
2130 					if (verbose)
2131 						printf("%u: skip, not an "
2132 						    "HT40 channel\n", freq);
2133 					continue;
2134 				}
2135 				/*
2136 				 * DFS and HT40 don't mix.  This should be
2137 				 * expressed in the regdomain database but
2138 				 * just in case enforce it here.
2139 				 */
2140 				if ((chanFlags & IEEE80211_CHAN_HT40) &&
2141 				    (flags & IEEE80211_CHAN_DFS)) {
2142 					if (verbose)
2143 						printf("%u: skip, HT40+DFS "
2144 						    "not permitted\n", freq);
2145 					continue;
2146 				}
2147 				/* NB: HT attribute comes from caller */
2148 				flags &= ~IEEE80211_CHAN_HT;
2149 				flags |= chanFlags & IEEE80211_CHAN_HT;
2150 			}
2151 			/*
2152 			 * Check if device can operate on this frequency.
2153 			 */
2154 			if (!checkchan(avail, freq, flags)) {
2155 				if (verbose) {
2156 					printf("%u: skip, ", freq);
2157 					printb("flags", flags,
2158 					    IEEE80211_CHAN_BITS);
2159 					printf(" not available\n");
2160 				}
2161 				continue;
2162 			}
2163 			if ((flags & REQ_ECM) && !reg->ecm) {
2164 				if (verbose)
2165 					printf("%u: skip, ECM channel\n", freq);
2166 				continue;
2167 			}
2168 			if ((flags & REQ_INDOOR) && reg->location == 'O') {
2169 				if (verbose)
2170 					printf("%u: skip, indoor channel\n",
2171 					    freq);
2172 				continue;
2173 			}
2174 			if ((flags & REQ_OUTDOOR) && reg->location == 'I') {
2175 				if (verbose)
2176 					printf("%u: skip, outdoor channel\n",
2177 					    freq);
2178 				continue;
2179 			}
2180 			if ((flags & IEEE80211_CHAN_HT40) &&
2181 			    prev != NULL && (freq - prev->ic_freq) < channelSep) {
2182 				if (verbose)
2183 					printf("%u: skip, only %u channel "
2184 					    "separation, need %d\n", freq,
2185 					    freq - prev->ic_freq, channelSep);
2186 				continue;
2187 			}
2188 			if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
2189 				if (verbose)
2190 					printf("%u: skip, channel table full\n",
2191 					    freq);
2192 				break;
2193 			}
2194 			c = &ci->ic_chans[ci->ic_nchans++];
2195 			memset(c, 0, sizeof(*c));
2196 			c->ic_freq = freq;
2197 			c->ic_flags = flags;
2198 			if (c->ic_flags & IEEE80211_CHAN_DFS)
2199 				c->ic_maxregpower = nb->maxPowerDFS;
2200 			else
2201 				c->ic_maxregpower = nb->maxPower;
2202 			if (verbose) {
2203 				printf("[%3d] add freq %u ",
2204 				    ci->ic_nchans-1, c->ic_freq);
2205 				printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
2206 				printf(" power %u\n", c->ic_maxregpower);
2207 			}
2208 			/* NB: kernel fills in other fields */
2209 			prev = c;
2210 		}
2211 	}
2212 }
2213 
2214 static void
2215 regdomain_makechannels(
2216 	struct ieee80211_regdomain_req *req,
2217 	const struct ieee80211_devcaps_req *dc)
2218 {
2219 	struct regdata *rdp = getregdata();
2220 	const struct country *cc;
2221 	const struct ieee80211_regdomain *reg = &req->rd;
2222 	struct ieee80211req_chaninfo *ci = &req->chaninfo;
2223 	const struct regdomain *rd;
2224 
2225 	/*
2226 	 * Locate construction table for new channel list.  We treat
2227 	 * the regdomain/SKU as definitive so a country can be in
2228 	 * multiple with different properties (e.g. US in FCC+FCC3).
2229 	 * If no regdomain is specified then we fallback on the country
2230 	 * code to find the associated regdomain since countries always
2231 	 * belong to at least one regdomain.
2232 	 */
2233 	if (reg->regdomain == 0) {
2234 		cc = lib80211_country_findbycc(rdp, reg->country);
2235 		if (cc == NULL)
2236 			errx(1, "internal error, country %d not found",
2237 			    reg->country);
2238 		rd = cc->rd;
2239 	} else
2240 		rd = lib80211_regdomain_findbysku(rdp, reg->regdomain);
2241 	if (rd == NULL)
2242 		errx(1, "internal error, regdomain %d not found",
2243 			    reg->regdomain);
2244 	if (rd->sku != SKU_DEBUG) {
2245 		/*
2246 		 * regdomain_addchans incrememnts the channel count for
2247 		 * each channel it adds so initialize ic_nchans to zero.
2248 		 * Note that we know we have enough space to hold all possible
2249 		 * channels because the devcaps list size was used to
2250 		 * allocate our request.
2251 		 */
2252 		ci->ic_nchans = 0;
2253 		if (!LIST_EMPTY(&rd->bands_11b))
2254 			regdomain_addchans(ci, &rd->bands_11b, reg,
2255 			    IEEE80211_CHAN_B, &dc->dc_chaninfo);
2256 		if (!LIST_EMPTY(&rd->bands_11g))
2257 			regdomain_addchans(ci, &rd->bands_11g, reg,
2258 			    IEEE80211_CHAN_G, &dc->dc_chaninfo);
2259 		if (!LIST_EMPTY(&rd->bands_11a))
2260 			regdomain_addchans(ci, &rd->bands_11a, reg,
2261 			    IEEE80211_CHAN_A, &dc->dc_chaninfo);
2262 		if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) {
2263 			regdomain_addchans(ci, &rd->bands_11na, reg,
2264 			    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
2265 			    &dc->dc_chaninfo);
2266 			if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2267 				regdomain_addchans(ci, &rd->bands_11na, reg,
2268 				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,
2269 				    &dc->dc_chaninfo);
2270 				regdomain_addchans(ci, &rd->bands_11na, reg,
2271 				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,
2272 				    &dc->dc_chaninfo);
2273 			}
2274 		}
2275 		if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
2276 			regdomain_addchans(ci, &rd->bands_11ng, reg,
2277 			    IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
2278 			    &dc->dc_chaninfo);
2279 			if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2280 				regdomain_addchans(ci, &rd->bands_11ng, reg,
2281 				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,
2282 				    &dc->dc_chaninfo);
2283 				regdomain_addchans(ci, &rd->bands_11ng, reg,
2284 				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,
2285 				    &dc->dc_chaninfo);
2286 			}
2287 		}
2288 		qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
2289 		    regdomain_sort);
2290 	} else
2291 		memcpy(ci, &dc->dc_chaninfo,
2292 		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
2293 }
2294 
2295 static void
2296 list_countries(void)
2297 {
2298 	struct regdata *rdp = getregdata();
2299 	const struct country *cp;
2300 	const struct regdomain *dp;
2301 	int i;
2302 
2303 	i = 0;
2304 	printf("\nCountry codes:\n");
2305 	LIST_FOREACH(cp, &rdp->countries, next) {
2306 		printf("%2s %-15.15s%s", cp->isoname,
2307 		    cp->name, ((i+1)%4) == 0 ? "\n" : " ");
2308 		i++;
2309 	}
2310 	i = 0;
2311 	printf("\nRegulatory domains:\n");
2312 	LIST_FOREACH(dp, &rdp->domains, next) {
2313 		printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " ");
2314 		i++;
2315 	}
2316 	printf("\n");
2317 }
2318 
2319 static void
2320 defaultcountry(const struct regdomain *rd)
2321 {
2322 	struct regdata *rdp = getregdata();
2323 	const struct country *cc;
2324 
2325 	cc = lib80211_country_findbycc(rdp, rd->cc->code);
2326 	if (cc == NULL)
2327 		errx(1, "internal error, ISO country code %d not "
2328 		    "defined for regdomain %s", rd->cc->code, rd->name);
2329 	regdomain.country = cc->code;
2330 	regdomain.isocc[0] = cc->isoname[0];
2331 	regdomain.isocc[1] = cc->isoname[1];
2332 }
2333 
2334 static void
2335 set80211regdomain(const char *val, int d __unused, int s,
2336 		  const struct afswtch *afp __unused)
2337 {
2338 	struct regdata *rdp = getregdata();
2339 	const struct regdomain *rd;
2340 
2341 	rd = lib80211_regdomain_findbyname(rdp, val);
2342 	if (rd == NULL) {
2343 		char *eptr;
2344 		long sku = strtol(val, &eptr, 0);
2345 
2346 		if (eptr != val)
2347 			rd = lib80211_regdomain_findbysku(rdp, sku);
2348 		if (eptr == val || rd == NULL)
2349 			errx(1, "unknown regdomain %s", val);
2350 	}
2351 	getregdomain(s);
2352 	regdomain.regdomain = rd->sku;
2353 	if (regdomain.country == 0 && rd->cc != NULL) {
2354 		/*
2355 		 * No country code setup and there's a default
2356 		 * one for this regdomain fill it in.
2357 		 */
2358 		defaultcountry(rd);
2359 	}
2360 	callback_register(setregdomain_cb, &regdomain);
2361 }
2362 
2363 static void
2364 set80211country(const char *val, int d __unused, int s,
2365 		const struct afswtch *afp __unused)
2366 {
2367 	struct regdata *rdp = getregdata();
2368 	const struct country *cc;
2369 
2370 	cc = lib80211_country_findbyname(rdp, val);
2371 	if (cc == NULL) {
2372 		char *eptr;
2373 		long code = strtol(val, &eptr, 0);
2374 
2375 		if (eptr != val)
2376 			cc = lib80211_country_findbycc(rdp, code);
2377 		if (eptr == val || cc == NULL)
2378 			errx(1, "unknown ISO country code %s", val);
2379 	}
2380 	getregdomain(s);
2381 	regdomain.regdomain = cc->rd->sku;
2382 	regdomain.country = cc->code;
2383 	regdomain.isocc[0] = cc->isoname[0];
2384 	regdomain.isocc[1] = cc->isoname[1];
2385 	callback_register(setregdomain_cb, &regdomain);
2386 }
2387 
2388 static void
2389 set80211location(const char *val __unused, int d, int s,
2390 		 const struct afswtch *rafp __unused)
2391 {
2392 	getregdomain(s);
2393 	regdomain.location = d;
2394 	callback_register(setregdomain_cb, &regdomain);
2395 }
2396 
2397 static void
2398 set80211ecm(const char *val __unused, int d, int s,
2399 	    const struct afswtch *rafp __unused)
2400 {
2401 	getregdomain(s);
2402 	regdomain.ecm = d;
2403 	callback_register(setregdomain_cb, &regdomain);
2404 }
2405 
2406 static void
2407 LINE_INIT(char c)
2408 {
2409 	spacer = c;
2410 	if (c == '\t')
2411 		col = 8;
2412 	else
2413 		col = 1;
2414 }
2415 
2416 static void
2417 LINE_BREAK(void)
2418 {
2419 	if (spacer != '\t') {
2420 		printf("\n");
2421 		spacer = '\t';
2422 	}
2423 	col = 8;		/* 8-col tab */
2424 }
2425 
2426 static void
2427 LINE_CHECK(const char *fmt, ...)
2428 {
2429 	char buf[80];
2430 	va_list ap;
2431 	int n;
2432 
2433 	va_start(ap, fmt);
2434 	n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
2435 	va_end(ap);
2436 	col += 1+n;
2437 	if (col > MAXCOL) {
2438 		LINE_BREAK();
2439 		col += n;
2440 	}
2441 	buf[0] = spacer;
2442 	printf("%s", buf);
2443 	spacer = ' ';
2444 }
2445 
2446 static int
2447 getmaxrate(const uint8_t rates[15], uint8_t nrates)
2448 {
2449 	int i, maxrate = -1;
2450 
2451 	for (i = 0; i < nrates; i++) {
2452 		int rate = rates[i] & IEEE80211_RATE_VAL;
2453 		if (rate > maxrate)
2454 			maxrate = rate;
2455 	}
2456 	return maxrate / 2;
2457 }
2458 
2459 static const char *
2460 getcaps(int capinfo)
2461 {
2462 	static char capstring[32];
2463 	char *cp = capstring;
2464 
2465 	if (capinfo & IEEE80211_CAPINFO_ESS)
2466 		*cp++ = 'E';
2467 	if (capinfo & IEEE80211_CAPINFO_IBSS)
2468 		*cp++ = 'I';
2469 	if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
2470 		*cp++ = 'c';
2471 	if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
2472 		*cp++ = 'C';
2473 	if (capinfo & IEEE80211_CAPINFO_PRIVACY)
2474 		*cp++ = 'P';
2475 	if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
2476 		*cp++ = 'S';
2477 	if (capinfo & IEEE80211_CAPINFO_PBCC)
2478 		*cp++ = 'B';
2479 	if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
2480 		*cp++ = 'A';
2481 	if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
2482 		*cp++ = 's';
2483 	if (capinfo & IEEE80211_CAPINFO_RSN)
2484 		*cp++ = 'R';
2485 	if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
2486 		*cp++ = 'D';
2487 	*cp = '\0';
2488 	return capstring;
2489 }
2490 
2491 static const char *
2492 getflags(int flags)
2493 {
2494 	static char flagstring[32];
2495 	char *cp = flagstring;
2496 
2497 	if (flags & IEEE80211_NODE_AUTH)
2498 		*cp++ = 'A';
2499 	if (flags & IEEE80211_NODE_QOS)
2500 		*cp++ = 'Q';
2501 	if (flags & IEEE80211_NODE_ERP)
2502 		*cp++ = 'E';
2503 	if (flags & IEEE80211_NODE_PWR_MGT)
2504 		*cp++ = 'P';
2505 	if (flags & IEEE80211_NODE_HT) {
2506 		*cp++ = 'H';
2507 		if (flags & IEEE80211_NODE_HTCOMPAT)
2508 			*cp++ = '+';
2509 	}
2510 	if (flags & IEEE80211_NODE_WPS)
2511 		*cp++ = 'W';
2512 	if (flags & IEEE80211_NODE_TSN)
2513 		*cp++ = 'N';
2514 	if (flags & IEEE80211_NODE_AMPDU_TX)
2515 		*cp++ = 'T';
2516 	if (flags & IEEE80211_NODE_AMPDU_RX)
2517 		*cp++ = 'R';
2518 	if (flags & IEEE80211_NODE_MIMO_PS) {
2519 		*cp++ = 'M';
2520 		if (flags & IEEE80211_NODE_MIMO_RTS)
2521 			*cp++ = '+';
2522 	}
2523 	if (flags & IEEE80211_NODE_RIFS)
2524 		*cp++ = 'I';
2525 	if (flags & IEEE80211_NODE_SGI40) {
2526 		*cp++ = 'S';
2527 		if (flags & IEEE80211_NODE_SGI20)
2528 			*cp++ = '+';
2529 	} else if (flags & IEEE80211_NODE_SGI20)
2530 		*cp++ = 's';
2531 	if (flags & IEEE80211_NODE_AMSDU_TX)
2532 		*cp++ = 't';
2533 	if (flags & IEEE80211_NODE_AMSDU_RX)
2534 		*cp++ = 'r';
2535 	*cp = '\0';
2536 	return flagstring;
2537 }
2538 
2539 static void
2540 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
2541 {
2542 	printf("%s", tag);
2543 	if (verbose) {
2544 		maxlen -= strlen(tag)+2;
2545 		if (2*ielen > (size_t)maxlen)
2546 			maxlen--;
2547 		printf("<");
2548 		for (; ielen > 0; ie++, ielen--) {
2549 			if (maxlen-- <= 0)
2550 				break;
2551 			printf("%02x", *ie);
2552 		}
2553 		if (ielen != 0)
2554 			printf("-");
2555 		printf(">");
2556 	}
2557 }
2558 
2559 #define LE_READ_2(p)					\
2560 	((u_int16_t)					\
2561 	 ((((const u_int8_t *)(p))[0]      ) |		\
2562 	  (((const u_int8_t *)(p))[1] <<  8)))
2563 #define LE_READ_4(p)					\
2564 	((u_int32_t)					\
2565 	 ((((const u_int8_t *)(p))[0]      ) |		\
2566 	  (((const u_int8_t *)(p))[1] <<  8) |		\
2567 	  (((const u_int8_t *)(p))[2] << 16) |		\
2568 	  (((const u_int8_t *)(p))[3] << 24)))
2569 
2570 /*
2571  * NB: The decoding routines assume a properly formatted ie
2572  *     which should be safe as the kernel only retains them
2573  *     if they parse ok.
2574  */
2575 
2576 static void
2577 printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2578 	      int maxlen __unused)
2579 {
2580 #define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
2581 	static const char *acnames[] = { "BE", "BK", "VO", "VI" };
2582 	const struct ieee80211_wme_param *wme =
2583 	    (const struct ieee80211_wme_param *) ie;
2584 	int i;
2585 
2586 	printf("%s", tag);
2587 	if (!verbose)
2588 		return;
2589 	printf("<qosinfo 0x%x", wme->param_qosInfo);
2590 	ie += offsetof(struct ieee80211_wme_param, params_acParams);
2591 	for (i = 0; i < WME_NUM_AC; i++) {
2592 		const struct ieee80211_wme_acparams *ac =
2593 		    &wme->params_acParams[i];
2594 
2595 		printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
2596 			, acnames[i]
2597 			, MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
2598 			, MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
2599 			, MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
2600 			, MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
2601 			, LE_READ_2(&ac->acp_txop)
2602 		);
2603 	}
2604 	printf(">");
2605 #undef MS
2606 }
2607 
2608 static void
2609 printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2610 	     int maxlen __unused)
2611 {
2612 	printf("%s", tag);
2613 	if (verbose) {
2614 		const struct ieee80211_wme_info *wme =
2615 		    (const struct ieee80211_wme_info *) ie;
2616 		printf("<version 0x%x info 0x%x>",
2617 		    wme->wme_version, wme->wme_info);
2618 	}
2619 }
2620 
2621 static void
2622 printhtcap(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2623 	   int maxlen __unused)
2624 {
2625 	printf("%s", tag);
2626 	if (verbose) {
2627 		const struct ieee80211_ie_htcap *htcap =
2628 		    (const struct ieee80211_ie_htcap *) ie;
2629 		const char *sep;
2630 		int i, j;
2631 
2632 		printf("<cap 0x%x param 0x%x",
2633 		    LE_READ_2(&htcap->hc_cap), htcap->hc_param);
2634 		printf(" mcsset[");
2635 		sep = "";
2636 		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
2637 			if (isset(htcap->hc_mcsset, i)) {
2638 				for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
2639 					if (isclr(htcap->hc_mcsset, j))
2640 						break;
2641 				j--;
2642 				if (i == j)
2643 					printf("%s%u", sep, i);
2644 				else
2645 					printf("%s%u-%u", sep, i, j);
2646 				i += j-i;
2647 				sep = ",";
2648 			}
2649 		printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
2650 		    LE_READ_2(&htcap->hc_extcap),
2651 		    LE_READ_4(&htcap->hc_txbf),
2652 		    htcap->hc_antenna);
2653 	}
2654 }
2655 
2656 static void
2657 printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2658 	    int maxlen __unused)
2659 {
2660 	printf("%s", tag);
2661 	if (verbose) {
2662 		const struct ieee80211_ie_htinfo *htinfo =
2663 		    (const struct ieee80211_ie_htinfo *) ie;
2664 		const char *sep;
2665 		int i, j;
2666 
2667 		printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
2668 		    htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
2669 		    LE_READ_2(&htinfo->hi_byte45));
2670 		printf(" basicmcs[");
2671 		sep = "";
2672 		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
2673 			if (isset(htinfo->hi_basicmcsset, i)) {
2674 				for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
2675 					if (isclr(htinfo->hi_basicmcsset, j))
2676 						break;
2677 				j--;
2678 				if (i == j)
2679 					printf("%s%u", sep, i);
2680 				else
2681 					printf("%s%u-%u", sep, i, j);
2682 				i += j-i;
2683 				sep = ",";
2684 			}
2685 		printf("]>");
2686 	}
2687 }
2688 
2689 static void
2690 printathie(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2691 	   int maxlen __unused)
2692 {
2693 	printf("%s", tag);
2694 	if (verbose) {
2695 		const struct ieee80211_ath_ie *ath =
2696 			(const struct ieee80211_ath_ie *)ie;
2697 
2698 		printf("<");
2699 		if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
2700 			printf("DTURBO,");
2701 		if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
2702 			printf("COMP,");
2703 		if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
2704 			printf("FF,");
2705 		if (ath->ath_capability & ATHEROS_CAP_XR)
2706 			printf("XR,");
2707 		if (ath->ath_capability & ATHEROS_CAP_AR)
2708 			printf("AR,");
2709 		if (ath->ath_capability & ATHEROS_CAP_BURST)
2710 			printf("BURST,");
2711 		if (ath->ath_capability & ATHEROS_CAP_WME)
2712 			printf("WME,");
2713 		if (ath->ath_capability & ATHEROS_CAP_BOOST)
2714 			printf("BOOST,");
2715 		printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
2716 	}
2717 }
2718 
2719 
2720 static void
2721 printmeshconf(const char *tag, const uint8_t *ie, size_t ielen __unused,
2722 	      int maxlen __unused)
2723 {
2724 #define MATCHOUI(field, oui, string)					\
2725 do {									\
2726 	if (memcmp(field, oui, 4) == 0)					\
2727 		printf("%s", string);					\
2728 } while (0)
2729 
2730 	printf("%s", tag);
2731 	if (verbose) {
2732 		const struct ieee80211_meshconf_ie *mconf =
2733 			(const struct ieee80211_meshconf_ie *)ie;
2734 		printf("<PATH:");
2735 		if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP)
2736 			printf("HWMP");
2737 		else
2738 			printf("UNKNOWN");
2739 		printf(" LINK:");
2740 		if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME)
2741 			printf("AIRTIME");
2742 		else
2743 			printf("UNKNOWN");
2744 		printf(" CONGESTION:");
2745 		if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED)
2746 			printf("DISABLED");
2747 		else
2748 			printf("UNKNOWN");
2749 		printf(" SYNC:");
2750 		if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF)
2751 			printf("NEIGHOFF");
2752 		else
2753 			printf("UNKNOWN");
2754 		printf(" AUTH:");
2755 		if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED)
2756 			printf("DISABLED");
2757 		else
2758 			printf("UNKNOWN");
2759 		printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
2760 		    mconf->conf_cap);
2761 	}
2762 #undef MATCHOUI
2763 }
2764 
2765 static const char *
2766 wpa_cipher(const u_int8_t *sel)
2767 {
2768 #define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
2769 	u_int32_t w = LE_READ_4(sel);
2770 
2771 	switch (w) {
2772 	case WPA_SEL(WPA_CSE_NULL):
2773 		return "NONE";
2774 	case WPA_SEL(WPA_CSE_WEP40):
2775 		return "WEP40";
2776 	case WPA_SEL(WPA_CSE_WEP104):
2777 		return "WEP104";
2778 	case WPA_SEL(WPA_CSE_TKIP):
2779 		return "TKIP";
2780 	case WPA_SEL(WPA_CSE_CCMP):
2781 		return "AES-CCMP";
2782 	}
2783 	return "?";		/* NB: so 1<< is discarded */
2784 #undef WPA_SEL
2785 }
2786 
2787 static const char *
2788 wpa_keymgmt(const u_int8_t *sel)
2789 {
2790 #define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
2791 	u_int32_t w = LE_READ_4(sel);
2792 
2793 	switch (w) {
2794 	case WPA_SEL(WPA_ASE_8021X_UNSPEC):
2795 		return "8021X-UNSPEC";
2796 	case WPA_SEL(WPA_ASE_8021X_PSK):
2797 		return "8021X-PSK";
2798 	case WPA_SEL(WPA_ASE_NONE):
2799 		return "NONE";
2800 	}
2801 	return "?";
2802 #undef WPA_SEL
2803 }
2804 
2805 static void
2806 printwpaie(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2807 	   int maxlen __unused)
2808 {
2809 	u_int8_t len = ie[1];
2810 
2811 	printf("%s", tag);
2812 	if (verbose) {
2813 		const char *sep;
2814 		int n;
2815 
2816 		ie += 6, len -= 4;		/* NB: len is payload only */
2817 
2818 		printf("<v%u", LE_READ_2(ie));
2819 		ie += 2, len -= 2;
2820 
2821 		printf(" mc:%s", wpa_cipher(ie));
2822 		ie += 4, len -= 4;
2823 
2824 		/* unicast ciphers */
2825 		n = LE_READ_2(ie);
2826 		ie += 2, len -= 2;
2827 		sep = " uc:";
2828 		for (; n > 0; n--) {
2829 			printf("%s%s", sep, wpa_cipher(ie));
2830 			ie += 4, len -= 4;
2831 			sep = "+";
2832 		}
2833 
2834 		/* key management algorithms */
2835 		n = LE_READ_2(ie);
2836 		ie += 2, len -= 2;
2837 		sep = " km:";
2838 		for (; n > 0; n--) {
2839 			printf("%s%s", sep, wpa_keymgmt(ie));
2840 			ie += 4, len -= 4;
2841 			sep = "+";
2842 		}
2843 
2844 		if (len > 2)		/* optional capabilities */
2845 			printf(", caps 0x%x", LE_READ_2(ie));
2846 		printf(">");
2847 	}
2848 }
2849 
2850 static const char *
2851 rsn_cipher(const u_int8_t *sel)
2852 {
2853 #define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
2854 	u_int32_t w = LE_READ_4(sel);
2855 
2856 	switch (w) {
2857 	case RSN_SEL(RSN_CSE_NULL):
2858 		return "NONE";
2859 	case RSN_SEL(RSN_CSE_WEP40):
2860 		return "WEP40";
2861 	case RSN_SEL(RSN_CSE_WEP104):
2862 		return "WEP104";
2863 	case RSN_SEL(RSN_CSE_TKIP):
2864 		return "TKIP";
2865 	case RSN_SEL(RSN_CSE_CCMP):
2866 		return "AES-CCMP";
2867 	case RSN_SEL(RSN_CSE_WRAP):
2868 		return "AES-OCB";
2869 	}
2870 	return "?";
2871 #undef WPA_SEL
2872 }
2873 
2874 static const char *
2875 rsn_keymgmt(const u_int8_t *sel)
2876 {
2877 #define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
2878 	u_int32_t w = LE_READ_4(sel);
2879 
2880 	switch (w) {
2881 	case RSN_SEL(RSN_ASE_8021X_UNSPEC):
2882 		return "8021X-UNSPEC";
2883 	case RSN_SEL(RSN_ASE_8021X_PSK):
2884 		return "8021X-PSK";
2885 	case RSN_SEL(RSN_ASE_NONE):
2886 		return "NONE";
2887 	}
2888 	return "?";
2889 #undef RSN_SEL
2890 }
2891 
2892 static void
2893 printrsnie(const char *tag, const u_int8_t *ie, size_t ielen,
2894 	   int maxlen __unused)
2895 {
2896 	printf("%s", tag);
2897 	if (verbose) {
2898 		const char *sep;
2899 		int n;
2900 
2901 		ie += 2, ielen -= 2;
2902 
2903 		printf("<v%u", LE_READ_2(ie));
2904 		ie += 2, ielen -= 2;
2905 
2906 		printf(" mc:%s", rsn_cipher(ie));
2907 		ie += 4, ielen -= 4;
2908 
2909 		/* unicast ciphers */
2910 		n = LE_READ_2(ie);
2911 		ie += 2, ielen -= 2;
2912 		sep = " uc:";
2913 		for (; n > 0; n--) {
2914 			printf("%s%s", sep, rsn_cipher(ie));
2915 			ie += 4, ielen -= 4;
2916 			sep = "+";
2917 		}
2918 
2919 		/* key management algorithms */
2920 		n = LE_READ_2(ie);
2921 		ie += 2, ielen -= 2;
2922 		sep = " km:";
2923 		for (; n > 0; n--) {
2924 			printf("%s%s", sep, rsn_keymgmt(ie));
2925 			ie += 4, ielen -= 4;
2926 			sep = "+";
2927 		}
2928 
2929 		if (ielen > 2)		/* optional capabilities */
2930 			printf(", caps 0x%x", LE_READ_2(ie));
2931 		/* XXXPMKID */
2932 		printf(">");
2933 	}
2934 }
2935 
2936 #define BE_READ_2(p)					\
2937 	((u_int16_t)					\
2938 	 ((((const u_int8_t *)(p))[1]      ) |		\
2939 	  (((const u_int8_t *)(p))[0] <<  8)))
2940 
2941 static void
2942 printwpsie(const char *tag, const u_int8_t *ie, size_t ielen __unused,
2943 	   int maxlen __unused)
2944 {
2945 	u_int8_t len = ie[1];
2946 	uint16_t tlv_type;
2947 	uint16_t tlv_len;
2948 	uint16_t cfg_mthd;
2949 	int n;
2950 	int f;
2951 
2952 	printf("%s", tag);
2953 	if (verbose) {
2954 		static const char *dev_pass_id[] = {
2955 			"D",	/* Default (PIN) */
2956 			"U",	/* User-specified */
2957 			"M",	/* Machine-specified */
2958 			"K",	/* Rekey */
2959 			"P",	/* PushButton */
2960 			"R"	/* Registrar-specified */
2961 		};
2962 
2963 		ie +=6, len -= 4;		/* NB: len is payload only */
2964 
2965 		/* WPS IE in Beacon and Probe Resp frames have different fields */
2966 		printf("<");
2967 		while (len) {
2968 			tlv_type = BE_READ_2(ie);
2969 			tlv_len  = BE_READ_2(ie + 2);
2970 
2971 			/* some devices broadcast invalid WPS frames */
2972 			if (tlv_len > len) {
2973 				printf("bad frame length tlv_type=0x%02x "
2974 				    "tlv_len=%d len=%d", tlv_type, tlv_len,
2975 				    len);
2976 				break;
2977 			}
2978 
2979 			ie += 4, len -= 4;
2980 
2981 			switch (tlv_type) {
2982 			case IEEE80211_WPS_ATTR_VERSION:
2983 				printf("v:%d.%d", *ie >> 4, *ie & 0xf);
2984 				break;
2985 			case IEEE80211_WPS_ATTR_AP_SETUP_LOCKED:
2986 				printf(" ap_setup:%s", *ie ? "locked" :
2987 				    "unlocked");
2988 				break;
2989 			case IEEE80211_WPS_ATTR_CONFIG_METHODS:
2990 			case IEEE80211_WPS_ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
2991 				if (tlv_type == IEEE80211_WPS_ATTR_SELECTED_REGISTRAR_CONFIG_METHODS)
2992 					printf(" sel_reg_cfg_mthd:");
2993 				else
2994 					printf(" cfg_mthd:" );
2995 				cfg_mthd = BE_READ_2(ie);
2996 				f = 0;
2997 				for (n = 15; n >= 0; n--) {
2998 					if (f) {
2999 						printf(",");
3000 						f = 0;
3001 					}
3002 					switch (cfg_mthd & (1 << n)) {
3003 					case 0:
3004 						break;
3005 					case IEEE80211_WPS_CONFIG_USBA:
3006 						printf("usba");
3007 						f++;
3008 						break;
3009 					case IEEE80211_WPS_CONFIG_ETHERNET:
3010 						printf("ethernet");
3011 						f++;
3012 						break;
3013 					case IEEE80211_WPS_CONFIG_LABEL:
3014 						printf("label");
3015 						f++;
3016 						break;
3017 					case IEEE80211_WPS_CONFIG_DISPLAY:
3018 						if (!(cfg_mthd &
3019 						    (IEEE80211_WPS_CONFIG_VIRT_DISPLAY |
3020 						    IEEE80211_WPS_CONFIG_PHY_DISPLAY)))
3021 						    {
3022 							printf("display");
3023 							f++;
3024 						}
3025 						break;
3026 					case IEEE80211_WPS_CONFIG_EXT_NFC_TOKEN:
3027 						printf("ext_nfc_tokenk");
3028 						f++;
3029 						break;
3030 					case IEEE80211_WPS_CONFIG_INT_NFC_TOKEN:
3031 						printf("int_nfc_token");
3032 						f++;
3033 						break;
3034 					case IEEE80211_WPS_CONFIG_NFC_INTERFACE:
3035 						printf("nfc_interface");
3036 						f++;
3037 						break;
3038 					case IEEE80211_WPS_CONFIG_PUSHBUTTON:
3039 						if (!(cfg_mthd &
3040 						    (IEEE80211_WPS_CONFIG_VIRT_PUSHBUTTON |
3041 						    IEEE80211_WPS_CONFIG_PHY_PUSHBUTTON))) {
3042 							printf("push_button");
3043 							f++;
3044 						}
3045 						break;
3046 					case IEEE80211_WPS_CONFIG_KEYPAD:
3047 						printf("keypad");
3048 						f++;
3049 						break;
3050 					case IEEE80211_WPS_CONFIG_VIRT_PUSHBUTTON:
3051 						printf("virtual_push_button");
3052 						f++;
3053 						break;
3054 					case IEEE80211_WPS_CONFIG_PHY_PUSHBUTTON:
3055 						printf("physical_push_button");
3056 						f++;
3057 						break;
3058 					case IEEE80211_WPS_CONFIG_P2PS:
3059 						printf("p2ps");
3060 						f++;
3061 						break;
3062 					case IEEE80211_WPS_CONFIG_VIRT_DISPLAY:
3063 						printf("virtual_display");
3064 						f++;
3065 						break;
3066 					case IEEE80211_WPS_CONFIG_PHY_DISPLAY:
3067 						printf("physical_display");
3068 						f++;
3069 						break;
3070 					default:
3071 						printf("unknown_wps_config<%04x>",
3072 						    cfg_mthd & (1 << n));
3073 						f++;
3074 						break;
3075 					}
3076 				}
3077 				break;
3078 			case IEEE80211_WPS_ATTR_DEV_NAME:
3079 				printf(" device_name:<%.*s>", tlv_len, ie);
3080 				break;
3081 			case IEEE80211_WPS_ATTR_DEV_PASSWORD_ID:
3082 				n = LE_READ_2(ie);
3083 				if (n < (int)nitems(dev_pass_id))
3084 					printf(" dpi:%s", dev_pass_id[n]);
3085 				break;
3086 			case IEEE80211_WPS_ATTR_MANUFACTURER:
3087 				printf(" manufacturer:<%.*s>", tlv_len, ie);
3088 				break;
3089 			case IEEE80211_WPS_ATTR_MODEL_NAME:
3090 				printf(" model_name:<%.*s>", tlv_len, ie);
3091 				break;
3092 			case IEEE80211_WPS_ATTR_MODEL_NUMBER:
3093 				printf(" model_number:<%.*s>", tlv_len, ie);
3094 				break;
3095 			case IEEE80211_WPS_ATTR_PRIMARY_DEV_TYPE:
3096 				printf(" prim_dev:");
3097 				for (n = 0; n < tlv_len; n++)
3098 					printf("%02x", ie[n]);
3099 				break;
3100 			case IEEE80211_WPS_ATTR_RF_BANDS:
3101 				printf(" rf:");
3102 				f = 0;
3103 				for (n = 7; n >= 0; n--) {
3104 					if (f) {
3105 						printf(",");
3106 						f = 0;
3107 					}
3108 					switch (*ie & (1 << n)) {
3109 					case 0:
3110 						break;
3111 					case IEEE80211_WPS_RF_BAND_24GHZ:
3112 						printf("2.4Ghz");
3113 						f++;
3114 						break;
3115 					case IEEE80211_WPS_RF_BAND_50GHZ:
3116 						printf("5Ghz");
3117 						f++;
3118 						break;
3119 					case IEEE80211_WPS_RF_BAND_600GHZ:
3120 						printf("60Ghz");
3121 						f++;
3122 						break;
3123 					default:
3124 						printf("unknown<%02x>",
3125 						    *ie & (1 << n));
3126 						f++;
3127 						break;
3128 					}
3129 				}
3130 				break;
3131 			case IEEE80211_WPS_ATTR_RESPONSE_TYPE:
3132 				printf(" resp_type:0x%02x", *ie);
3133 				break;
3134 			case IEEE80211_WPS_ATTR_SELECTED_REGISTRAR:
3135 				printf(" sel:%s", *ie ? "T" : "F");
3136 				break;
3137 			case IEEE80211_WPS_ATTR_SERIAL_NUMBER:
3138 				printf(" serial_number:<%.*s>", tlv_len, ie);
3139 				break;
3140 			case IEEE80211_WPS_ATTR_UUID_E:
3141 				printf(" uuid-e:");
3142 				for (n = 0; n < (tlv_len - 1); n++)
3143 					printf("%02x-", ie[n]);
3144 				printf("%02x", ie[n]);
3145 				break;
3146 			case IEEE80211_WPS_ATTR_VENDOR_EXT:
3147 				printf(" vendor:");
3148 				for (n = 0; n < tlv_len; n++)
3149 					printf("%02x", ie[n]);
3150 				break;
3151 			case IEEE80211_WPS_ATTR_WPS_STATE:
3152 				switch (*ie) {
3153 				case IEEE80211_WPS_STATE_NOT_CONFIGURED:
3154 					printf(" state:N");
3155 					break;
3156 				case IEEE80211_WPS_STATE_CONFIGURED:
3157 					printf(" state:C");
3158 					break;
3159 				default:
3160 					printf(" state:B<%02x>", *ie);
3161 					break;
3162 				}
3163 				break;
3164 			default:
3165 				printf(" unknown_wps_attr:0x%x", tlv_type);
3166 				break;
3167 			}
3168 			ie += tlv_len, len -= tlv_len;
3169 		}
3170 		printf(">");
3171 	}
3172 }
3173 
3174 static void
3175 printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen,
3176 	    int maxlen __unused)
3177 {
3178 	printf("%s", tag);
3179 	if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
3180 		const struct ieee80211_tdma_param *tdma =
3181 		   (const struct ieee80211_tdma_param *) ie;
3182 
3183 		/* XXX tstamp */
3184 		printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
3185 		    tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
3186 		    LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
3187 		    tdma->tdma_inuse[0]);
3188 	}
3189 }
3190 
3191 /*
3192  * Copy the ssid string contents into buf, truncating to fit.  If the
3193  * ssid is entirely printable then just copy intact.  Otherwise convert
3194  * to hexadecimal.  If the result is truncated then replace the last
3195  * three characters with "...".
3196  */
3197 static int
3198 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
3199 {
3200 	const u_int8_t *p;
3201 	size_t maxlen;
3202 	size_t i;
3203 
3204 	if (essid_len > bufsize)
3205 		maxlen = bufsize;
3206 	else
3207 		maxlen = essid_len;
3208 	/* determine printable or not */
3209 	for (i = 0, p = essid; i < maxlen; i++, p++) {
3210 		if (*p < ' ' || *p > 0x7e)
3211 			break;
3212 	}
3213 	if (i != maxlen) {		/* not printable, print as hex */
3214 		if (bufsize < 3)
3215 			return 0;
3216 		strlcpy(buf, "0x", bufsize);
3217 		bufsize -= 2;
3218 		p = essid;
3219 		for (i = 0; i < maxlen && bufsize >= 2; i++) {
3220 			sprintf(&buf[2+2*i], "%02x", p[i]);
3221 			bufsize -= 2;
3222 		}
3223 		if (i != essid_len)
3224 			memcpy(&buf[2+2*i-3], "...", 3);
3225 	} else {			/* printable, truncate as needed */
3226 		memcpy(buf, essid, maxlen);
3227 		if (maxlen != essid_len)
3228 			memcpy(&buf[maxlen-3], "...", 3);
3229 	}
3230 	return maxlen;
3231 }
3232 
3233 static void
3234 printssid(const char *tag, const u_int8_t *ie, size_t ielen __unused,
3235 	  int maxlen)
3236 {
3237 	char ssid[2*IEEE80211_NWID_LEN+1];
3238 
3239 	printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
3240 }
3241 
3242 static void
3243 printrates(const char *tag, const u_int8_t *ie, size_t ielen,
3244 	   int maxlen __unused)
3245 {
3246 	const char *sep;
3247 	size_t i;
3248 
3249 	printf("%s", tag);
3250 	sep = "<";
3251 	for (i = 2; i < ielen; i++) {
3252 		printf("%s%s%d", sep,
3253 		    ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
3254 		    ie[i] & IEEE80211_RATE_VAL);
3255 		sep = ",";
3256 	}
3257 	printf(">");
3258 }
3259 
3260 static void
3261 printcountry(const char *tag, const u_int8_t *ie, size_t ielen __unused,
3262 	     int maxlen __unused)
3263 {
3264 	const struct ieee80211_country_ie *cie =
3265 	   (const struct ieee80211_country_ie *) ie;
3266 	size_t i, nbands, schan, nchan;
3267 
3268 	printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
3269 	nbands = (cie->len - 3) / sizeof(cie->band[0]);
3270 	for (i = 0; i < nbands; i++) {
3271 		schan = cie->band[i].schan;
3272 		nchan = cie->band[i].nchan;
3273 		if (nchan != 1)
3274 			printf(" %zu-%zu,%u", schan, schan + nchan-1,
3275 			    cie->band[i].maxtxpwr);
3276 		else
3277 			printf(" %zu,%u", schan, cie->band[i].maxtxpwr);
3278 	}
3279 	printf(">");
3280 }
3281 
3282 /* unaligned little endian access */
3283 #define LE_READ_4(p)					\
3284 	((u_int32_t)					\
3285 	 ((((const u_int8_t *)(p))[0]      ) |		\
3286 	  (((const u_int8_t *)(p))[1] <<  8) |		\
3287 	  (((const u_int8_t *)(p))[2] << 16) |		\
3288 	  (((const u_int8_t *)(p))[3] << 24)))
3289 
3290 static __inline int
3291 iswpaoui(const u_int8_t *frm)
3292 {
3293 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
3294 }
3295 
3296 static __inline int
3297 iswmeinfo(const u_int8_t *frm)
3298 {
3299 	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3300 		frm[6] == WME_INFO_OUI_SUBTYPE;
3301 }
3302 
3303 static __inline int
3304 iswmeparam(const u_int8_t *frm)
3305 {
3306 	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3307 		frm[6] == WME_PARAM_OUI_SUBTYPE;
3308 }
3309 
3310 static __inline int
3311 isatherosoui(const u_int8_t *frm)
3312 {
3313 	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
3314 }
3315 
3316 static __inline int
3317 istdmaoui(const uint8_t *frm)
3318 {
3319 	return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
3320 }
3321 
3322 static __inline int
3323 iswpsoui(const uint8_t *frm)
3324 {
3325 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
3326 }
3327 
3328 static const char *
3329 iename(int elemid)
3330 {
3331 	static char iename_buf[64];
3332 	switch (elemid) {
3333 	case IEEE80211_ELEMID_FHPARMS:	return " FHPARMS";
3334 	case IEEE80211_ELEMID_CFPARMS:	return " CFPARMS";
3335 	case IEEE80211_ELEMID_TIM:	return " TIM";
3336 	case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
3337 	case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
3338 	case IEEE80211_ELEMID_PWRCNSTR:	return " PWRCNSTR";
3339 	case IEEE80211_ELEMID_PWRCAP:	return " PWRCAP";
3340 	case IEEE80211_ELEMID_TPCREQ:	return " TPCREQ";
3341 	case IEEE80211_ELEMID_TPCREP:	return " TPCREP";
3342 	case IEEE80211_ELEMID_SUPPCHAN:	return " SUPPCHAN";
3343 	case IEEE80211_ELEMID_CSA:	return " CSA";
3344 	case IEEE80211_ELEMID_MEASREQ:	return " MEASREQ";
3345 	case IEEE80211_ELEMID_MEASREP:	return " MEASREP";
3346 	case IEEE80211_ELEMID_QUIET:	return " QUIET";
3347 	case IEEE80211_ELEMID_IBSSDFS:	return " IBSSDFS";
3348 	case IEEE80211_ELEMID_RESERVED_47:
3349 					return " RESERVED_47";
3350 	case IEEE80211_ELEMID_MOBILITY_DOMAIN:
3351 					return " MOBILITY_DOMAIN";
3352 	case IEEE80211_ELEMID_RRM_ENACAPS:
3353 					return " RRM_ENCAPS";
3354 	case IEEE80211_ELEMID_OVERLAP_BSS_SCAN_PARAM:
3355 					return " OVERLAP_BSS";
3356 	case IEEE80211_ELEMID_TPC:	return " TPC";
3357 	case IEEE80211_ELEMID_CCKM:	return " CCKM";
3358 	case IEEE80211_ELEMID_EXTCAP:	return " EXTCAP";
3359 	}
3360 	snprintf(iename_buf, sizeof(iename_buf), " UNKNOWN_ELEMID_%d",
3361 	    elemid);
3362 	return (const char *) iename_buf;
3363 }
3364 
3365 static void
3366 printies(const u_int8_t *vp, int ielen, int maxcols)
3367 {
3368 	while (ielen > 0) {
3369 		switch (vp[0]) {
3370 		case IEEE80211_ELEMID_SSID:
3371 			if (verbose)
3372 				printssid(" SSID", vp, 2+vp[1], maxcols);
3373 			break;
3374 		case IEEE80211_ELEMID_RATES:
3375 		case IEEE80211_ELEMID_XRATES:
3376 			if (verbose)
3377 				printrates(vp[0] == IEEE80211_ELEMID_RATES ?
3378 				    " RATES" : " XRATES", vp, 2+vp[1], maxcols);
3379 			break;
3380 		case IEEE80211_ELEMID_DSPARMS:
3381 			if (verbose)
3382 				printf(" DSPARMS<%u>", vp[2]);
3383 			break;
3384 		case IEEE80211_ELEMID_COUNTRY:
3385 			if (verbose)
3386 				printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
3387 			break;
3388 		case IEEE80211_ELEMID_ERP:
3389 			if (verbose)
3390 				printf(" ERP<0x%x>", vp[2]);
3391 			break;
3392 		case IEEE80211_ELEMID_VENDOR:
3393 			if (iswpaoui(vp))
3394 				printwpaie(" WPA", vp, 2+vp[1], maxcols);
3395 			else if (iswmeinfo(vp))
3396 				printwmeinfo(" WME", vp, 2+vp[1], maxcols);
3397 			else if (iswmeparam(vp))
3398 				printwmeparam(" WME", vp, 2+vp[1], maxcols);
3399 			else if (isatherosoui(vp))
3400 				printathie(" ATH", vp, 2+vp[1], maxcols);
3401 			else if (iswpsoui(vp))
3402 				printwpsie(" WPS", vp, 2+vp[1], maxcols);
3403 			else if (istdmaoui(vp))
3404 				printtdmaie(" TDMA", vp, 2+vp[1], maxcols);
3405 			else if (verbose)
3406 				printie(" VEN", vp, 2+vp[1], maxcols);
3407 			break;
3408 		case IEEE80211_ELEMID_RSN:
3409 			printrsnie(" RSN", vp, 2+vp[1], maxcols);
3410 			break;
3411 		case IEEE80211_ELEMID_HTCAP:
3412 			printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
3413 			break;
3414 		case IEEE80211_ELEMID_HTINFO:
3415 			if (verbose)
3416 				printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
3417 			break;
3418 		case IEEE80211_ELEMID_MESHID:
3419 			if (verbose)
3420 				printssid(" MESHID", vp, 2+vp[1], maxcols);
3421 			break;
3422 		case IEEE80211_ELEMID_MESHCONF:
3423 			printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols);
3424 			break;
3425 		default:
3426 			if (verbose)
3427 				printie(iename(vp[0]), vp, 2+vp[1], maxcols);
3428 			break;
3429 		}
3430 		ielen -= 2+vp[1];
3431 		vp += 2+vp[1];
3432 	}
3433 }
3434 
3435 static void
3436 printmimo(const struct ieee80211_mimo_info *mi)
3437 {
3438 	/* NB: don't muddy display unless there's something to show */
3439 	if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) {
3440 		/* XXX ignore EVM for now */
3441 		printf(" (rssi %d:%d:%d nf %d:%d:%d)",
3442 		    mi->rssi[0], mi->rssi[1], mi->rssi[2],
3443 		    mi->noise[0], mi->noise[1], mi->noise[2]);
3444 	}
3445 }
3446 
3447 static void
3448 list_scan(int s, int long_ssids)
3449 {
3450 	uint8_t buf[24*1024];
3451 	char ssid[IEEE80211_NWID_LEN+1];
3452 	const uint8_t *cp;
3453 	size_t len, ssidmax, idlen;
3454 
3455 	if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
3456 		errx(1, "unable to get scan results");
3457 	if (len < sizeof(struct ieee80211req_scan_result))
3458 		return;
3459 
3460 	getchaninfo(s);
3461 
3462 	ssidmax = (verbose || long_ssids) ? IEEE80211_NWID_LEN - 1 : 14;
3463 	printf("%-*.*s  %-17.17s  %4s %4s  %-7s  %3s %4s\n"
3464 		, (int)ssidmax, (int)ssidmax, "SSID/MESH ID"
3465 		, "BSSID"
3466 		, "CHAN"
3467 		, "RATE"
3468 		, " S:N"
3469 		, "INT"
3470 		, "CAPS"
3471 	);
3472 	cp = buf;
3473 	do {
3474 		const struct ieee80211req_scan_result *sr;
3475 		const uint8_t *vp, *idp;
3476 
3477 		sr = (const struct ieee80211req_scan_result *) cp;
3478 		vp = cp + sr->isr_ie_off;
3479 		if (sr->isr_meshid_len) {
3480 			idp = vp + sr->isr_ssid_len;
3481 			idlen = sr->isr_meshid_len;
3482 		} else {
3483 			idp = vp;
3484 			idlen = sr->isr_ssid_len;
3485 		}
3486 		printf("%-*.*s  %s  %3d  %3dM %3d:%-3d  %3d %-4.4s"
3487 			, (int)ssidmax
3488 			, copy_essid(ssid, ssidmax, idp, idlen)
3489 			, ssid
3490 			, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
3491 			, ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
3492 			, getmaxrate(sr->isr_rates, sr->isr_nrates)
3493 			, (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
3494 			, sr->isr_intval
3495 			, getcaps(sr->isr_capinfo)
3496 		);
3497 		printies(vp + sr->isr_ssid_len + sr->isr_meshid_len,
3498 		    sr->isr_ie_len, 24);
3499 		printf("\n");
3500 		cp += sr->isr_len, len -= sr->isr_len;
3501 	} while (len >= sizeof(struct ieee80211req_scan_result));
3502 }
3503 
3504 static void
3505 scan_and_wait(int s)
3506 {
3507 	struct ieee80211_scan_req sr;
3508 	struct ieee80211req ireq;
3509 	int sroute;
3510 
3511 	sroute = socket(PF_ROUTE, SOCK_RAW, 0);
3512 	if (sroute < 0) {
3513 		perror("socket(PF_ROUTE,SOCK_RAW)");
3514 		return;
3515 	}
3516 	memset(&ireq, 0, sizeof(ireq));
3517 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
3518 	ireq.i_type = IEEE80211_IOC_SCAN_REQ;
3519 
3520 	memset(&sr, 0, sizeof(sr));
3521 	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
3522 		    | IEEE80211_IOC_SCAN_NOPICK
3523 		    | IEEE80211_IOC_SCAN_ONCE;
3524 	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
3525 	sr.sr_nssid = 0;
3526 
3527 	ireq.i_data = &sr;
3528 	ireq.i_len = sizeof(sr);
3529 	/* NB: only root can trigger a scan so ignore errors */
3530 	if (ioctl(s, SIOCS80211, &ireq) >= 0) {
3531 		char buf[2048];
3532 		struct if_announcemsghdr *ifan;
3533 		struct rt_msghdr *rtm;
3534 
3535 		do {
3536 			if (read(sroute, buf, sizeof(buf)) < 0) {
3537 				perror("read(PF_ROUTE)");
3538 				break;
3539 			}
3540 			rtm = (struct rt_msghdr *) buf;
3541 			if (rtm->rtm_version != RTM_VERSION)
3542 				break;
3543 			ifan = (struct if_announcemsghdr *) rtm;
3544 		} while (rtm->rtm_type != RTM_IEEE80211 ||
3545 		    ifan->ifan_what != RTM_IEEE80211_SCAN);
3546 	}
3547 	close(sroute);
3548 }
3549 
3550 static void
3551 set80211scan(const char *val __unused, int d __unused, int s,
3552 	     const struct afswtch *afp __unused)
3553 {
3554 	scan_and_wait(s);
3555 	list_scan(s, 0);
3556 }
3557 
3558 static enum ieee80211_opmode get80211opmode(int s);
3559 
3560 static int
3561 gettxseq(const struct ieee80211req_sta_info *si)
3562 {
3563 	int i, txseq;
3564 
3565 	if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
3566 		return si->isi_txseqs[0];
3567 	/* XXX not right but usually what folks want */
3568 	txseq = 0;
3569 	for (i = 0; i < IEEE80211_TID_SIZE; i++)
3570 		if (si->isi_txseqs[i] > txseq)
3571 			txseq = si->isi_txseqs[i];
3572 	return txseq;
3573 }
3574 
3575 static int
3576 getrxseq(const struct ieee80211req_sta_info *si)
3577 {
3578 	int i, rxseq;
3579 
3580 	if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
3581 		return si->isi_rxseqs[0];
3582 	/* XXX not right but usually what folks want */
3583 	rxseq = 0;
3584 	for (i = 0; i < IEEE80211_TID_SIZE; i++)
3585 		if (si->isi_rxseqs[i] > rxseq)
3586 			rxseq = si->isi_rxseqs[i];
3587 	return rxseq;
3588 }
3589 
3590 static void
3591 list_stations(int s)
3592 {
3593 	union {
3594 		struct ieee80211req_sta_req req;
3595 		uint8_t buf[24*1024];
3596 	} u;
3597 	enum ieee80211_opmode opmode = get80211opmode(s);
3598 	const uint8_t *cp;
3599 	size_t len;
3600 
3601 	/* broadcast address =>'s get all stations */
3602 	memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
3603 	if (opmode == IEEE80211_M_STA) {
3604 		/*
3605 		 * Get information about the associated AP.
3606 		 */
3607 		get80211(s, IEEE80211_IOC_BSSID,
3608 			 u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
3609 	}
3610 	if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
3611 		errx(1, "unable to get station information");
3612 	if (len < sizeof(struct ieee80211req_sta_info))
3613 		return;
3614 
3615 	getchaninfo(s);
3616 
3617 	if (opmode == IEEE80211_M_MBSS) {
3618 		printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
3619 			, "ADDR"
3620 			, "CHAN"
3621 			, "LOCAL"
3622 			, "PEER"
3623 			, "STATE"
3624 			, "RATE"
3625 			, "RSSI"
3626 			, "IDLE"
3627 			, "TXSEQ"
3628 			, "RXSEQ"
3629 		);
3630 	} else {
3631 		printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
3632 			, "ADDR"
3633 			, "AID"
3634 			, "CHAN"
3635 			, "RATE"
3636 			, "RSSI"
3637 			, "IDLE"
3638 			, "TXSEQ"
3639 			, "RXSEQ"
3640 			, "CAPS"
3641 			, "FLAG"
3642 		);
3643 	}
3644 	cp = (const uint8_t *) u.req.info;
3645 	do {
3646 		const struct ieee80211req_sta_info *si;
3647 
3648 		si = (const struct ieee80211req_sta_info *) cp;
3649 		if (si->isi_len < sizeof(*si))
3650 			break;
3651 		if (opmode == IEEE80211_M_MBSS) {
3652 			printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
3653 				, ether_ntoa((const struct ether_addr*)
3654 				    si->isi_macaddr)
3655 				, ieee80211_mhz2ieee(si->isi_freq,
3656 				    si->isi_flags)
3657 				, si->isi_localid
3658 				, si->isi_peerid
3659 				, mesh_linkstate_string(si->isi_peerstate)
3660 				, si->isi_txmbps/2
3661 				, si->isi_rssi/2.
3662 				, si->isi_inact
3663 				, gettxseq(si)
3664 				, getrxseq(si)
3665 			);
3666 		} else {
3667 			printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
3668 				, ether_ntoa((const struct ether_addr*)
3669 				    si->isi_macaddr)
3670 				, IEEE80211_AID(si->isi_associd)
3671 				, ieee80211_mhz2ieee(si->isi_freq,
3672 				    si->isi_flags)
3673 				, si->isi_txmbps/2
3674 				, si->isi_rssi/2.
3675 				, si->isi_inact
3676 				, gettxseq(si)
3677 				, getrxseq(si)
3678 				, getcaps(si->isi_capinfo)
3679 				, getflags(si->isi_state)
3680 			);
3681 		}
3682 		printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
3683 		printmimo(&si->isi_mimo);
3684 		printf("\n");
3685 		cp += si->isi_len, len -= si->isi_len;
3686 	} while (len >= sizeof(struct ieee80211req_sta_info));
3687 }
3688 
3689 static const char *
3690 mesh_linkstate_string(uint8_t state)
3691 {
3692 	static const char *state_names[] = {
3693 	    [0] = "IDLE",
3694 	    [1] = "OPEN-TX",
3695 	    [2] = "OPEN-RX",
3696 	    [3] = "CONF-RX",
3697 	    [4] = "ESTAB",
3698 	    [5] = "HOLDING",
3699 	};
3700 
3701 	if (state >= nitems(state_names)) {
3702 		static char buf[10];
3703 		snprintf(buf, sizeof(buf), "#%u", state);
3704 		return buf;
3705 	} else {
3706 		return state_names[state];
3707 	}
3708 }
3709 
3710 static const char *
3711 get_chaninfo(const struct ieee80211_channel *c, int precise,
3712 	char buf[], size_t bsize)
3713 {
3714 	buf[0] = '\0';
3715 	if (IEEE80211_IS_CHAN_FHSS(c))
3716 		strlcat(buf, " FHSS", bsize);
3717 	if (IEEE80211_IS_CHAN_A(c))
3718 		strlcat(buf, " 11a", bsize);
3719 	else if (IEEE80211_IS_CHAN_ANYG(c))
3720 		strlcat(buf, " 11g", bsize);
3721 	else if (IEEE80211_IS_CHAN_B(c))
3722 		strlcat(buf, " 11b", bsize);
3723 	if (IEEE80211_IS_CHAN_HALF(c))
3724 		strlcat(buf, "/10MHz", bsize);
3725 	if (IEEE80211_IS_CHAN_QUARTER(c))
3726 		strlcat(buf, "/5MHz", bsize);
3727 	if (IEEE80211_IS_CHAN_TURBO(c))
3728 		strlcat(buf, " Turbo", bsize);
3729 	if (precise) {
3730 		if (IEEE80211_IS_CHAN_HT20(c))
3731 			strlcat(buf, " ht/20", bsize);
3732 		else if (IEEE80211_IS_CHAN_HT40D(c))
3733 			strlcat(buf, " ht/40-", bsize);
3734 		else if (IEEE80211_IS_CHAN_HT40U(c))
3735 			strlcat(buf, " ht/40+", bsize);
3736 	} else {
3737 		if (IEEE80211_IS_CHAN_HT(c))
3738 			strlcat(buf, " ht", bsize);
3739 	}
3740 	return buf;
3741 }
3742 
3743 static void
3744 print_chaninfo(const struct ieee80211_channel *c, int verb)
3745 {
3746 	char buf[14];
3747 
3748 	printf("Channel %3u : %u%c MHz%-14.14s",
3749 		ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
3750 		IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
3751 		get_chaninfo(c, verb, buf, sizeof(buf)));
3752 }
3753 
3754 static int
3755 chanpref(const struct ieee80211_channel *c)
3756 {
3757 	if (IEEE80211_IS_CHAN_HT40(c))
3758 		return 40;
3759 	if (IEEE80211_IS_CHAN_HT20(c))
3760 		return 30;
3761 	if (IEEE80211_IS_CHAN_HALF(c))
3762 		return 10;
3763 	if (IEEE80211_IS_CHAN_QUARTER(c))
3764 		return 5;
3765 	if (IEEE80211_IS_CHAN_TURBO(c))
3766 		return 25;
3767 	if (IEEE80211_IS_CHAN_A(c))
3768 		return 20;
3769 	if (IEEE80211_IS_CHAN_G(c))
3770 		return 20;
3771 	if (IEEE80211_IS_CHAN_B(c))
3772 		return 15;
3773 	if (IEEE80211_IS_CHAN_PUREG(c))
3774 		return 15;
3775 	return 0;
3776 }
3777 
3778 static void
3779 print_channels(int s, const struct ieee80211req_chaninfo *chans,
3780 	bool allchans, bool verb)
3781 {
3782 	struct ieee80211req_chaninfo *achans;
3783 	uint8_t reported[IEEE80211_CHAN_BYTES];
3784 	const struct ieee80211_channel *c;
3785 	size_t i, half;
3786 
3787 	achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
3788 	if (achans == NULL)
3789 		errx(1, "no space for active channel list");
3790 	achans->ic_nchans = 0;
3791 	memset(reported, 0, sizeof(reported));
3792 	if (!allchans) {
3793 		struct ieee80211req_chanlist active;
3794 
3795 		if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
3796 			errx(1, "unable to get active channel list");
3797 		for (i = 0; i < chans->ic_nchans; i++) {
3798 			c = &chans->ic_chans[i];
3799 			if (!isset(active.ic_channels, c->ic_ieee))
3800 				continue;
3801 			/*
3802 			 * Suppress compatible duplicates unless
3803 			 * verbose.  The kernel gives us it's
3804 			 * complete channel list which has separate
3805 			 * entries for 11g/11b and 11a/turbo.
3806 			 */
3807 			if (isset(reported, c->ic_ieee) && !verb) {
3808 				/* XXX we assume duplicates are adjacent */
3809 				achans->ic_chans[achans->ic_nchans-1] = *c;
3810 			} else {
3811 				achans->ic_chans[achans->ic_nchans++] = *c;
3812 				setbit(reported, c->ic_ieee);
3813 			}
3814 		}
3815 	} else {
3816 		for (i = 0; i < chans->ic_nchans; i++) {
3817 			c = &chans->ic_chans[i];
3818 			/* suppress duplicates as above */
3819 			if (isset(reported, c->ic_ieee) && !verb) {
3820 				/* XXX we assume duplicates are adjacent */
3821 				struct ieee80211_channel *a =
3822 				    &achans->ic_chans[achans->ic_nchans-1];
3823 				if (chanpref(c) > chanpref(a))
3824 					*a = *c;
3825 			} else {
3826 				achans->ic_chans[achans->ic_nchans++] = *c;
3827 				setbit(reported, c->ic_ieee);
3828 			}
3829 		}
3830 	}
3831 	half = achans->ic_nchans / 2;
3832 	if (achans->ic_nchans % 2)
3833 		half++;
3834 
3835 	for (i = 0; i < achans->ic_nchans / 2; i++) {
3836 		print_chaninfo(&achans->ic_chans[i], verb);
3837 		print_chaninfo(&achans->ic_chans[half+i], verb);
3838 		printf("\n");
3839 	}
3840 	if (achans->ic_nchans % 2) {
3841 		print_chaninfo(&achans->ic_chans[i], verb);
3842 		printf("\n");
3843 	}
3844 	free(achans);
3845 }
3846 
3847 static void
3848 list_channels(int s, bool allchans)
3849 {
3850 	getchaninfo(s);
3851 	print_channels(s, chaninfo, allchans, verbose);
3852 }
3853 
3854 static void
3855 print_txpow(const struct ieee80211_channel *c)
3856 {
3857 	printf("Channel %3u : %u MHz %3.1f reg %2d  ",
3858 	    c->ic_ieee, c->ic_freq,
3859 	    c->ic_maxpower/2., c->ic_maxregpower);
3860 }
3861 
3862 static void
3863 print_txpow_verbose(const struct ieee80211_channel *c)
3864 {
3865 	print_chaninfo(c, 1);
3866 	printf("min %4.1f dBm  max %3.1f dBm  reg %2d dBm",
3867 	    c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
3868 	/* indicate where regulatory cap limits power use */
3869 	if (c->ic_maxpower > 2*c->ic_maxregpower)
3870 		printf(" <");
3871 }
3872 
3873 static void
3874 list_txpow(int s)
3875 {
3876 	struct ieee80211req_chaninfo *achans;
3877 	uint8_t reported[IEEE80211_CHAN_BYTES];
3878 	struct ieee80211_channel *c, *prev;
3879 	size_t i, half;
3880 
3881 	getchaninfo(s);
3882 	achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
3883 	if (achans == NULL)
3884 		errx(1, "no space for active channel list");
3885 	achans->ic_nchans = 0;
3886 	memset(reported, 0, sizeof(reported));
3887 	for (i = 0; i < chaninfo->ic_nchans; i++) {
3888 		c = &chaninfo->ic_chans[i];
3889 		/* suppress duplicates as above */
3890 		if (isset(reported, c->ic_ieee) && !verbose) {
3891 			/* XXX we assume duplicates are adjacent */
3892 			prev = &achans->ic_chans[achans->ic_nchans-1];
3893 			/* display highest power on channel */
3894 			if (c->ic_maxpower > prev->ic_maxpower)
3895 				*prev = *c;
3896 		} else {
3897 			achans->ic_chans[achans->ic_nchans++] = *c;
3898 			setbit(reported, c->ic_ieee);
3899 		}
3900 	}
3901 	if (!verbose) {
3902 		half = achans->ic_nchans / 2;
3903 		if (achans->ic_nchans % 2)
3904 			half++;
3905 
3906 		for (i = 0; i < achans->ic_nchans / 2; i++) {
3907 			print_txpow(&achans->ic_chans[i]);
3908 			print_txpow(&achans->ic_chans[half+i]);
3909 			printf("\n");
3910 		}
3911 		if (achans->ic_nchans % 2) {
3912 			print_txpow(&achans->ic_chans[i]);
3913 			printf("\n");
3914 		}
3915 	} else {
3916 		for (i = 0; i < achans->ic_nchans; i++) {
3917 			print_txpow_verbose(&achans->ic_chans[i]);
3918 			printf("\n");
3919 		}
3920 	}
3921 	free(achans);
3922 }
3923 
3924 static void
3925 list_keys(int s __unused)
3926 {
3927 }
3928 
3929 #define	IEEE80211_C_BITS \
3930 	"\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
3931 	"\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
3932 	"\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
3933 	"\37TXFRAG\40TDMA"
3934 
3935 static void
3936 list_capabilities(int s)
3937 {
3938 	struct ieee80211_devcaps_req *dc;
3939 
3940 	if (verbose)
3941 		dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
3942 	else
3943 		dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
3944 	if (dc == NULL)
3945 		errx(1, "no space for device capabilities");
3946 	dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
3947 	getdevcaps(s, dc);
3948 	printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
3949 	if (dc->dc_cryptocaps != 0 || verbose) {
3950 		putchar('\n');
3951 		printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
3952 	}
3953 	if (dc->dc_htcaps != 0 || verbose) {
3954 		putchar('\n');
3955 		printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
3956 	}
3957 	putchar('\n');
3958 	if (verbose) {
3959 		chaninfo = &dc->dc_chaninfo;	/* XXX */
3960 		print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose);
3961 	}
3962 	free(dc);
3963 }
3964 
3965 static int
3966 get80211wme(int s, int param, int ac, int *val)
3967 {
3968 	struct ieee80211req ireq;
3969 
3970 	memset(&ireq, 0, sizeof(ireq));
3971 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
3972 	ireq.i_type = param;
3973 	ireq.i_len = ac;
3974 	if (ioctl(s, SIOCG80211, &ireq) < 0) {
3975 		warn("cannot get WME parameter %d, ac %d%s",
3976 		    param, ac & IEEE80211_WMEPARAM_VAL,
3977 		    ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
3978 		return -1;
3979 	}
3980 	*val = ireq.i_val;
3981 	return 0;
3982 }
3983 
3984 static void
3985 list_wme_aci(int s, const char *tag, int ac)
3986 {
3987 	int val;
3988 
3989 	printf("\t%s", tag);
3990 
3991 	/* show WME BSS parameters */
3992 	if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
3993 		printf(" cwmin %2u", val);
3994 	if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
3995 		printf(" cwmax %2u", val);
3996 	if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
3997 		printf(" aifs %2u", val);
3998 	if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
3999 		printf(" txopLimit %3u", val);
4000 	if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
4001 		if (val)
4002 			printf(" acm");
4003 		else if (verbose)
4004 			printf(" -acm");
4005 	}
4006 	/* !BSS only */
4007 	if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
4008 		if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
4009 			if (!val)
4010 				printf(" -ack");
4011 			else if (verbose)
4012 				printf(" ack");
4013 		}
4014 	}
4015 	printf("\n");
4016 }
4017 
4018 static void
4019 list_wme(int s)
4020 {
4021 	static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
4022 	int ac;
4023 
4024 	if (verbose) {
4025 		/* display both BSS and local settings */
4026 		for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
4027 	again:
4028 			if (ac & IEEE80211_WMEPARAM_BSS)
4029 				list_wme_aci(s, "     ", ac);
4030 			else
4031 				list_wme_aci(s, acnames[ac], ac);
4032 			if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
4033 				ac |= IEEE80211_WMEPARAM_BSS;
4034 				goto again;
4035 			} else
4036 				ac &= ~IEEE80211_WMEPARAM_BSS;
4037 		}
4038 	} else {
4039 		/* display only channel settings */
4040 		for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++)
4041 			list_wme_aci(s, acnames[ac], ac);
4042 	}
4043 }
4044 
4045 static void
4046 list_roam(int s)
4047 {
4048 	const struct ieee80211_roamparam *rp;
4049 	int mode;
4050 
4051 	getroam(s);
4052 	for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
4053 		rp = &roamparams.params[mode];
4054 		if (rp->rssi == 0 && rp->rate == 0)
4055 			continue;
4056 		if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
4057 			if (rp->rssi & 1)
4058 				LINE_CHECK("roam:%-7.7s rssi %2u.5dBm  MCS %2u    ",
4059 				    modename[mode], rp->rssi/2,
4060 				    rp->rate &~ IEEE80211_RATE_MCS);
4061 			else
4062 				LINE_CHECK("roam:%-7.7s rssi %4udBm  MCS %2u    ",
4063 				    modename[mode], rp->rssi/2,
4064 				    rp->rate &~ IEEE80211_RATE_MCS);
4065 		} else {
4066 			if (rp->rssi & 1)
4067 				LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s",
4068 				    modename[mode], rp->rssi/2, rp->rate/2);
4069 			else
4070 				LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s",
4071 				    modename[mode], rp->rssi/2, rp->rate/2);
4072 		}
4073 	}
4074 }
4075 
4076 static void
4077 list_txparams(int s)
4078 {
4079 	const struct ieee80211_txparam *tp;
4080 	int mode;
4081 
4082 	gettxparams(s);
4083 	for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
4084 		tp = &txparams.params[mode];
4085 		if (tp->mgmtrate == 0 && tp->mcastrate == 0)
4086 			continue;
4087 		if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
4088 			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
4089 				LINE_CHECK("%-7.7s ucast NONE    mgmt %2u MCS  "
4090 				    "mcast %2u MCS  maxretry %u",
4091 				    modename[mode],
4092 				    tp->mgmtrate &~ IEEE80211_RATE_MCS,
4093 				    tp->mcastrate &~ IEEE80211_RATE_MCS,
4094 				    tp->maxretry);
4095 			else
4096 				LINE_CHECK("%-7.7s ucast %2u MCS  mgmt %2u MCS  "
4097 				    "mcast %2u MCS  maxretry %u",
4098 				    modename[mode],
4099 				    tp->ucastrate &~ IEEE80211_RATE_MCS,
4100 				    tp->mgmtrate &~ IEEE80211_RATE_MCS,
4101 				    tp->mcastrate &~ IEEE80211_RATE_MCS,
4102 				    tp->maxretry);
4103 		} else {
4104 			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
4105 				LINE_CHECK("%-7.7s ucast NONE    mgmt %2u Mb/s "
4106 				    "mcast %2u Mb/s maxretry %u",
4107 				    modename[mode],
4108 				    tp->mgmtrate/2,
4109 				    tp->mcastrate/2, tp->maxretry);
4110 			else
4111 				LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s "
4112 				    "mcast %2u Mb/s maxretry %u",
4113 				    modename[mode],
4114 				    tp->ucastrate/2, tp->mgmtrate/2,
4115 				    tp->mcastrate/2, tp->maxretry);
4116 		}
4117 	}
4118 }
4119 
4120 static void
4121 printpolicy(int policy)
4122 {
4123 	switch (policy) {
4124 	case IEEE80211_MACCMD_POLICY_OPEN:
4125 		printf("policy: open\n");
4126 		break;
4127 	case IEEE80211_MACCMD_POLICY_ALLOW:
4128 		printf("policy: allow\n");
4129 		break;
4130 	case IEEE80211_MACCMD_POLICY_DENY:
4131 		printf("policy: deny\n");
4132 		break;
4133 	case IEEE80211_MACCMD_POLICY_RADIUS:
4134 		printf("policy: radius\n");
4135 		break;
4136 	default:
4137 		printf("policy: unknown (%u)\n", policy);
4138 		break;
4139 	}
4140 }
4141 
4142 static void
4143 list_mac(int s)
4144 {
4145 	struct ieee80211req ireq;
4146 	struct ieee80211req_maclist *acllist;
4147 	int i, nacls, policy, len;
4148 	uint8_t *data;
4149 	char c;
4150 
4151 	memset(&ireq, 0, sizeof(ireq));
4152 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name)); /* XXX ?? */
4153 	ireq.i_type = IEEE80211_IOC_MACCMD;
4154 	ireq.i_val = IEEE80211_MACCMD_POLICY;
4155 	if (ioctl(s, SIOCG80211, &ireq) < 0) {
4156 		if (errno == EINVAL) {
4157 			printf("No acl policy loaded\n");
4158 			return;
4159 		}
4160 		err(1, "unable to get mac policy");
4161 	}
4162 	policy = ireq.i_val;
4163 	if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
4164 		c = '*';
4165 	} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
4166 		c = '+';
4167 	} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
4168 		c = '-';
4169 	} else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) {
4170 		c = 'r';		/* NB: should never have entries */
4171 	} else {
4172 		printf("policy: unknown (%u)\n", policy);
4173 		c = '?';
4174 	}
4175 	if (verbose || c == '?')
4176 		printpolicy(policy);
4177 
4178 	ireq.i_val = IEEE80211_MACCMD_LIST;
4179 	ireq.i_len = 0;
4180 	if (ioctl(s, SIOCG80211, &ireq) < 0)
4181 		err(1, "unable to get mac acl list size");
4182 	if (ireq.i_len == 0) {		/* NB: no acls */
4183 		if (!(verbose || c == '?'))
4184 			printpolicy(policy);
4185 		return;
4186 	}
4187 	len = ireq.i_len;
4188 
4189 	data = malloc(len);
4190 	if (data == NULL)
4191 		err(1, "out of memory for acl list");
4192 
4193 	ireq.i_data = data;
4194 	if (ioctl(s, SIOCG80211, &ireq) < 0)
4195 		err(1, "unable to get mac acl list");
4196 	nacls = len / sizeof(*acllist);
4197 	acllist = (struct ieee80211req_maclist *) data;
4198 	for (i = 0; i < nacls; i++)
4199 		printf("%c%s\n", c, ether_ntoa(
4200 			(const struct ether_addr *) acllist[i].ml_macaddr));
4201 	free(data);
4202 }
4203 
4204 static void
4205 print_regdomain(const struct ieee80211_regdomain *reg, int verb)
4206 {
4207 	if ((reg->regdomain != 0 &&
4208 	    reg->regdomain != reg->country) || verb) {
4209 		const struct regdomain *rd =
4210 		    lib80211_regdomain_findbysku(getregdata(), reg->regdomain);
4211 		if (rd == NULL)
4212 			LINE_CHECK("regdomain %d", reg->regdomain);
4213 		else
4214 			LINE_CHECK("regdomain %s", rd->name);
4215 	}
4216 	if (reg->country != 0 || verb) {
4217 		const struct country *cc =
4218 		    lib80211_country_findbycc(getregdata(), reg->country);
4219 		if (cc == NULL)
4220 			LINE_CHECK("country %d", reg->country);
4221 		else
4222 			LINE_CHECK("country %s", cc->isoname);
4223 	}
4224 	if (reg->location == 'I')
4225 		LINE_CHECK("indoor");
4226 	else if (reg->location == 'O')
4227 		LINE_CHECK("outdoor");
4228 	else if (verb)
4229 		LINE_CHECK("anywhere");
4230 	if (reg->ecm)
4231 		LINE_CHECK("ecm");
4232 	else if (verb)
4233 		LINE_CHECK("-ecm");
4234 }
4235 
4236 static void
4237 list_regdomain(int s, int channelsalso)
4238 {
4239 	getregdomain(s);
4240 	if (channelsalso) {
4241 		getchaninfo(s);
4242 		spacer = ':';
4243 		print_regdomain(&regdomain, 1);
4244 		LINE_BREAK();
4245 		print_channels(s, chaninfo, true /* allchans */,
4246 		    true /* verbose */);
4247 	} else
4248 		print_regdomain(&regdomain, verbose);
4249 }
4250 
4251 static void
4252 list_mesh(int s)
4253 {
4254 	struct ieee80211req ireq;
4255 	struct ieee80211req_mesh_route routes[128];
4256 	struct ieee80211req_mesh_route *rt;
4257 
4258 	memset(&ireq, 0, sizeof(ireq));
4259 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
4260 	ireq.i_type = IEEE80211_IOC_MESH_RTCMD;
4261 	ireq.i_val = IEEE80211_MESH_RTCMD_LIST;
4262 	ireq.i_data = &routes;
4263 	ireq.i_len = sizeof(routes);
4264 	if (ioctl(s, SIOCG80211, &ireq) < 0)
4265 		err(1, "unable to get the Mesh routing table");
4266 
4267 	printf("%-17.17s %-17.17s %4s %4s %4s %6s %s\n"
4268 		, "DEST"
4269 		, "NEXT HOP"
4270 		, "HOPS"
4271 		, "METRIC"
4272 		, "LIFETIME"
4273 		, "MSEQ"
4274 		, "FLAGS");
4275 
4276 	for (rt = &routes[0];
4277 	     rt - &routes[0] < (int)(ireq.i_len / sizeof(*rt));
4278 	     rt++) {
4279 		printf("%s ",
4280 		    ether_ntoa((const struct ether_addr *)rt->imr_dest));
4281 		printf("%s %4u   %4u   %6u %6u    %c%c\n",
4282 			ether_ntoa((const struct ether_addr *)rt->imr_nexthop),
4283 			rt->imr_nhops, rt->imr_metric, rt->imr_lifetime,
4284 			rt->imr_lastmseq,
4285 			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ?
4286 			    'V' : '!',
4287 			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ?
4288 			    'P' : ' ');
4289 	}
4290 }
4291 
4292 static void
4293 set80211list(const char *arg, int d __unused, int s,
4294 	     const struct afswtch *afp __unused)
4295 {
4296 	LINE_INIT('\t');
4297 
4298 	if (iseq(arg, "sta"))
4299 		list_stations(s);
4300 	else if (iseq(arg, "scan") || iseq(arg, "ap"))
4301 		list_scan(s, 0);
4302 	else if (iseq(arg, "lscan"))
4303 		list_scan(s, 1);
4304 	else if (iseq(arg, "chan") || iseq(arg, "freq"))
4305 		list_channels(s, true);
4306 	else if (iseq(arg, "active"))
4307 		list_channels(s, false);
4308 	else if (iseq(arg, "keys"))
4309 		list_keys(s);
4310 	else if (iseq(arg, "caps"))
4311 		list_capabilities(s);
4312 	else if (iseq(arg, "wme") || iseq(arg, "wmm"))
4313 		list_wme(s);
4314 	else if (iseq(arg, "mac"))
4315 		list_mac(s);
4316 	else if (iseq(arg, "txpow"))
4317 		list_txpow(s);
4318 	else if (iseq(arg, "roam"))
4319 		list_roam(s);
4320 	else if (iseq(arg, "txparam") || iseq(arg, "txparm"))
4321 		list_txparams(s);
4322 	else if (iseq(arg, "regdomain"))
4323 		list_regdomain(s, 1);
4324 	else if (iseq(arg, "countries"))
4325 		list_countries();
4326 	else if (iseq(arg, "mesh"))
4327 		list_mesh(s);
4328 	else
4329 		errx(1, "Don't know how to list %s for %s", arg, IfName);
4330 	LINE_BREAK();
4331 }
4332 
4333 static enum ieee80211_opmode
4334 get80211opmode(int s)
4335 {
4336 	struct ifmediareq ifmr;
4337 
4338 	memset(&ifmr, 0, sizeof(ifmr));
4339 	strlcpy(ifmr.ifm_name, IfName, sizeof(ifmr.ifm_name));
4340 
4341 	if (ioctl(s, SIOCGIFMEDIA, &ifmr) >= 0) {
4342 		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
4343 			if (ifmr.ifm_current & IFM_FLAG0)
4344 				return IEEE80211_M_AHDEMO;
4345 			else
4346 				return IEEE80211_M_IBSS;
4347 		}
4348 		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
4349 			return IEEE80211_M_HOSTAP;
4350 		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
4351 			return IEEE80211_M_MONITOR;
4352 		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
4353 			return IEEE80211_M_MBSS;
4354 	}
4355 	return IEEE80211_M_STA;
4356 }
4357 
4358 #if 0
4359 static void
4360 printcipher(int s, struct ieee80211req *ireq, int keylenop)
4361 {
4362 	switch (ireq->i_val) {
4363 	case IEEE80211_CIPHER_WEP:
4364 		ireq->i_type = keylenop;
4365 		if (ioctl(s, SIOCG80211, ireq) != -1)
4366 			printf("WEP-%s",
4367 			    ireq->i_len <= 5 ? "40" :
4368 			    ireq->i_len <= 13 ? "104" : "128");
4369 		else
4370 			printf("WEP");
4371 		break;
4372 	case IEEE80211_CIPHER_TKIP:
4373 		printf("TKIP");
4374 		break;
4375 	case IEEE80211_CIPHER_AES_OCB:
4376 		printf("AES-OCB");
4377 		break;
4378 	case IEEE80211_CIPHER_AES_CCM:
4379 		printf("AES-CCM");
4380 		break;
4381 	case IEEE80211_CIPHER_CKIP:
4382 		printf("CKIP");
4383 		break;
4384 	case IEEE80211_CIPHER_NONE:
4385 		printf("NONE");
4386 		break;
4387 	default:
4388 		printf("UNKNOWN (0x%x)", ireq->i_val);
4389 		break;
4390 	}
4391 }
4392 #endif
4393 
4394 static void
4395 printkey(const struct ieee80211req_key *ik)
4396 {
4397 	static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
4398 	int keylen = ik->ik_keylen;
4399 	int printcontents;
4400 
4401 	printcontents = printkeys &&
4402 		(memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
4403 	if (printcontents)
4404 		LINE_BREAK();
4405 	switch (ik->ik_type) {
4406 	case IEEE80211_CIPHER_WEP:
4407 		/* compatibility */
4408 		LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
4409 		    keylen <= 5 ? "40-bit" :
4410 		    keylen <= 13 ? "104-bit" : "128-bit");
4411 		break;
4412 	case IEEE80211_CIPHER_TKIP:
4413 		if (keylen > 128/8)
4414 			keylen -= 128/8;	/* ignore MIC for now */
4415 		LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
4416 		break;
4417 	case IEEE80211_CIPHER_AES_OCB:
4418 		LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
4419 		break;
4420 	case IEEE80211_CIPHER_AES_CCM:
4421 		LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
4422 		break;
4423 	case IEEE80211_CIPHER_CKIP:
4424 		LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
4425 		break;
4426 	case IEEE80211_CIPHER_NONE:
4427 		LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
4428 		break;
4429 	default:
4430 		LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
4431 			ik->ik_type, ik->ik_keyix+1, 8*keylen);
4432 		break;
4433 	}
4434 	if (printcontents) {
4435 		int i;
4436 
4437 		printf(" <");
4438 		for (i = 0; i < keylen; i++)
4439 			printf("%02x", ik->ik_keydata[i]);
4440 		printf(">");
4441 		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
4442 		    (ik->ik_keyrsc != 0 || verbose))
4443 			printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
4444 		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
4445 		    (ik->ik_keytsc != 0 || verbose))
4446 			printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
4447 		if (ik->ik_flags != 0 && verbose) {
4448 			const char *sep = " ";
4449 
4450 			if (ik->ik_flags & IEEE80211_KEY_XMIT)
4451 				printf("%stx", sep), sep = "+";
4452 			if (ik->ik_flags & IEEE80211_KEY_RECV)
4453 				printf("%srx", sep), sep = "+";
4454 			if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
4455 				printf("%sdef", sep), sep = "+";
4456 		}
4457 		LINE_BREAK();
4458 	}
4459 }
4460 
4461 static void
4462 printrate(const char *tag, int v, int defrate, int defmcs)
4463 {
4464 	if ((v & IEEE80211_RATE_MCS) == 0) {
4465 		if (v != defrate) {
4466 			if (v & 1)
4467 				LINE_CHECK("%s %d.5", tag, v/2);
4468 			else
4469 				LINE_CHECK("%s %d", tag, v/2);
4470 		}
4471 	} else {
4472 		if (v != defmcs)
4473 			LINE_CHECK("%s %d", tag, v &~ 0x80);
4474 	}
4475 }
4476 
4477 static int
4478 getid(int s, int ix, void *data, size_t len, size_t *plen, int mesh)
4479 {
4480 	struct ieee80211req ireq;
4481 
4482 	memset(&ireq, 0, sizeof(ireq));
4483 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
4484 	ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID;
4485 	ireq.i_val = ix;
4486 	ireq.i_data = data;
4487 	ireq.i_len = len;
4488 	if (ioctl(s, SIOCG80211, &ireq) < 0)
4489 		return -1;
4490 	*plen = ireq.i_len;
4491 	return 0;
4492 }
4493 
4494 static void
4495 ieee80211_status(int s)
4496 {
4497 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
4498 	enum ieee80211_opmode opmode = get80211opmode(s);
4499 	int i, num, wpa, wme, bgscan, bgscaninterval, val, wepmode;
4500 	size_t len;
4501 	uint8_t data[32];
4502 	const struct ieee80211_channel *c;
4503 	const struct ieee80211_roamparam *rp;
4504 	const struct ieee80211_txparam *tp;
4505 
4506 	if (getid(s, -1, data, sizeof(data), &len, 0) < 0) {
4507 		/* If we can't get the SSID, this isn't an 802.11 device. */
4508 		return;
4509 	}
4510 
4511 	/*
4512 	 * Invalidate cached state so printing status for multiple
4513 	 * if's doesn't reuse the first interfaces' cached state.
4514 	 */
4515 	gotcurchan = 0;
4516 	gotroam = 0;
4517 	gottxparams = 0;
4518 	gothtconf = 0;
4519 	gotregdomain = 0;
4520 
4521 	printf("\t");
4522 	if (opmode == IEEE80211_M_MBSS) {
4523 		printf("meshid ");
4524 		getid(s, 0, data, sizeof(data), &len, 1);
4525 		print_string(data, len);
4526 	} else {
4527 		if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0)
4528 			num = 0;
4529 		printf("ssid ");
4530 		if (num > 1) {
4531 			for (i = 0; i < num; i++) {
4532 				if (getid(s, i, data, sizeof(data), &len, 0) >= 0 && len > 0) {
4533 					printf(" %d:", i + 1);
4534 					print_string(data, len);
4535 				}
4536 			}
4537 		} else
4538 			print_string(data, len);
4539 	}
4540 	c = getcurchan(s);
4541 	if (c->ic_freq != IEEE80211_CHAN_ANY) {
4542 		char buf[14];
4543 		printf(" channel %d (%u MHz%s)", c->ic_ieee, c->ic_freq,
4544 			get_chaninfo(c, 1, buf, sizeof(buf)));
4545 	} else if (verbose)
4546 		printf(" channel UNDEF");
4547 
4548 	if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 &&
4549 	    (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
4550 		printf(" bssid %s", ether_ntoa((struct ether_addr *)data));
4551 
4552 	if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) {
4553 		printf("\n\tstationname ");
4554 		print_string(data, len);
4555 	}
4556 
4557 	spacer = ' ';		/* force first break */
4558 	LINE_BREAK();
4559 
4560 	list_regdomain(s, 0);
4561 
4562 	wpa = 0;
4563 	if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) {
4564 		switch (val) {
4565 		case IEEE80211_AUTH_NONE:
4566 			LINE_CHECK("authmode NONE");
4567 			break;
4568 		case IEEE80211_AUTH_OPEN:
4569 			LINE_CHECK("authmode OPEN");
4570 			break;
4571 		case IEEE80211_AUTH_SHARED:
4572 			LINE_CHECK("authmode SHARED");
4573 			break;
4574 		case IEEE80211_AUTH_8021X:
4575 			LINE_CHECK("authmode 802.1x");
4576 			break;
4577 		case IEEE80211_AUTH_WPA:
4578 			if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0)
4579 				wpa = 1;	/* default to WPA1 */
4580 			switch (wpa) {
4581 			case 2:
4582 				LINE_CHECK("authmode WPA2/802.11i");
4583 				break;
4584 			case 3:
4585 				LINE_CHECK("authmode WPA1+WPA2/802.11i");
4586 				break;
4587 			default:
4588 				LINE_CHECK("authmode WPA");
4589 				break;
4590 			}
4591 			break;
4592 		case IEEE80211_AUTH_AUTO:
4593 			LINE_CHECK("authmode AUTO");
4594 			break;
4595 		default:
4596 			LINE_CHECK("authmode UNKNOWN (0x%x)", val);
4597 			break;
4598 		}
4599 	}
4600 
4601 	if (wpa || verbose) {
4602 		if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) {
4603 			if (val)
4604 				LINE_CHECK("wps");
4605 			else if (verbose)
4606 				LINE_CHECK("-wps");
4607 		}
4608 		if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) {
4609 			if (val)
4610 				LINE_CHECK("tsn");
4611 			else if (verbose)
4612 				LINE_CHECK("-tsn");
4613 		}
4614 		if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) {
4615 			if (val)
4616 				LINE_CHECK("countermeasures");
4617 			else if (verbose)
4618 				LINE_CHECK("-countermeasures");
4619 		}
4620 #if 0
4621 		/* XXX not interesting with WPA done in user space */
4622 		ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
4623 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
4624 		}
4625 
4626 		ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
4627 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
4628 			LINE_CHECK("mcastcipher ");
4629 			printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
4630 			spacer = ' ';
4631 		}
4632 
4633 		ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
4634 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
4635 			LINE_CHECK("ucastcipher ");
4636 			printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
4637 		}
4638 
4639 		if (wpa & 2) {
4640 			ireq.i_type = IEEE80211_IOC_RSNCAPS;
4641 			if (ioctl(s, SIOCG80211, &ireq) != -1) {
4642 				LINE_CHECK("RSN caps 0x%x", ireq.i_val);
4643 				spacer = ' ';
4644 			}
4645 		}
4646 
4647 		ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
4648 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
4649 		}
4650 #endif
4651 	}
4652 
4653 	if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 &&
4654 	    wepmode != IEEE80211_WEP_NOSUP) {
4655 		switch (wepmode) {
4656 		case IEEE80211_WEP_OFF:
4657 			LINE_CHECK("privacy OFF");
4658 			break;
4659 		case IEEE80211_WEP_ON:
4660 			LINE_CHECK("privacy ON");
4661 			break;
4662 		case IEEE80211_WEP_MIXED:
4663 			LINE_CHECK("privacy MIXED");
4664 			break;
4665 		default:
4666 			LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
4667 			break;
4668 		}
4669 
4670 		/*
4671 		 * If we get here then we've got WEP support so we need
4672 		 * to print WEP status.
4673 		 */
4674 
4675 		if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) {
4676 			warn("WEP support, but no tx key!");
4677 			goto end;
4678 		}
4679 		if (val != -1)
4680 			LINE_CHECK("deftxkey %d", val+1);
4681 		else if (wepmode != IEEE80211_WEP_OFF || verbose)
4682 			LINE_CHECK("deftxkey UNDEF");
4683 
4684 		if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) {
4685 			warn("WEP support, but no NUMWEPKEYS support!");
4686 			goto end;
4687 		}
4688 
4689 		for (i = 0; i < num; i++) {
4690 			struct ieee80211req_key ik;
4691 
4692 			memset(&ik, 0, sizeof(ik));
4693 			ik.ik_keyix = i;
4694 			if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) {
4695 				warn("WEP support, but can get keys!");
4696 				goto end;
4697 			}
4698 			if (ik.ik_keylen != 0) {
4699 				if (verbose)
4700 					LINE_BREAK();
4701 				printkey(&ik);
4702 			}
4703 		}
4704 end:
4705 		;
4706 	}
4707 
4708 	if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 &&
4709 	    val != IEEE80211_POWERSAVE_NOSUP ) {
4710 		if (val != IEEE80211_POWERSAVE_OFF || verbose) {
4711 			switch (val) {
4712 			case IEEE80211_POWERSAVE_OFF:
4713 				LINE_CHECK("powersavemode OFF");
4714 				break;
4715 			case IEEE80211_POWERSAVE_CAM:
4716 				LINE_CHECK("powersavemode CAM");
4717 				break;
4718 			case IEEE80211_POWERSAVE_PSP:
4719 				LINE_CHECK("powersavemode PSP");
4720 				break;
4721 			case IEEE80211_POWERSAVE_PSP_CAM:
4722 				LINE_CHECK("powersavemode PSP-CAM");
4723 				break;
4724 			}
4725 			if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1)
4726 				LINE_CHECK("powersavesleep %d", val);
4727 		}
4728 	}
4729 
4730 	if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) {
4731 		if (val & 1)
4732 			LINE_CHECK("txpower %d.5", val/2);
4733 		else
4734 			LINE_CHECK("txpower %d", val/2);
4735 	}
4736 	if (verbose) {
4737 		if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1)
4738 			LINE_CHECK("txpowmax %.1f", val/2.);
4739 	}
4740 
4741 	if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) {
4742 		if (val)
4743 			LINE_CHECK("dotd");
4744 		else if (verbose)
4745 			LINE_CHECK("-dotd");
4746 	}
4747 
4748 	if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) {
4749 		if (val != IEEE80211_RTS_MAX || verbose)
4750 			LINE_CHECK("rtsthreshold %d", val);
4751 	}
4752 
4753 	if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) {
4754 		if (val != IEEE80211_FRAG_MAX || verbose)
4755 			LINE_CHECK("fragthreshold %d", val);
4756 	}
4757 	if (opmode == IEEE80211_M_STA || verbose) {
4758 		if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) {
4759 			if (val != IEEE80211_HWBMISS_MAX || verbose)
4760 				LINE_CHECK("bmiss %d", val);
4761 		}
4762 	}
4763 
4764 	if (!verbose) {
4765 		gettxparams(s);
4766 		tp = &txparams.params[chan2mode(c)];
4767 		printrate("ucastrate", tp->ucastrate,
4768 		    IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE);
4769 		printrate("mcastrate", tp->mcastrate, 2*1,
4770 		    IEEE80211_RATE_MCS|0);
4771 		printrate("mgmtrate", tp->mgmtrate, 2*1,
4772 		    IEEE80211_RATE_MCS|0);
4773 		if (tp->maxretry != 6)		/* XXX */
4774 			LINE_CHECK("maxretry %d", tp->maxretry);
4775 	} else {
4776 		LINE_BREAK();
4777 		list_txparams(s);
4778 	}
4779 
4780 	bgscaninterval = -1;
4781 	get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval);
4782 
4783 	if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) {
4784 		if (val != bgscaninterval || verbose)
4785 			LINE_CHECK("scanvalid %u", val);
4786 	}
4787 
4788 	bgscan = 0;
4789 	if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) {
4790 		if (bgscan)
4791 			LINE_CHECK("bgscan");
4792 		else if (verbose)
4793 			LINE_CHECK("-bgscan");
4794 	}
4795 	if (bgscan || verbose) {
4796 		if (bgscaninterval != -1)
4797 			LINE_CHECK("bgscanintvl %u", bgscaninterval);
4798 		if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1)
4799 			LINE_CHECK("bgscanidle %u", val);
4800 		if (!verbose) {
4801 			getroam(s);
4802 			rp = &roamparams.params[chan2mode(c)];
4803 			if (rp->rssi & 1)
4804 				LINE_CHECK("roam:rssi %u.5", rp->rssi/2);
4805 			else
4806 				LINE_CHECK("roam:rssi %u", rp->rssi/2);
4807 			LINE_CHECK("roam:rate %u", rp->rate/2);
4808 		} else {
4809 			LINE_BREAK();
4810 			list_roam(s);
4811 		}
4812 	}
4813 
4814 	if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
4815 		if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) {
4816 			if (val)
4817 				LINE_CHECK("pureg");
4818 			else if (verbose)
4819 				LINE_CHECK("-pureg");
4820 		}
4821 		if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) {
4822 			switch (val) {
4823 			case IEEE80211_PROTMODE_OFF:
4824 				LINE_CHECK("protmode OFF");
4825 				break;
4826 			case IEEE80211_PROTMODE_CTS:
4827 				LINE_CHECK("protmode CTS");
4828 				break;
4829 			case IEEE80211_PROTMODE_RTSCTS:
4830 				LINE_CHECK("protmode RTSCTS");
4831 				break;
4832 			default:
4833 				LINE_CHECK("protmode UNKNOWN (0x%x)", val);
4834 				break;
4835 			}
4836 		}
4837 	}
4838 
4839 	if (IEEE80211_IS_CHAN_HT(c) || verbose) {
4840 		gethtconf(s);
4841 		switch (htconf & 3) {
4842 		case 0:
4843 		case 2:
4844 			LINE_CHECK("-ht");
4845 			break;
4846 		case 1:
4847 			LINE_CHECK("ht20");
4848 			break;
4849 		case 3:
4850 			if (verbose)
4851 				LINE_CHECK("ht");
4852 			break;
4853 		}
4854 		if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) {
4855 			if (!val)
4856 				LINE_CHECK("-htcompat");
4857 			else if (verbose)
4858 				LINE_CHECK("htcompat");
4859 		}
4860 		if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) {
4861 			switch (val) {
4862 			case 0:
4863 				LINE_CHECK("-ampdu");
4864 				break;
4865 			case 1:
4866 				LINE_CHECK("ampdutx -ampdurx");
4867 				break;
4868 			case 2:
4869 				LINE_CHECK("-ampdutx ampdurx");
4870 				break;
4871 			case 3:
4872 				if (verbose)
4873 					LINE_CHECK("ampdu");
4874 				break;
4875 			}
4876 		}
4877 		if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) {
4878 			switch (val) {
4879 			case IEEE80211_HTCAP_MAXRXAMPDU_8K:
4880 				LINE_CHECK("ampdulimit 8k");
4881 				break;
4882 			case IEEE80211_HTCAP_MAXRXAMPDU_16K:
4883 				LINE_CHECK("ampdulimit 16k");
4884 				break;
4885 			case IEEE80211_HTCAP_MAXRXAMPDU_32K:
4886 				LINE_CHECK("ampdulimit 32k");
4887 				break;
4888 			case IEEE80211_HTCAP_MAXRXAMPDU_64K:
4889 				LINE_CHECK("ampdulimit 64k");
4890 				break;
4891 			}
4892 		}
4893 		if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) {
4894 			switch (val) {
4895 			case IEEE80211_HTCAP_MPDUDENSITY_NA:
4896 				if (verbose)
4897 					LINE_CHECK("ampdudensity NA");
4898 				break;
4899 			case IEEE80211_HTCAP_MPDUDENSITY_025:
4900 				LINE_CHECK("ampdudensity .25");
4901 				break;
4902 			case IEEE80211_HTCAP_MPDUDENSITY_05:
4903 				LINE_CHECK("ampdudensity .5");
4904 				break;
4905 			case IEEE80211_HTCAP_MPDUDENSITY_1:
4906 				LINE_CHECK("ampdudensity 1");
4907 				break;
4908 			case IEEE80211_HTCAP_MPDUDENSITY_2:
4909 				LINE_CHECK("ampdudensity 2");
4910 				break;
4911 			case IEEE80211_HTCAP_MPDUDENSITY_4:
4912 				LINE_CHECK("ampdudensity 4");
4913 				break;
4914 			case IEEE80211_HTCAP_MPDUDENSITY_8:
4915 				LINE_CHECK("ampdudensity 8");
4916 				break;
4917 			case IEEE80211_HTCAP_MPDUDENSITY_16:
4918 				LINE_CHECK("ampdudensity 16");
4919 				break;
4920 			}
4921 		}
4922 		if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) {
4923 			switch (val) {
4924 			case 0:
4925 				LINE_CHECK("-amsdu");
4926 				break;
4927 			case 1:
4928 				LINE_CHECK("amsdutx -amsdurx");
4929 				break;
4930 			case 2:
4931 				LINE_CHECK("-amsdutx amsdurx");
4932 				break;
4933 			case 3:
4934 				if (verbose)
4935 					LINE_CHECK("amsdu");
4936 				break;
4937 			}
4938 		}
4939 		/* XXX amsdu limit */
4940 		if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) {
4941 			if (val)
4942 				LINE_CHECK("shortgi");
4943 			else if (verbose)
4944 				LINE_CHECK("-shortgi");
4945 		}
4946 		if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) {
4947 			if (val == IEEE80211_PROTMODE_OFF)
4948 				LINE_CHECK("htprotmode OFF");
4949 			else if (val != IEEE80211_PROTMODE_RTSCTS)
4950 				LINE_CHECK("htprotmode UNKNOWN (0x%x)", val);
4951 			else if (verbose)
4952 				LINE_CHECK("htprotmode RTSCTS");
4953 		}
4954 		if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) {
4955 			if (val)
4956 				LINE_CHECK("puren");
4957 			else if (verbose)
4958 				LINE_CHECK("-puren");
4959 		}
4960 		if (get80211val(s, IEEE80211_IOC_SMPS, &val) != -1) {
4961 			if (val == IEEE80211_HTCAP_SMPS_DYNAMIC)
4962 				LINE_CHECK("smpsdyn");
4963 			else if (val == IEEE80211_HTCAP_SMPS_ENA)
4964 				LINE_CHECK("smps");
4965 			else if (verbose)
4966 				LINE_CHECK("-smps");
4967 		}
4968 		if (get80211val(s, IEEE80211_IOC_RIFS, &val) != -1) {
4969 			if (val)
4970 				LINE_CHECK("rifs");
4971 			else if (verbose)
4972 				LINE_CHECK("-rifs");
4973 		}
4974 	}
4975 
4976 	if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) {
4977 		if (wme)
4978 			LINE_CHECK("wme");
4979 		else if (verbose)
4980 			LINE_CHECK("-wme");
4981 	} else
4982 		wme = 0;
4983 
4984 	if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) {
4985 		if (val)
4986 			LINE_CHECK("burst");
4987 		else if (verbose)
4988 			LINE_CHECK("-burst");
4989 	}
4990 
4991 	if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) {
4992 		if (val)
4993 			LINE_CHECK("ff");
4994 		else if (verbose)
4995 			LINE_CHECK("-ff");
4996 	}
4997 	if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) {
4998 		if (val)
4999 			LINE_CHECK("dturbo");
5000 		else if (verbose)
5001 			LINE_CHECK("-dturbo");
5002 	}
5003 	if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) {
5004 		if (val)
5005 			LINE_CHECK("dwds");
5006 		else if (verbose)
5007 			LINE_CHECK("-dwds");
5008 	}
5009 
5010 	if (opmode == IEEE80211_M_HOSTAP) {
5011 		if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) {
5012 			if (val)
5013 				LINE_CHECK("hidessid");
5014 			else if (verbose)
5015 				LINE_CHECK("-hidessid");
5016 		}
5017 		if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) {
5018 			if (!val)
5019 				LINE_CHECK("-apbridge");
5020 			else if (verbose)
5021 				LINE_CHECK("apbridge");
5022 		}
5023 		if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1)
5024 			LINE_CHECK("dtimperiod %u", val);
5025 
5026 		if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) {
5027 			if (!val)
5028 				LINE_CHECK("-doth");
5029 			else if (verbose)
5030 				LINE_CHECK("doth");
5031 		}
5032 		if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) {
5033 			if (!val)
5034 				LINE_CHECK("-dfs");
5035 			else if (verbose)
5036 				LINE_CHECK("dfs");
5037 		}
5038 		if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) {
5039 			if (!val)
5040 				LINE_CHECK("-inact");
5041 			else if (verbose)
5042 				LINE_CHECK("inact");
5043 		}
5044 	} else {
5045 		if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) {
5046 			if (val != IEEE80211_ROAMING_AUTO || verbose) {
5047 				switch (val) {
5048 				case IEEE80211_ROAMING_DEVICE:
5049 					LINE_CHECK("roaming DEVICE");
5050 					break;
5051 				case IEEE80211_ROAMING_AUTO:
5052 					LINE_CHECK("roaming AUTO");
5053 					break;
5054 				case IEEE80211_ROAMING_MANUAL:
5055 					LINE_CHECK("roaming MANUAL");
5056 					break;
5057 				default:
5058 					LINE_CHECK("roaming UNKNOWN (0x%x)",
5059 						val);
5060 					break;
5061 				}
5062 			}
5063 		}
5064 	}
5065 
5066 	if (opmode == IEEE80211_M_AHDEMO) {
5067 		if (get80211val(s, IEEE80211_IOC_TDMA_SLOT, &val) != -1)
5068 			LINE_CHECK("tdmaslot %u", val);
5069 		if (get80211val(s, IEEE80211_IOC_TDMA_SLOTCNT, &val) != -1)
5070 			LINE_CHECK("tdmaslotcnt %u", val);
5071 		if (get80211val(s, IEEE80211_IOC_TDMA_SLOTLEN, &val) != -1)
5072 			LINE_CHECK("tdmaslotlen %u", val);
5073 		if (get80211val(s, IEEE80211_IOC_TDMA_BINTERVAL, &val) != -1)
5074 			LINE_CHECK("tdmabintval %u", val);
5075 	} else if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
5076 		/* XXX default define not visible */
5077 		if (val != 100 || verbose)
5078 			LINE_CHECK("bintval %u", val);
5079 	}
5080 
5081 	if (wme && verbose) {
5082 		LINE_BREAK();
5083 		list_wme(s);
5084 	}
5085 
5086 	if (opmode == IEEE80211_M_MBSS) {
5087 		if (get80211val(s, IEEE80211_IOC_MESH_TTL, &val) != -1) {
5088 			LINE_CHECK("meshttl %u", val);
5089 		}
5090 		if (get80211val(s, IEEE80211_IOC_MESH_AP, &val) != -1) {
5091 			if (val)
5092 				LINE_CHECK("meshpeering");
5093 			else
5094 				LINE_CHECK("-meshpeering");
5095 		}
5096 		if (get80211val(s, IEEE80211_IOC_MESH_FWRD, &val) != -1) {
5097 			if (val)
5098 				LINE_CHECK("meshforward");
5099 			else
5100 				LINE_CHECK("-meshforward");
5101 		}
5102 		if (get80211len(s, IEEE80211_IOC_MESH_PR_METRIC, data, 12,
5103 		    &len) != -1) {
5104 			data[len] = '\0';
5105 			LINE_CHECK("meshmetric %s", data);
5106 		}
5107 		if (get80211len(s, IEEE80211_IOC_MESH_PR_PATH, data, 12,
5108 		    &len) != -1) {
5109 			data[len] = '\0';
5110 			LINE_CHECK("meshpath %s", data);
5111 		}
5112 		if (get80211val(s, IEEE80211_IOC_HWMP_ROOTMODE, &val) != -1) {
5113 			switch (val) {
5114 			case IEEE80211_HWMP_ROOTMODE_DISABLED:
5115 				LINE_CHECK("hwmprootmode DISABLED");
5116 				break;
5117 			case IEEE80211_HWMP_ROOTMODE_NORMAL:
5118 				LINE_CHECK("hwmprootmode NORMAL");
5119 				break;
5120 			case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
5121 				LINE_CHECK("hwmprootmode PROACTIVE");
5122 				break;
5123 			case IEEE80211_HWMP_ROOTMODE_RANN:
5124 				LINE_CHECK("hwmprootmode RANN");
5125 				break;
5126 			default:
5127 				LINE_CHECK("hwmprootmode UNKNOWN(%d)", val);
5128 				break;
5129 			}
5130 		}
5131 		if (get80211val(s, IEEE80211_IOC_HWMP_MAXHOPS, &val) != -1) {
5132 			LINE_CHECK("hwmpmaxhops %u", val);
5133 		}
5134 	}
5135 
5136 	LINE_BREAK();
5137 }
5138 
5139 static int
5140 get80211(int s, int type, void *data, int len)
5141 {
5142 	struct ieee80211req ireq;
5143 
5144 	memset(&ireq, 0, sizeof(ireq));
5145 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
5146 	ireq.i_type = type;
5147 	ireq.i_data = data;
5148 	ireq.i_len = len;
5149 	return ioctl(s, SIOCG80211, &ireq);
5150 }
5151 
5152 static int
5153 get80211len(int s, int type, void *data, size_t len, size_t *plen)
5154 {
5155 	struct ieee80211req ireq;
5156 
5157 	memset(&ireq, 0, sizeof(ireq));
5158 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
5159 	ireq.i_type = type;
5160 	ireq.i_len = len;
5161 	assert(ireq.i_len == len);	/* NB: check for 16-bit truncation */
5162 	ireq.i_data = data;
5163 	if (ioctl(s, SIOCG80211, &ireq) < 0)
5164 		return -1;
5165 	*plen = ireq.i_len;
5166 	return 0;
5167 }
5168 
5169 static int
5170 get80211val(int s, int type, int *val)
5171 {
5172 	struct ieee80211req ireq;
5173 
5174 	memset(&ireq, 0, sizeof(ireq));
5175 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
5176 	ireq.i_type = type;
5177 	if (ioctl(s, SIOCG80211, &ireq) < 0)
5178 		return -1;
5179 	*val = ireq.i_val;
5180 	return 0;
5181 }
5182 
5183 static void
5184 set80211(int s, int type, int val, int len, void *data)
5185 {
5186 	struct ieee80211req ireq;
5187 
5188 	memset(&ireq, 0, sizeof(ireq));
5189 	strlcpy(ireq.i_name, IfName, sizeof(ireq.i_name));
5190 	ireq.i_type = type;
5191 	ireq.i_val = val;
5192 	ireq.i_len = len;
5193 	assert(ireq.i_len == len);	/* NB: check for 16-bit truncation */
5194 	ireq.i_data = data;
5195 	if (ioctl(s, SIOCS80211, &ireq) < 0)
5196 		err(1, "SIOCS80211");
5197 }
5198 
5199 static const char *
5200 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
5201 {
5202 	int len;
5203 	int hexstr;
5204 	u_int8_t *p;
5205 
5206 	len = *lenp;
5207 	p = buf;
5208 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
5209 	if (hexstr)
5210 		val += 2;
5211 	for (;;) {
5212 		if (*val == '\0')
5213 			break;
5214 		if (sep != NULL && strchr(sep, *val) != NULL) {
5215 			val++;
5216 			break;
5217 		}
5218 		if (hexstr) {
5219 			if (!isxdigit((u_char)val[0])) {
5220 				warnx("bad hexadecimal digits");
5221 				return NULL;
5222 			}
5223 			if (!isxdigit((u_char)val[1])) {
5224 				warnx("odd count hexadecimal digits");
5225 				return NULL;
5226 			}
5227 		}
5228 		if (p >= buf + len) {
5229 			if (hexstr)
5230 				warnx("hexadecimal digits too long");
5231 			else
5232 				warnx("string too long");
5233 			return NULL;
5234 		}
5235 		if (hexstr) {
5236 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
5237 			*p++ = (tohex((u_char)val[0]) << 4) |
5238 			    tohex((u_char)val[1]);
5239 #undef tohex
5240 			val += 2;
5241 		} else
5242 			*p++ = *val++;
5243 	}
5244 	len = p - buf;
5245 	/* The string "-" is treated as the empty string. */
5246 	if (!hexstr && len == 1 && buf[0] == '-') {
5247 		len = 0;
5248 		memset(buf, 0, *lenp);
5249 	} else if (len < *lenp)
5250 		memset(p, 0, *lenp - len);
5251 	*lenp = len;
5252 	return val;
5253 }
5254 
5255 static void
5256 print_string(const u_int8_t *buf, int len)
5257 {
5258 	int i;
5259 	int hasspc;
5260 	int utf8;
5261 
5262 	i = 0;
5263 	hasspc = 0;
5264 
5265 	setlocale(LC_CTYPE, "");
5266 	utf8 = strncmp("UTF-8", nl_langinfo(CODESET), 5) == 0;
5267 
5268 	for (; i < len; i++) {
5269 		if (!isprint(buf[i]) && buf[i] != '\0' && !utf8)
5270 			break;
5271 		if (isspace(buf[i]))
5272 			hasspc++;
5273 	}
5274 	if (i == len || utf8) {
5275 		if (hasspc || len == 0 || buf[0] == '\0')
5276 			printf("\"%.*s\"", len, buf);
5277 		else
5278 			printf("%.*s", len, buf);
5279 	} else {
5280 		printf("0x");
5281 		for (i = 0; i < len; i++)
5282 			printf("%02x", buf[i]);
5283 	}
5284 }
5285 
5286 /*
5287  * Virtual AP cloning support.
5288  */
5289 static struct ieee80211_clone_params params = {
5290 	.icp_opmode	= IEEE80211_M_STA,	/* default to station mode */
5291 };
5292 
5293 static void
5294 wlan_create(int s, struct ifreq *ifr)
5295 {
5296 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
5297 
5298 	if (params.icp_parent[0] == '\0')
5299 		errx(1, "must specify a parent device (wlandev) when creating "
5300 		    "a wlan device");
5301 	if (params.icp_opmode == IEEE80211_M_WDS &&
5302 	    memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0)
5303 		errx(1, "no bssid specified for WDS (use wlanbssid)");
5304 	ifr->ifr_data = &params;
5305 	if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
5306 		err(1, "SIOCIFCREATE2");
5307 }
5308 
5309 static void
5310 set80211clone_wlandev(const char *arg, int d __unused, int s __unused,
5311 		      const struct afswtch *afp __unused)
5312 {
5313 	strlcpy(params.icp_parent, arg, IFNAMSIZ);
5314 }
5315 
5316 static void
5317 set80211clone_wlanbssid(const char *arg, int d __unused, int s __unused,
5318 			const struct afswtch *afp __unused)
5319 {
5320 	const struct ether_addr *ea;
5321 
5322 	ea = ether_aton(arg);
5323 	if (ea == NULL)
5324 		errx(1, "%s: cannot parse bssid", arg);
5325 	memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN);
5326 }
5327 
5328 static void
5329 set80211clone_wlanaddr(const char *arg, int d __unused, int s __unused,
5330 		       const struct afswtch *afp __unused)
5331 {
5332 	const struct ether_addr *ea;
5333 
5334 	ea = ether_aton(arg);
5335 	if (ea == NULL)
5336 		errx(1, "%s: cannot parse address", arg);
5337 	memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN);
5338 	params.icp_flags |= IEEE80211_CLONE_MACADDR;
5339 }
5340 
5341 static void
5342 set80211clone_wlanmode(const char *arg, int d __unused, int s __unused,
5343 		       const struct afswtch *afp __unused)
5344 {
5345 	if (iseq(arg, "sta"))
5346 		params.icp_opmode = IEEE80211_M_STA;
5347 	else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo"))
5348 		params.icp_opmode = IEEE80211_M_AHDEMO;
5349 	else if (iseq(arg, "ibss") || iseq(arg, "adhoc"))
5350 		params.icp_opmode = IEEE80211_M_IBSS;
5351 	else if (iseq(arg, "ap") || iseq(arg, "host"))
5352 		params.icp_opmode = IEEE80211_M_HOSTAP;
5353 	else if (iseq(arg, "wds"))
5354 		params.icp_opmode = IEEE80211_M_WDS;
5355 	else if (iseq(arg, "monitor"))
5356 		params.icp_opmode = IEEE80211_M_MONITOR;
5357 	else if (iseq(arg, "tdma")) {
5358 		params.icp_opmode = IEEE80211_M_AHDEMO;
5359 		params.icp_flags |= IEEE80211_CLONE_TDMA;
5360 	} else if (iseq(arg, "mesh") || iseq(arg, "mp")) /* mesh point */
5361 		params.icp_opmode = IEEE80211_M_MBSS;
5362 	else
5363 		errx(1, "Don't know to create %s for %s", arg, IfName);
5364 }
5365 
5366 static void
5367 set80211clone_beacons(const char *val __unused, int d, int s __unused,
5368 		      const struct afswtch *rafp __unused)
5369 {
5370 	/* NB: inverted sense */
5371 	if (d)
5372 		params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS;
5373 	else
5374 		params.icp_flags |= IEEE80211_CLONE_NOBEACONS;
5375 }
5376 
5377 static void
5378 set80211clone_bssid(const char *val __unused, int d, int s __unused,
5379 		    const struct afswtch *rafp __unused)
5380 {
5381 	if (d)
5382 		params.icp_flags |= IEEE80211_CLONE_BSSID;
5383 	else
5384 		params.icp_flags &= ~IEEE80211_CLONE_BSSID;
5385 }
5386 
5387 static void
5388 set80211clone_wdslegacy(const char *val __unused, int d, int s __unused,
5389 			const struct afswtch *rafp __unused)
5390 {
5391 	if (d)
5392 		params.icp_flags |= IEEE80211_CLONE_WDSLEGACY;
5393 	else
5394 		params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY;
5395 }
5396 
5397 static struct cmd ieee80211_cmds[] = {
5398 	DEF_CMD_ARG("ssid",		set80211ssid),
5399 	DEF_CMD_ARG("nwid",		set80211ssid),
5400 	DEF_CMD_ARG("meshid",		set80211meshid),
5401 	DEF_CMD_ARG("stationname",	set80211stationname),
5402 	DEF_CMD_ARG("station",		set80211stationname),	/* BSD/OS */
5403 	DEF_CMD_ARG("channel",		set80211channel),
5404 	DEF_CMD_ARG("authmode",		set80211authmode),
5405 	DEF_CMD_ARG("powersavemode",	set80211powersavemode),
5406 	DEF_CMD("powersave",	1,	set80211powersave),
5407 	DEF_CMD("-powersave",	0,	set80211powersave),
5408 	DEF_CMD_ARG("powersavesleep", 	set80211powersavesleep),
5409 	DEF_CMD_ARG("wepmode",		set80211wepmode),
5410 	DEF_CMD("wep",		1,	set80211wep),
5411 	DEF_CMD("-wep",		0,	set80211wep),
5412 	DEF_CMD_ARG("deftxkey",		set80211weptxkey),
5413 	DEF_CMD_ARG("weptxkey",		set80211weptxkey),
5414 	DEF_CMD_ARG("wepkey",		set80211wepkey),
5415 	DEF_CMD_ARG("nwkey",		set80211nwkey),		/* NetBSD */
5416 	DEF_CMD("-nwkey",	0,	set80211wep),		/* NetBSD */
5417 	DEF_CMD_ARG("rtsthreshold",	set80211rtsthreshold),
5418 	DEF_CMD_ARG("protmode",		set80211protmode),
5419 	DEF_CMD_ARG("txpower",		set80211txpower),
5420 	DEF_CMD_ARG("roaming",		set80211roaming),
5421 	DEF_CMD("wme",		1,	set80211wme),
5422 	DEF_CMD("-wme",		0,	set80211wme),
5423 	DEF_CMD("wmm",		1,	set80211wme),
5424 	DEF_CMD("-wmm",		0,	set80211wme),
5425 	DEF_CMD("hidessid",	1,	set80211hidessid),
5426 	DEF_CMD("-hidessid",	0,	set80211hidessid),
5427 	DEF_CMD("apbridge",	1,	set80211apbridge),
5428 	DEF_CMD("-apbridge",	0,	set80211apbridge),
5429 	DEF_CMD_ARG("chanlist",		set80211chanlist),
5430 	DEF_CMD_ARG("bssid",		set80211bssid),
5431 	DEF_CMD_ARG("ap",		set80211bssid),
5432 	DEF_CMD("scan",	0,		set80211scan),
5433 	DEF_CMD_ARG("list",		set80211list),
5434 	DEF_CMD_ARG2("cwmin",		set80211cwmin),
5435 	DEF_CMD_ARG2("cwmax",		set80211cwmax),
5436 	DEF_CMD_ARG2("aifs",		set80211aifs),
5437 	DEF_CMD_ARG2("txoplimit",	set80211txoplimit),
5438 	DEF_CMD_ARG("acm",		set80211acm),
5439 	DEF_CMD_ARG("-acm",		set80211noacm),
5440 	DEF_CMD_ARG("ack",		set80211ackpolicy),
5441 	DEF_CMD_ARG("-ack",		set80211noackpolicy),
5442 	DEF_CMD_ARG2("bss:cwmin",	set80211bsscwmin),
5443 	DEF_CMD_ARG2("bss:cwmax",	set80211bsscwmax),
5444 	DEF_CMD_ARG2("bss:aifs",	set80211bssaifs),
5445 	DEF_CMD_ARG2("bss:txoplimit",	set80211bsstxoplimit),
5446 	DEF_CMD_ARG("dtimperiod",	set80211dtimperiod),
5447 	DEF_CMD_ARG("bintval",		set80211bintval),
5448 	DEF_CMD("mac:open",	IEEE80211_MACCMD_POLICY_OPEN,	set80211maccmd),
5449 	DEF_CMD("mac:allow",	IEEE80211_MACCMD_POLICY_ALLOW,	set80211maccmd),
5450 	DEF_CMD("mac:deny",	IEEE80211_MACCMD_POLICY_DENY,	set80211maccmd),
5451 	DEF_CMD("mac:radius",	IEEE80211_MACCMD_POLICY_RADIUS,	set80211maccmd),
5452 	DEF_CMD("mac:flush",	IEEE80211_MACCMD_FLUSH,		set80211maccmd),
5453 	DEF_CMD("mac:detach",	IEEE80211_MACCMD_DETACH,	set80211maccmd),
5454 	DEF_CMD_ARG("mac:add",		set80211addmac),
5455 	DEF_CMD_ARG("mac:del",		set80211delmac),
5456 	DEF_CMD_ARG("mac:kick",		set80211kickmac),
5457 	DEF_CMD("pureg",	1,	set80211pureg),
5458 	DEF_CMD("-pureg",	0,	set80211pureg),
5459 	DEF_CMD("ff",		1,	set80211fastframes),
5460 	DEF_CMD("-ff",		0,	set80211fastframes),
5461 	DEF_CMD("dturbo",	1,	set80211dturbo),
5462 	DEF_CMD("-dturbo",	0,	set80211dturbo),
5463 	DEF_CMD("bgscan",	1,	set80211bgscan),
5464 	DEF_CMD("-bgscan",	0,	set80211bgscan),
5465 	DEF_CMD_ARG("bgscanidle",	set80211bgscanidle),
5466 	DEF_CMD_ARG("bgscanintvl",	set80211bgscanintvl),
5467 	DEF_CMD_ARG("scanvalid",	set80211scanvalid),
5468 	DEF_CMD_ARG("roam:rssi",	set80211roamrssi),
5469 	DEF_CMD_ARG("roam:rate",	set80211roamrate),
5470 	DEF_CMD_ARG("mcastrate",	set80211mcastrate),
5471 	DEF_CMD_ARG("ucastrate",	set80211ucastrate),
5472 	DEF_CMD_ARG("mgtrate",		set80211mgtrate),
5473 	DEF_CMD_ARG("mgmtrate",		set80211mgtrate),
5474 	DEF_CMD_ARG("maxretry",		set80211maxretry),
5475 	DEF_CMD_ARG("fragthreshold",	set80211fragthreshold),
5476 	DEF_CMD("burst",	1,	set80211burst),
5477 	DEF_CMD("-burst",	0,	set80211burst),
5478 	DEF_CMD_ARG("bmiss",		set80211bmissthreshold),
5479 	DEF_CMD_ARG("bmissthreshold",	set80211bmissthreshold),
5480 	DEF_CMD("shortgi",	1,	set80211shortgi),
5481 	DEF_CMD("-shortgi",	0,	set80211shortgi),
5482 	DEF_CMD("ampdurx",	2,	set80211ampdu),
5483 	DEF_CMD("-ampdurx",	-2,	set80211ampdu),
5484 	DEF_CMD("ampdutx",	1,	set80211ampdu),
5485 	DEF_CMD("-ampdutx",	-1,	set80211ampdu),
5486 	DEF_CMD("ampdu",	3,	set80211ampdu),		/* NB: tx+rx */
5487 	DEF_CMD("-ampdu",	-3,	set80211ampdu),
5488 	DEF_CMD_ARG("ampdulimit",	set80211ampdulimit),
5489 	DEF_CMD_ARG("ampdudensity",	set80211ampdudensity),
5490 	DEF_CMD("amsdurx",	2,	set80211amsdu),
5491 	DEF_CMD("-amsdurx",	-2,	set80211amsdu),
5492 	DEF_CMD("amsdutx",	1,	set80211amsdu),
5493 	DEF_CMD("-amsdutx",	-1,	set80211amsdu),
5494 	DEF_CMD("amsdu",	3,	set80211amsdu),		/* NB: tx+rx */
5495 	DEF_CMD("-amsdu",	-3,	set80211amsdu),
5496 	DEF_CMD_ARG("amsdulimit",	set80211amsdulimit),
5497 	DEF_CMD("puren",	1,	set80211puren),
5498 	DEF_CMD("-puren",	0,	set80211puren),
5499 	DEF_CMD("doth",		1,	set80211doth),
5500 	DEF_CMD("-doth",	0,	set80211doth),
5501 	DEF_CMD("dfs",		1,	set80211dfs),
5502 	DEF_CMD("-dfs",		0,	set80211dfs),
5503 	DEF_CMD("htcompat",	1,	set80211htcompat),
5504 	DEF_CMD("-htcompat",	0,	set80211htcompat),
5505 	DEF_CMD("dwds",		1,	set80211dwds),
5506 	DEF_CMD("-dwds",	0,	set80211dwds),
5507 	DEF_CMD("inact",	1,	set80211inact),
5508 	DEF_CMD("-inact",	0,	set80211inact),
5509 	DEF_CMD("tsn",		1,	set80211tsn),
5510 	DEF_CMD("-tsn",		0,	set80211tsn),
5511 	DEF_CMD_ARG("regdomain",	set80211regdomain),
5512 	DEF_CMD_ARG("country",		set80211country),
5513 	DEF_CMD("indoor",	'I',	set80211location),
5514 	DEF_CMD("-indoor",	'O',	set80211location),
5515 	DEF_CMD("outdoor",	'O',	set80211location),
5516 	DEF_CMD("-outdoor",	'I',	set80211location),
5517 	DEF_CMD("anywhere",	' ',	set80211location),
5518 	DEF_CMD("ecm",		1,	set80211ecm),
5519 	DEF_CMD("-ecm",		0,	set80211ecm),
5520 	DEF_CMD("dotd",		1,	set80211dotd),
5521 	DEF_CMD("-dotd",	0,	set80211dotd),
5522 	DEF_CMD_ARG("htprotmode",	set80211htprotmode),
5523 	DEF_CMD("ht20",		1,	set80211htconf),
5524 	DEF_CMD("-ht20",	0,	set80211htconf),
5525 	DEF_CMD("ht40",		3,	set80211htconf),	/* NB: 20+40 */
5526 	DEF_CMD("-ht40",	0,	set80211htconf),
5527 	DEF_CMD("ht",		3,	set80211htconf),	/* NB: 20+40 */
5528 	DEF_CMD("-ht",		0,	set80211htconf),
5529 	DEF_CMD("rifs",		1,	set80211rifs),
5530 	DEF_CMD("-rifs",	0,	set80211rifs),
5531 	DEF_CMD("smps",		IEEE80211_HTCAP_SMPS_ENA,	set80211smps),
5532 	DEF_CMD("smpsdyn",	IEEE80211_HTCAP_SMPS_DYNAMIC,	set80211smps),
5533 	DEF_CMD("-smps",	IEEE80211_HTCAP_SMPS_OFF,	set80211smps),
5534 	/* XXX for testing */
5535 	DEF_CMD_ARG("chanswitch",	set80211chanswitch),
5536 
5537 	DEF_CMD_ARG("tdmaslot",		set80211tdmaslot),
5538 	DEF_CMD_ARG("tdmaslotcnt",	set80211tdmaslotcnt),
5539 	DEF_CMD_ARG("tdmaslotlen",	set80211tdmaslotlen),
5540 	DEF_CMD_ARG("tdmabintval",	set80211tdmabintval),
5541 
5542 	DEF_CMD_ARG("meshttl",		set80211meshttl),
5543 	DEF_CMD("meshforward",	1,	set80211meshforward),
5544 	DEF_CMD("-meshforward",	0,	set80211meshforward),
5545 	DEF_CMD("meshpeering",	1,	set80211meshpeering),
5546 	DEF_CMD("-meshpeering",	0,	set80211meshpeering),
5547 	DEF_CMD_ARG("meshmetric",	set80211meshmetric),
5548 	DEF_CMD_ARG("meshpath",		set80211meshpath),
5549 	DEF_CMD("meshrt:flush",	IEEE80211_MESH_RTCMD_FLUSH,	set80211meshrtcmd),
5550 	DEF_CMD_ARG("meshrt:add",	set80211addmeshrt),
5551 	DEF_CMD_ARG("meshrt:del",	set80211delmeshrt),
5552 	DEF_CMD_ARG("hwmprootmode",	set80211hwmprootmode),
5553 	DEF_CMD_ARG("hwmpmaxhops",	set80211hwmpmaxhops),
5554 
5555 	/* vap cloning support */
5556 	DEF_CLONE_CMD_ARG("wlanaddr",	set80211clone_wlanaddr),
5557 	DEF_CLONE_CMD_ARG("wlanbssid",	set80211clone_wlanbssid),
5558 	DEF_CLONE_CMD_ARG("wlandev",	set80211clone_wlandev),
5559 	DEF_CLONE_CMD_ARG("wlanmode",	set80211clone_wlanmode),
5560 	DEF_CLONE_CMD("beacons", 1,	set80211clone_beacons),
5561 	DEF_CLONE_CMD("-beacons", 0,	set80211clone_beacons),
5562 	DEF_CLONE_CMD("bssid",	1,	set80211clone_bssid),
5563 	DEF_CLONE_CMD("-bssid",	0,	set80211clone_bssid),
5564 	DEF_CLONE_CMD("wdslegacy", 1,	set80211clone_wdslegacy),
5565 	DEF_CLONE_CMD("-wdslegacy", 0,	set80211clone_wdslegacy),
5566 };
5567 static struct afswtch af_ieee80211 = {
5568 	.af_name	= "af_ieee80211",
5569 	.af_af		= AF_UNSPEC,
5570 	.af_other_status = ieee80211_status,
5571 };
5572 
5573 __constructor(125)
5574 static void
5575 ieee80211_ctor(void)
5576 {
5577 	size_t i;
5578 
5579 	for (i = 0; i < nitems(ieee80211_cmds);  i++)
5580 		cmd_register(&ieee80211_cmds[i]);
5581 	af_register(&af_ieee80211);
5582 	clone_setdefcallback("wlan", wlan_create);
5583 }
5584