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