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