64b61e67c985544f0f7931639d4b94cf1483b14b
[dragonfly.git] / sbin / ifconfig / ifieee80211.c
1 /*
2  * Copyright 2001 The Aerospace Corporation.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. The name of The Aerospace Corporation may not be used to endorse or
13  *    promote products derived from this software.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 203970 2010-02-16 21:39:20Z imp $
28  */
29
30 /*-
31  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32  * All rights reserved.
33  *
34  * This code is derived from software contributed to The NetBSD Foundation
35  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36  * NASA Ames Research Center.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57  * POSSIBILITY OF SUCH DAMAGE.
58  */
59
60 #include <sys/param.h>
61 #include <sys/ioctl.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
64 #include <sys/time.h>
65
66 #include <net/ethernet.h>
67 #include <net/if.h>
68 #include <net/if_dl.h>
69 #include <net/if_types.h>
70 #include <net/if_media.h>
71 #include <net/route.h>
72
73 #include <netproto/802_11/ieee80211_ioctl.h>
74 #include <netproto/802_11/ieee80211_dragonfly.h>
75 #include <netproto/802_11/ieee80211_superg.h>
76 #include <netproto/802_11/ieee80211_tdma.h>
77 #include <netproto/802_11/ieee80211_mesh.h>
78
79 #include <assert.h>
80 #include <ctype.h>
81 #include <err.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <inttypes.h>
85 #include <langinfo.h>
86 #include <locale.h>
87 #include <stdarg.h>
88 #include <stddef.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <unistd.h>
93
94 #include "ifconfig.h"
95 #include "regdomain.h"
96
97 #ifndef IEEE80211_FIXED_RATE_NONE
98 #define IEEE80211_FIXED_RATE_NONE       0xff
99 #endif
100
101 /* XXX need these publicly defined or similar */
102 #ifndef IEEE80211_NODE_AUTH
103 #define IEEE80211_NODE_AUTH     0x000001        /* authorized for data */
104 #define IEEE80211_NODE_QOS      0x000002        /* QoS enabled */
105 #define IEEE80211_NODE_ERP      0x000004        /* ERP enabled */
106 #define IEEE80211_NODE_PWR_MGT  0x000010        /* power save mode enabled */
107 #define IEEE80211_NODE_AREF     0x000020        /* authentication ref held */
108 #define IEEE80211_NODE_HT       0x000040        /* HT enabled */
109 #define IEEE80211_NODE_HTCOMPAT 0x000080        /* HT setup w/ vendor OUI's */
110 #define IEEE80211_NODE_WPS      0x000100        /* WPS association */
111 #define IEEE80211_NODE_TSN      0x000200        /* TSN association */
112 #define IEEE80211_NODE_AMPDU_RX 0x000400        /* AMPDU rx enabled */
113 #define IEEE80211_NODE_AMPDU_TX 0x000800        /* AMPDU tx enabled */
114 #define IEEE80211_NODE_MIMO_PS  0x001000        /* MIMO power save enabled */
115 #define IEEE80211_NODE_MIMO_RTS 0x002000        /* send RTS in MIMO PS */
116 #define IEEE80211_NODE_RIFS     0x004000        /* RIFS enabled */
117 #define IEEE80211_NODE_SGI20    0x008000        /* Short GI in HT20 enabled */
118 #define IEEE80211_NODE_SGI40    0x010000        /* Short GI in HT40 enabled */
119 #define IEEE80211_NODE_ASSOCID  0x020000        /* xmit requires associd */
120 #define IEEE80211_NODE_AMSDU_RX 0x040000        /* AMSDU rx enabled */
121 #define IEEE80211_NODE_AMSDU_TX 0x080000        /* AMSDU tx enabled */
122 #endif
123
124 #define MAXCHAN 1536            /* max 1.5K channels */
125
126 #define MAXCOL  78
127 static  int col;
128 static  char spacer;
129
130 static void LINE_INIT(char c);
131 static void LINE_BREAK(void);
132 static void LINE_CHECK(const char *fmt, ...) __printflike(1, 2);
133
134 static const char *modename[IEEE80211_MODE_MAX] = {
135         [IEEE80211_MODE_AUTO]     = "auto",
136         [IEEE80211_MODE_11A]      = "11a",
137         [IEEE80211_MODE_11B]      = "11b",
138         [IEEE80211_MODE_11G]      = "11g",
139         [IEEE80211_MODE_FH]       = "fh",
140         [IEEE80211_MODE_TURBO_A]  = "turboA",
141         [IEEE80211_MODE_TURBO_G]  = "turboG",
142         [IEEE80211_MODE_STURBO_A] = "sturbo",
143         [IEEE80211_MODE_11NA]     = "11na",
144         [IEEE80211_MODE_11NG]     = "11ng",
145         [IEEE80211_MODE_HALF]     = "half",
146         [IEEE80211_MODE_QUARTER]  = "quarter"
147 };
148
149 static void set80211(int s, int type, int val, int len, void *data);
150 static int get80211(int s, int type, void *data, int len);
151 static int get80211len(int s, int type, void *data, size_t len, size_t *plen);
152 static int get80211val(int s, int type, int *val);
153 static const char *get_string(const char *val, const char *sep,
154     u_int8_t *buf, int *lenp);
155 static void print_string(const u_int8_t *buf, int len);
156 static void print_regdomain(const struct ieee80211_regdomain *, int);
157 static void print_channels(int, const struct ieee80211req_chaninfo *,
158     int allchans, int verbose);
159 static void regdomain_makechannels(struct ieee80211_regdomain_req *,
160     const struct ieee80211_devcaps_req *);
161 static const char *mesh_linkstate_string(uint8_t state);
162
163 static struct ieee80211req_chaninfo *chaninfo;
164 static struct ieee80211_regdomain regdomain;
165 static int gotregdomain = 0;
166 static struct ieee80211_roamparams_req roamparams;
167 static int gotroam = 0;
168 static struct ieee80211_txparams_req txparams;
169 static int gottxparams = 0;
170 static struct ieee80211_channel curchan;
171 static int gotcurchan = 0;
172 static struct ifmediareq *ifmr;
173 static int htconf = 0;
174 static int gothtconf = 0;
175
176 static int
177 iseq(const char *a, const char *b)
178 {
179         return (strcasecmp(a, b) == 0);
180 }
181
182 static int
183 ismatch(const char *a, const char *b)
184 {
185         return (strncasecmp(a, b, strlen(b)) == 0);
186 }
187
188 static void
189 gethtconf(int s)
190 {
191         if (gothtconf)
192                 return;
193         if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0)
194                 warn("unable to get HT configuration information");
195         gothtconf = 1;
196 }
197
198 /*
199  * Collect channel info from the kernel.  We use this (mostly)
200  * to handle mapping between frequency and IEEE channel number.
201  */
202 static void
203 getchaninfo(int s)
204 {
205         if (chaninfo != NULL)
206                 return;
207         chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
208         if (chaninfo == NULL)
209                 errx(1, "no space for channel list");
210         if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo,
211             IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
212                 err(1, "unable to get channel information");
213         ifmr = ifmedia_getstate(s);
214         gethtconf(s);
215 }
216
217 static struct regdata *
218 getregdata(void)
219 {
220         static struct regdata *rdp = NULL;
221         if (rdp == NULL) {
222                 rdp = lib80211_alloc_regdata();
223                 if (rdp == NULL)
224                         errx(-1, "missing or corrupted regdomain database");
225         }
226         return rdp;
227 }
228
229 /*
230  * Given the channel at index i with attributes from,
231  * check if there is a channel with attributes to in
232  * the channel table.  With suitable attributes this
233  * allows the caller to look for promotion; e.g. from
234  * 11b > 11g.
235  */
236 static int
237 canpromote(u_int i, uint32_t from, uint32_t to)
238 {
239         const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
240         u_int j;
241
242         if ((fc->ic_flags & from) != from)
243                 return i;
244         /* NB: quick check exploiting ordering of chans w/ same frequency */
245         if (i+1 < chaninfo->ic_nchans &&
246             chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
247             (chaninfo->ic_chans[i+1].ic_flags & to) == to)
248                 return i+1;
249         /* brute force search in case channel list is not ordered */
250         for (j = 0; j < chaninfo->ic_nchans; j++) {
251                 const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
252                 if (j != i &&
253                     tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
254                 return j;
255         }
256         return i;
257 }
258
259 /*
260  * Handle channel promotion.  When a channel is specified with
261  * only a frequency we want to promote it to the ``best'' channel
262  * available.  The channel list has separate entries for 11b, 11g,
263  * 11a, and 11n[ga] channels so specifying a frequency w/o any
264  * attributes requires we upgrade, e.g. from 11b -> 11g.  This
265  * gets complicated when the channel is specified on the same
266  * command line with a media request that constrains the available
267  * channe list (e.g. mode 11a); we want to honor that to avoid
268  * confusing behaviour.
269  */
270 static int
271 promote(int i)
272 {
273         /*
274          * Query the current mode of the interface in case it's
275          * constrained (e.g. to 11a).  We must do this carefully
276          * as there may be a pending ifmedia request in which case
277          * asking the kernel will give us the wrong answer.  This
278          * is an unfortunate side-effect of the way ifconfig is
279          * structure for modularity (yech).
280          *
281          * NB: ifmr is actually setup in getchaninfo (above); we
282          *     assume it's called coincident with to this call so
283          *     we have a ``current setting''; otherwise we must pass
284          *     the socket descriptor down to here so we can make
285          *     the ifmedia_getstate call ourselves.
286          */
287         int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
288
289         /* when ambiguous promote to ``best'' */
290         /* NB: we abitrarily pick HT40+ over HT40- */
291         if (chanmode != IFM_IEEE80211_11B)
292                 i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
293         if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
294                 i = canpromote(i, IEEE80211_CHAN_G,
295                         IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
296                 if (htconf & 2) {
297                         i = canpromote(i, IEEE80211_CHAN_G,
298                                 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
299                         i = canpromote(i, IEEE80211_CHAN_G,
300                                 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
301                 }
302         }
303         if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
304                 i = canpromote(i, IEEE80211_CHAN_A,
305                         IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
306                 if (htconf & 2) {
307                         i = canpromote(i, IEEE80211_CHAN_A,
308                                 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
309                         i = canpromote(i, IEEE80211_CHAN_A,
310                                 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
311                 }
312         }
313         return i;
314 }
315
316 static void
317 mapfreq(struct ieee80211_channel *chan, uint16_t freq, uint32_t flags)
318 {
319         u_int i;
320
321         for (i = 0; i < chaninfo->ic_nchans; i++) {
322                 const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
323
324                 if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
325                         if (flags == 0) {
326                                 /* when ambiguous promote to ``best'' */
327                                 c = &chaninfo->ic_chans[promote(i)];
328                         }
329                         *chan = *c;
330                         return;
331                 }
332         }
333         errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
334 }
335
336 static void
337 mapchan(struct ieee80211_channel *chan, uint8_t ieee, uint32_t flags)
338 {
339         u_int i;
340
341         for (i = 0; i < chaninfo->ic_nchans; i++) {
342                 const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
343
344                 if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
345                         if (flags == 0) {
346                                 /* when ambiguous promote to ``best'' */
347                                 c = &chaninfo->ic_chans[promote(i)];
348                         }
349                         *chan = *c;
350                         return;
351                 }
352         }
353         errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
354 }
355
356 static const struct ieee80211_channel *
357 getcurchan(int s)
358 {
359         if (gotcurchan)
360                 return &curchan;
361         if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
362                 int val;
363                 /* fall back to legacy ioctl */
364                 if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
365                         err(-1, "cannot figure out current channel");
366                 getchaninfo(s);
367                 mapchan(&curchan, val, 0);
368         }
369         gotcurchan = 1;
370         return &curchan;
371 }
372
373 static enum ieee80211_phymode
374 chan2mode(const struct ieee80211_channel *c)
375 {
376         if (IEEE80211_IS_CHAN_HTA(c))
377                 return IEEE80211_MODE_11NA;
378         if (IEEE80211_IS_CHAN_HTG(c))
379                 return IEEE80211_MODE_11NG;
380         if (IEEE80211_IS_CHAN_108A(c))
381                 return IEEE80211_MODE_TURBO_A;
382         if (IEEE80211_IS_CHAN_108G(c))
383                 return IEEE80211_MODE_TURBO_G;
384         if (IEEE80211_IS_CHAN_ST(c))
385                 return IEEE80211_MODE_STURBO_A;
386         if (IEEE80211_IS_CHAN_FHSS(c))
387                 return IEEE80211_MODE_FH;
388         if (IEEE80211_IS_CHAN_HALF(c))
389                 return IEEE80211_MODE_HALF;
390         if (IEEE80211_IS_CHAN_QUARTER(c))
391                 return IEEE80211_MODE_QUARTER;
392         if (IEEE80211_IS_CHAN_A(c))
393                 return IEEE80211_MODE_11A;
394         if (IEEE80211_IS_CHAN_ANYG(c))
395                 return IEEE80211_MODE_11G;
396         if (IEEE80211_IS_CHAN_B(c))
397                 return IEEE80211_MODE_11B;
398         return IEEE80211_MODE_AUTO;
399 }
400
401 static void
402 getroam(int s)
403 {
404         if (gotroam)
405                 return;
406         if (get80211(s, IEEE80211_IOC_ROAM,
407             &roamparams, sizeof(roamparams)) < 0)
408                 err(1, "unable to get roaming parameters");
409         gotroam = 1;
410 }
411
412 static void
413 setroam_cb(int s, void *arg)
414 {
415         struct ieee80211_roamparams_req *roam = arg;
416         set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam);
417 }
418
419 static void
420 gettxparams(int s)
421 {
422         if (gottxparams)
423                 return;
424         if (get80211(s, IEEE80211_IOC_TXPARAMS,
425             &txparams, sizeof(txparams)) < 0)
426                 err(1, "unable to get transmit parameters");
427         gottxparams = 1;
428 }
429
430 static void
431 settxparams_cb(int s, void *arg)
432 {
433         struct ieee80211_txparams_req *txp = arg;
434         set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp);
435 }
436
437 static void
438 getregdomain(int s)
439 {
440         if (gotregdomain)
441                 return;
442         if (get80211(s, IEEE80211_IOC_REGDOMAIN,
443             &regdomain, sizeof(regdomain)) < 0)
444                 err(1, "unable to get regulatory domain info");
445         gotregdomain = 1;
446 }
447
448 static void
449 getdevcaps(int s, struct ieee80211_devcaps_req *dc)
450 {
451         if (get80211(s, IEEE80211_IOC_DEVCAPS, dc,
452             IEEE80211_DEVCAPS_SPACE(dc)) < 0)
453                 err(1, "unable to get device capabilities");
454 }
455
456 static void
457 setregdomain_cb(int s, void *arg)
458 {
459         struct ieee80211_regdomain_req *req;
460         struct ieee80211_regdomain *rd = arg;
461         struct ieee80211_devcaps_req *dc;
462         struct regdata *rdp = getregdata();
463
464         if (rd->country != NO_COUNTRY) {
465                 const struct country *cc;
466                 /*
467                  * Check current country seting to make sure it's
468                  * compatible with the new regdomain.  If not, then
469                  * override it with any default country for this
470                  * SKU.  If we cannot arrange a match, then abort.
471                  */
472                 cc = lib80211_country_findbycc(rdp, rd->country);
473                 if (cc == NULL)
474                         errx(1, "unknown ISO country code %d", rd->country);
475                 if (cc->rd->sku != rd->regdomain) {
476                         const struct regdomain *rp;
477                         /*
478                          * Check if country is incompatible with regdomain.
479                          * To enable multiple regdomains for a country code
480                          * we permit a mismatch between the regdomain and
481                          * the country's associated regdomain when the
482                          * regdomain is setup w/o a default country.  For
483                          * example, US is bound to the FCC regdomain but
484                          * we allow US to be combined with FCC3 because FCC3
485                          * has not default country.  This allows bogus
486                          * combinations like FCC3+DK which are resolved when
487                          * constructing the channel list by deferring to the
488                          * regdomain to construct the channel list.
489                          */
490                         rp = lib80211_regdomain_findbysku(rdp, rd->regdomain);
491                         if (rp == NULL)
492                                 errx(1, "country %s (%s) is not usable with "
493                                     "regdomain %d", cc->isoname, cc->name,
494                                     rd->regdomain);
495                         else if (rp->cc != NULL && rp->cc != cc)
496                                 errx(1, "country %s (%s) is not usable with "
497                                    "regdomain %s", cc->isoname, cc->name,
498                                    rp->name);
499                 }
500         }
501         /*
502          * Fetch the device capabilities and calculate the
503          * full set of netbands for which we request a new
504          * channel list be constructed.  Once that's done we
505          * push the regdomain info + channel list to the kernel.
506          */
507         dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
508         if (dc == NULL)
509                 errx(1, "no space for device capabilities");
510         dc->dc_chaninfo.ic_nchans = MAXCHAN;
511         getdevcaps(s, dc);
512 #if 0
513         if (verbose) {
514                 printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
515                 printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
516                 printf("htcaps    : 0x%x\n", dc->dc_htcaps);
517                 memcpy(chaninfo, &dc->dc_chaninfo,
518                     IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
519                 print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
520         }
521 #endif
522         req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
523         if (req == NULL)
524                 errx(1, "no space for regdomain request");
525         req->rd = *rd;
526         regdomain_makechannels(req, dc);
527         if (verbose) {
528                 LINE_INIT(':');
529                 print_regdomain(rd, 1/*verbose*/);
530                 LINE_BREAK();
531                 /* blech, reallocate channel list for new data */
532                 if (chaninfo != NULL)
533                         free(chaninfo);
534                 chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
535                 if (chaninfo == NULL)
536                         errx(1, "no space for channel list");
537                 memcpy(chaninfo, &req->chaninfo,
538                     IEEE80211_CHANINFO_SPACE(&req->chaninfo));
539                 print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/);
540         }
541         if (req->chaninfo.ic_nchans == 0)
542                 errx(1, "no channels calculated");
543         set80211(s, IEEE80211_IOC_REGDOMAIN, 0,
544             IEEE80211_REGDOMAIN_SPACE(req), req);
545         free(req);
546         free(dc);
547 }
548
549 static int
550 ieee80211_mhz2ieee(int freq, int flags)
551 {
552         struct ieee80211_channel chan;
553         mapfreq(&chan, freq, flags);
554         return chan.ic_ieee;
555 }
556
557 static int
558 isanyarg(const char *arg)
559 {
560         return (ismatch(arg, "-") ||
561                 ismatch(arg, "any") ||
562                 ismatch(arg, "off"));
563 }
564
565 static void
566 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
567 {
568         int             ssid;
569         int             len;
570         u_int8_t        data[IEEE80211_NWID_LEN];
571
572         ssid = 0;
573         len = strlen(val);
574         if (len > 2 && isdigit((int)val[0]) && val[1] == ':') {
575                 ssid = atoi(val)-1;
576                 val += 2;
577         }
578
579         bzero(data, sizeof(data));
580         len = sizeof(data);
581         if (get_string(val, NULL, data, &len) == NULL)
582                 exit(1);
583
584         set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
585 }
586
587 static void
588 set80211meshid(const char *val, int d, int s, const struct afswtch *rafp)
589 {
590         int             len;
591         u_int8_t        data[IEEE80211_NWID_LEN];
592
593         memset(data, 0, sizeof(data));
594         len = sizeof(data);
595         if (get_string(val, NULL, data, &len) == NULL)
596                 exit(1);
597
598         set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data);
599 }
600
601 static void
602 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
603 {
604         int                     len;
605         u_int8_t                data[33];
606
607         bzero(data, sizeof(data));
608         len = sizeof(data);
609         get_string(val, NULL, data, &len);
610
611         set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
612 }
613
614 /*
615  * Parse a channel specification for attributes/flags.
616  * The syntax is:
617  *      freq/xx         channel width (5,10,20,40,40+,40-)
618  *      freq:mode       channel mode (a,b,g,h,n,t,s,d)
619  *
620  * These can be combined in either order; e.g. 2437:ng/40.
621  * Modes are case insensitive.
622  *
623  * The result is not validated here; it's assumed to be
624  * checked against the channel table fetched from the kernel.
625  */
626 static int
627 getchannelflags(const char *val, int freq)
628 {
629 #define _CHAN_HT        0x80000000
630         const char *cp;
631         int flags;
632
633         flags = 0;
634
635         cp = strchr(val, ':');
636         if (cp != NULL) {
637                 for (cp++; isalpha((int) *cp); cp++) {
638                         /* accept mixed case */
639                         int c = *cp;
640                         if (isupper(c))
641                                 c = tolower(c);
642                         switch (c) {
643                         case 'a':               /* 802.11a */
644                                 flags |= IEEE80211_CHAN_A;
645                                 break;
646                         case 'b':               /* 802.11b */
647                                 flags |= IEEE80211_CHAN_B;
648                                 break;
649                         case 'g':               /* 802.11g */
650                                 flags |= IEEE80211_CHAN_G;
651                                 break;
652                         case 'h':               /* ht = 802.11n */
653                         case 'n':               /* 802.11n */
654                                 flags |= _CHAN_HT;      /* NB: private */
655                                 break;
656                         case 'd':               /* dt = Atheros Dynamic Turbo */
657                                 flags |= IEEE80211_CHAN_TURBO;
658                                 break;
659                         case 't':               /* ht, dt, st, t */
660                                 /* dt and unadorned t specify Dynamic Turbo */
661                                 if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
662                                         flags |= IEEE80211_CHAN_TURBO;
663                                 break;
664                         case 's':               /* st = Atheros Static Turbo */
665                                 flags |= IEEE80211_CHAN_STURBO;
666                                 break;
667                         default:
668                                 errx(-1, "%s: Invalid channel attribute %c\n",
669                                     val, *cp);
670                         }
671                 }
672         }
673         cp = strchr(val, '/');
674         if (cp != NULL) {
675                 char *ep;
676                 u_long cw = strtoul(cp+1, &ep, 10);
677
678                 switch (cw) {
679                 case 5:
680                         flags |= IEEE80211_CHAN_QUARTER;
681                         break;
682                 case 10:
683                         flags |= IEEE80211_CHAN_HALF;
684                         break;
685                 case 20:
686                         /* NB: this may be removed below */
687                         flags |= IEEE80211_CHAN_HT20;
688                         break;
689                 case 40:
690                         if (ep != NULL && *ep == '+')
691                                 flags |= IEEE80211_CHAN_HT40U;
692                         else if (ep != NULL && *ep == '-')
693                                 flags |= IEEE80211_CHAN_HT40D;
694                         break;
695                 default:
696                         errx(-1, "%s: Invalid channel width\n", val);
697                 }
698         }
699         /*
700          * Cleanup specifications.
701          */
702         if ((flags & _CHAN_HT) == 0) {
703                 /*
704                  * If user specified freq/20 or freq/40 quietly remove
705                  * HT cw attributes depending on channel use.  To give
706                  * an explicit 20/40 width for an HT channel you must
707                  * indicate it is an HT channel since all HT channels
708                  * are also usable for legacy operation; e.g. freq:n/40.
709                  */
710                 flags &= ~IEEE80211_CHAN_HT;
711         } else {
712                 /*
713                  * Remove private indicator that this is an HT channel
714                  * and if no explicit channel width has been given
715                  * provide the default settings.
716                  */
717                 flags &= ~_CHAN_HT;
718                 if ((flags & IEEE80211_CHAN_HT) == 0) {
719                         struct ieee80211_channel chan;
720                         /*
721                          * Consult the channel list to see if we can use
722                          * HT40+ or HT40- (if both the map routines choose).
723                          */
724                         if (freq > 255)
725                                 mapfreq(&chan, freq, 0);
726                         else
727                                 mapchan(&chan, freq, 0);
728                         flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
729                 }
730         }
731         return flags;
732 #undef _CHAN_HT
733 }
734
735 static void
736 getchannel(int s, struct ieee80211_channel *chan, const char *val)
737 {
738         int v, flags;
739         char *eptr;
740
741         memset(chan, 0, sizeof(*chan));
742         if (isanyarg(val)) {
743                 chan->ic_freq = IEEE80211_CHAN_ANY;
744                 return;
745         }
746         getchaninfo(s);
747         errno = 0;
748         v = strtol(val, &eptr, 10);
749         if (val[0] == '\0' || val == eptr || errno == ERANGE ||
750             /* channel may be suffixed with nothing, :flag, or /width */
751             (eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/'))
752                 errx(1, "invalid channel specification%s",
753                     errno == ERANGE ? " (out of range)" : "");
754         flags = getchannelflags(val, v);
755         if (v > 255) {          /* treat as frequency */
756                 mapfreq(chan, v, flags);
757         } else {
758                 mapchan(chan, v, flags);
759         }
760 }
761
762 static void
763 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
764 {
765         struct ieee80211_channel chan;
766
767         getchannel(s, &chan, val);
768         set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
769 }
770
771 static void
772 set80211chanswitch(const char *val, int d, int s, const struct afswtch *rafp)
773 {
774         struct ieee80211_chanswitch_req csr;
775
776         getchannel(s, &csr.csa_chan, val);
777         csr.csa_mode = 1;
778         csr.csa_count = 5;
779         set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr);
780 }
781
782 static void
783 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
784 {
785         int     mode;
786
787         if (iseq(val, "none")) {
788                 mode = IEEE80211_AUTH_NONE;
789         } else if (iseq(val, "open")) {
790                 mode = IEEE80211_AUTH_OPEN;
791         } else if (iseq(val, "shared")) {
792                 mode = IEEE80211_AUTH_SHARED;
793         } else if (iseq(val, "8021x")) {
794                 mode = IEEE80211_AUTH_8021X;
795         } else if (iseq(val, "wpa")) {
796                 mode = IEEE80211_AUTH_WPA;
797         } else {
798                 errx(1, "unknown authmode");
799         }
800
801         set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
802 }
803
804 static void
805 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
806 {
807         int     mode;
808
809         if (iseq(val, "off")) {
810                 mode = IEEE80211_POWERSAVE_OFF;
811         } else if (iseq(val, "on")) {
812                 mode = IEEE80211_POWERSAVE_ON;
813         } else if (iseq(val, "cam")) {
814                 mode = IEEE80211_POWERSAVE_CAM;
815         } else if (iseq(val, "psp")) {
816                 mode = IEEE80211_POWERSAVE_PSP;
817         } else if (iseq(val, "psp-cam")) {
818                 mode = IEEE80211_POWERSAVE_PSP_CAM;
819         } else {
820                 errx(1, "unknown powersavemode");
821         }
822
823         set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
824 }
825
826 static void
827 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
828 {
829         if (d == 0)
830                 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
831                     0, NULL);
832         else
833                 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
834                     0, NULL);
835 }
836
837 static void
838 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
839 {
840         set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
841 }
842
843 static void
844 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
845 {
846         int     mode;
847
848         if (iseq(val, "off")) {
849                 mode = IEEE80211_WEP_OFF;
850         } else if (iseq(val, "on")) {
851                 mode = IEEE80211_WEP_ON;
852         } else if (iseq(val, "mixed")) {
853                 mode = IEEE80211_WEP_MIXED;
854         } else {
855                 errx(1, "unknown wep mode");
856         }
857
858         set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
859 }
860
861 static void
862 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
863 {
864         set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
865 }
866
867 static int
868 isundefarg(const char *arg)
869 {
870         return (strcmp(arg, "-") == 0 || ismatch(arg, "undef"));
871 }
872
873 static void
874 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
875 {
876         if (isundefarg(val))
877                 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
878         else
879                 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
880 }
881
882 static void
883 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
884 {
885         int             key = 0;
886         int             len;
887         u_int8_t        data[IEEE80211_KEYBUF_SIZE];
888
889         if (isdigit((int)val[0]) && val[1] == ':') {
890                 key = atoi(val)-1;
891                 val += 2;
892         }
893
894         bzero(data, sizeof(data));
895         len = sizeof(data);
896         get_string(val, NULL, data, &len);
897
898         set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
899 }
900
901 /*
902  * This function is purely a NetBSD compatibility interface.  The NetBSD
903  * interface is too inflexible, but it's there so we'll support it since
904  * it's not all that hard.
905  */
906 static void
907 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
908 {
909         int             txkey;
910         int             i, len;
911         u_int8_t        data[IEEE80211_KEYBUF_SIZE];
912
913         set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
914
915         if (isdigit((int)val[0]) && val[1] == ':') {
916                 txkey = val[0]-'0'-1;
917                 val += 2;
918
919                 for (i = 0; i < 4; i++) {
920                         bzero(data, sizeof(data));
921                         len = sizeof(data);
922                         val = get_string(val, ",", data, &len);
923                         if (val == NULL)
924                                 exit(1);
925
926                         set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
927                 }
928         } else {
929                 bzero(data, sizeof(data));
930                 len = sizeof(data);
931                 get_string(val, NULL, data, &len);
932                 txkey = 0;
933
934                 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
935
936                 bzero(data, sizeof(data));
937                 for (i = 1; i < 4; i++)
938                         set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
939         }
940
941         set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
942 }
943
944 static void
945 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
946 {
947         set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
948                 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
949 }
950
951 static void
952 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
953 {
954         int     mode;
955
956         if (iseq(val, "off")) {
957                 mode = IEEE80211_PROTMODE_OFF;
958         } else if (iseq(val, "cts")) {
959                 mode = IEEE80211_PROTMODE_CTS;
960         } else if (ismatch(val, "rts")) {
961                 mode = IEEE80211_PROTMODE_RTSCTS;
962         } else {
963                 errx(1, "unknown protection mode");
964         }
965
966         set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
967 }
968
969 static void
970 set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp)
971 {
972         int     mode;
973
974         if (iseq(val, "off")) {
975                 mode = IEEE80211_PROTMODE_OFF;
976         } else if (ismatch(val, "rts")) {
977                 mode = IEEE80211_PROTMODE_RTSCTS;
978         } else {
979                 errx(1, "unknown protection mode");
980         }
981
982         set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
983 }
984
985 static void
986 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
987 {
988         double v = atof(val);
989         int txpow;
990
991         txpow = (int) (2*v);
992         if (txpow != 2*v)
993                 errx(-1, "invalid tx power (must be .5 dBm units)");
994         set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
995 }
996
997 #define IEEE80211_ROAMING_DEVICE        0
998 #define IEEE80211_ROAMING_AUTO          1
999 #define IEEE80211_ROAMING_MANUAL        2
1000
1001 static void
1002 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
1003 {
1004         int mode;
1005
1006         if (iseq(val, "device")) {
1007                 mode = IEEE80211_ROAMING_DEVICE;
1008         } else if (iseq(val, "auto")) {
1009                 mode = IEEE80211_ROAMING_AUTO;
1010         } else if (iseq(val, "manual")) {
1011                 mode = IEEE80211_ROAMING_MANUAL;
1012         } else {
1013                 errx(1, "unknown roaming mode");
1014         }
1015         set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
1016 }
1017
1018 static void
1019 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
1020 {
1021         set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
1022 }
1023
1024 static void
1025 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
1026 {
1027         set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
1028 }
1029
1030 static void
1031 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
1032 {
1033         set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
1034 }
1035
1036 static void
1037 set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
1038 {
1039         set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
1040 }
1041
1042 static void
1043 set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
1044 {
1045         set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
1046 }
1047
1048 static void
1049 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
1050 {
1051         struct ieee80211req_chanlist chanlist;
1052         char *temp, *cp, *tp;
1053
1054         temp = strdup(val);
1055         if (temp == NULL)
1056                 errx(1, "strdup failed");
1057         memset(&chanlist, 0, sizeof(chanlist));
1058         cp = temp;
1059         for (;;) {
1060                 int first, last, f, c;
1061
1062                 tp = strchr(cp, ',');
1063                 if (tp != NULL)
1064                         *tp++ = '\0';
1065                 switch (sscanf(cp, "%u-%u", &first, &last)) {
1066                 case 1:
1067                         if (first > IEEE80211_CHAN_MAX)
1068                                 errx(-1, "channel %u out of range, max %u",
1069                                         first, IEEE80211_CHAN_MAX);
1070                         setbit(chanlist.ic_channels, first);
1071                         break;
1072                 case 2:
1073                         if (first > IEEE80211_CHAN_MAX)
1074                                 errx(-1, "channel %u out of range, max %u",
1075                                         first, IEEE80211_CHAN_MAX);
1076                         if (last > IEEE80211_CHAN_MAX)
1077                                 errx(-1, "channel %u out of range, max %u",
1078                                         last, IEEE80211_CHAN_MAX);
1079                         if (first > last)
1080                                 errx(-1, "void channel range, %u > %u",
1081                                         first, last);
1082                         for (f = first; f <= last; f++)
1083                                 setbit(chanlist.ic_channels, f);
1084                         break;
1085                 }
1086                 if (tp == NULL)
1087                         break;
1088                 c = *tp;
1089                 while (isspace(c))
1090                         tp++;
1091                 if (!isdigit(c))
1092                         break;
1093                 cp = tp;
1094         }
1095         set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
1096 }
1097
1098 static void
1099 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
1100 {
1101
1102         if (!isanyarg(val)) {
1103                 char *temp;
1104                 struct sockaddr_dl sdl;
1105
1106                 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1107                 if (temp == NULL)
1108                         errx(1, "malloc failed");
1109                 temp[0] = ':';
1110                 strcpy(temp + 1, val);
1111                 sdl.sdl_len = sizeof(sdl);
1112                 link_addr(temp, &sdl);
1113                 free(temp);
1114                 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1115                         errx(1, "malformed link-level address");
1116                 set80211(s, IEEE80211_IOC_BSSID, 0,
1117                         IEEE80211_ADDR_LEN, LLADDR(&sdl));
1118         } else {
1119                 uint8_t zerobssid[IEEE80211_ADDR_LEN];
1120                 memset(zerobssid, 0, sizeof(zerobssid));
1121                 set80211(s, IEEE80211_IOC_BSSID, 0,
1122                         IEEE80211_ADDR_LEN, zerobssid);
1123         }
1124 }
1125
1126 static int
1127 getac(const char *ac)
1128 {
1129         if (iseq(ac, "ac_be") || iseq(ac, "be"))
1130                 return WME_AC_BE;
1131         if (iseq(ac, "ac_bk") || iseq(ac, "bk"))
1132                 return WME_AC_BK;
1133         if (iseq(ac, "ac_vi") || iseq(ac, "vi"))
1134                 return WME_AC_VI;
1135         if (iseq(ac, "ac_vo") || iseq(ac, "vo"))
1136                 return WME_AC_VO;
1137         errx(1, "unknown wme access class %s", ac);
1138 }
1139
1140 static
1141 DECL_CMD_FUNC2(set80211cwmin, ac, val)
1142 {
1143         set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
1144 }
1145
1146 static
1147 DECL_CMD_FUNC2(set80211cwmax, ac, val)
1148 {
1149         set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
1150 }
1151
1152 static
1153 DECL_CMD_FUNC2(set80211aifs, ac, val)
1154 {
1155         set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
1156 }
1157
1158 static
1159 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
1160 {
1161         set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
1162 }
1163
1164 static
1165 DECL_CMD_FUNC(set80211acm, ac, d)
1166 {
1167         set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
1168 }
1169 static
1170 DECL_CMD_FUNC(set80211noacm, ac, d)
1171 {
1172         set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
1173 }
1174
1175 static
1176 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
1177 {
1178         set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
1179 }
1180 static
1181 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
1182 {
1183         set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
1184 }
1185
1186 static
1187 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
1188 {
1189         set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
1190                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1191 }
1192
1193 static
1194 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
1195 {
1196         set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
1197                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1198 }
1199
1200 static
1201 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
1202 {
1203         set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
1204                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1205 }
1206
1207 static
1208 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
1209 {
1210         set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
1211                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1212 }
1213
1214 static
1215 DECL_CMD_FUNC(set80211dtimperiod, val, d)
1216 {
1217         set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
1218 }
1219
1220 static
1221 DECL_CMD_FUNC(set80211bintval, val, d)
1222 {
1223         set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
1224 }
1225
1226 static void
1227 set80211macmac(int s, int op, const char *val)
1228 {
1229         char *temp;
1230         struct sockaddr_dl sdl;
1231
1232         temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1233         if (temp == NULL)
1234                 errx(1, "malloc failed");
1235         temp[0] = ':';
1236         strcpy(temp + 1, val);
1237         sdl.sdl_len = sizeof(sdl);
1238         link_addr(temp, &sdl);
1239         free(temp);
1240         if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1241                 errx(1, "malformed link-level address");
1242         set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
1243 }
1244
1245 static
1246 DECL_CMD_FUNC(set80211addmac, val, d)
1247 {
1248         set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
1249 }
1250
1251 static
1252 DECL_CMD_FUNC(set80211delmac, val, d)
1253 {
1254         set80211macmac(s, IEEE80211_IOC_DELMAC, val);
1255 }
1256
1257 static
1258 DECL_CMD_FUNC(set80211kickmac, val, d)
1259 {
1260         char *temp;
1261         struct sockaddr_dl sdl;
1262         struct ieee80211req_mlme mlme;
1263
1264         temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1265         if (temp == NULL)
1266                 errx(1, "malloc failed");
1267         temp[0] = ':';
1268         strcpy(temp + 1, val);
1269         sdl.sdl_len = sizeof(sdl);
1270         link_addr(temp, &sdl);
1271         free(temp);
1272         if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1273                 errx(1, "malformed link-level address");
1274         memset(&mlme, 0, sizeof(mlme));
1275         mlme.im_op = IEEE80211_MLME_DEAUTH;
1276         mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
1277         memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
1278         set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
1279 }
1280
1281 static
1282 DECL_CMD_FUNC(set80211maccmd, val, d)
1283 {
1284         set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
1285 }
1286
1287 static void
1288 set80211meshrtmac(int s, int req, const char *val)
1289 {
1290         char *temp;
1291         struct sockaddr_dl sdl;
1292
1293         temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1294         if (temp == NULL)
1295                 errx(1, "malloc failed");
1296         temp[0] = ':';
1297         strcpy(temp + 1, val);
1298         sdl.sdl_len = sizeof(sdl);
1299         link_addr(temp, &sdl);
1300         free(temp);
1301         if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1302                 errx(1, "malformed link-level address");
1303         set80211(s, IEEE80211_IOC_MESH_RTCMD, req,
1304             IEEE80211_ADDR_LEN, LLADDR(&sdl));
1305 }
1306
1307 static
1308 DECL_CMD_FUNC(set80211addmeshrt, val, d)
1309 {
1310         set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val);
1311 }
1312
1313 static
1314 DECL_CMD_FUNC(set80211delmeshrt, val, d)
1315 {
1316         set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val);
1317 }
1318
1319 static
1320 DECL_CMD_FUNC(set80211meshrtcmd, val, d)
1321 {
1322         set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL);
1323 }
1324
1325 static
1326 DECL_CMD_FUNC(set80211hwmprootmode, val, d)
1327 {
1328         int mode;
1329
1330         if (iseq(val, "normal"))
1331                 mode = IEEE80211_HWMP_ROOTMODE_NORMAL;
1332         else if (iseq(val, "proactive"))
1333                 mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
1334         else if (iseq(val, "rann"))
1335                 mode = IEEE80211_HWMP_ROOTMODE_RANN;
1336         else
1337                 mode = IEEE80211_HWMP_ROOTMODE_DISABLED;
1338         set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL);
1339 }
1340
1341 static
1342 DECL_CMD_FUNC(set80211hwmpmaxhops, val, d)
1343 {
1344         set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL);
1345 }
1346
1347 static void
1348 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
1349 {
1350         set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
1351 }
1352
1353 static void
1354 set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
1355 {
1356         set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
1357 }
1358
1359 static
1360 DECL_CMD_FUNC(set80211bgscanidle, val, d)
1361 {
1362         set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
1363 }
1364
1365 static
1366 DECL_CMD_FUNC(set80211bgscanintvl, val, d)
1367 {
1368         set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
1369 }
1370
1371 static
1372 DECL_CMD_FUNC(set80211scanvalid, val, d)
1373 {
1374         set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
1375 }
1376
1377 /*
1378  * Parse an optional trailing specification of which netbands
1379  * to apply a parameter to.  This is basically the same syntax
1380  * as used for channels but you can concatenate to specify
1381  * multiple.  For example:
1382  *      14:abg          apply to 11a, 11b, and 11g
1383  *      6:ht            apply to 11na and 11ng
1384  * We don't make a big effort to catch silly things; this is
1385  * really a convenience mechanism.
1386  */
1387 static int
1388 getmodeflags(const char *val)
1389 {
1390         const char *cp;
1391         int flags;
1392
1393         flags = 0;
1394
1395         cp = strchr(val, ':');
1396         if (cp != NULL) {
1397                 for (cp++; isalpha((int) *cp); cp++) {
1398                         /* accept mixed case */
1399                         int c = *cp;
1400                         if (isupper(c))
1401                                 c = tolower(c);
1402                         switch (c) {
1403                         case 'a':               /* 802.11a */
1404                                 flags |= IEEE80211_CHAN_A;
1405                                 break;
1406                         case 'b':               /* 802.11b */
1407                                 flags |= IEEE80211_CHAN_B;
1408                                 break;
1409                         case 'g':               /* 802.11g */
1410                                 flags |= IEEE80211_CHAN_G;
1411                                 break;
1412                         case 'n':               /* 802.11n */
1413                                 flags |= IEEE80211_CHAN_HT;
1414                                 break;
1415                         case 'd':               /* dt = Atheros Dynamic Turbo */
1416                                 flags |= IEEE80211_CHAN_TURBO;
1417                                 break;
1418                         case 't':               /* ht, dt, st, t */
1419                                 /* dt and unadorned t specify Dynamic Turbo */
1420                                 if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0)
1421                                         flags |= IEEE80211_CHAN_TURBO;
1422                                 break;
1423                         case 's':               /* st = Atheros Static Turbo */
1424                                 flags |= IEEE80211_CHAN_STURBO;
1425                                 break;
1426                         case 'h':               /* 1/2-width channels */
1427                                 flags |= IEEE80211_CHAN_HALF;
1428                                 break;
1429                         case 'q':               /* 1/4-width channels */
1430                                 flags |= IEEE80211_CHAN_QUARTER;
1431                                 break;
1432                         default:
1433                                 errx(-1, "%s: Invalid mode attribute %c\n",
1434                                     val, *cp);
1435                         }
1436                 }
1437         }
1438         return flags;
1439 }
1440
1441 #define IEEE80211_CHAN_HTA      (IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ)
1442 #define IEEE80211_CHAN_HTG      (IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ)
1443
1444 #define _APPLY(_flags, _base, _param, _v) do {                          \
1445     if (_flags & IEEE80211_CHAN_HT) {                                   \
1446             if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1447                     _base.params[IEEE80211_MODE_11NA]._param = _v;      \
1448                     _base.params[IEEE80211_MODE_11NG]._param = _v;      \
1449             } else if (_flags & IEEE80211_CHAN_5GHZ)                    \
1450                     _base.params[IEEE80211_MODE_11NA]._param = _v;      \
1451             else                                                        \
1452                     _base.params[IEEE80211_MODE_11NG]._param = _v;      \
1453     }                                                                   \
1454     if (_flags & IEEE80211_CHAN_TURBO) {                                \
1455             if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1456                     _base.params[IEEE80211_MODE_TURBO_A]._param = _v;   \
1457                     _base.params[IEEE80211_MODE_TURBO_G]._param = _v;   \
1458             } else if (_flags & IEEE80211_CHAN_5GHZ)                    \
1459                     _base.params[IEEE80211_MODE_TURBO_A]._param = _v;   \
1460             else                                                        \
1461                     _base.params[IEEE80211_MODE_TURBO_G]._param = _v;   \
1462     }                                                                   \
1463     if (_flags & IEEE80211_CHAN_STURBO)                                 \
1464             _base.params[IEEE80211_MODE_STURBO_A]._param = _v;          \
1465     if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)                \
1466             _base.params[IEEE80211_MODE_11A]._param = _v;               \
1467     if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)                \
1468             _base.params[IEEE80211_MODE_11G]._param = _v;               \
1469     if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)                \
1470             _base.params[IEEE80211_MODE_11B]._param = _v;               \
1471     if (_flags & IEEE80211_CHAN_HALF)                                   \
1472             _base.params[IEEE80211_MODE_HALF]._param = _v;              \
1473     if (_flags & IEEE80211_CHAN_QUARTER)                                \
1474             _base.params[IEEE80211_MODE_QUARTER]._param = _v;           \
1475 } while (0)
1476 #define _APPLY1(_flags, _base, _param, _v) do {                         \
1477     if (_flags & IEEE80211_CHAN_HT) {                                   \
1478             if (_flags & IEEE80211_CHAN_5GHZ)                           \
1479                     _base.params[IEEE80211_MODE_11NA]._param = _v;      \
1480             else                                                        \
1481                     _base.params[IEEE80211_MODE_11NG]._param = _v;      \
1482     } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)   \
1483             _base.params[IEEE80211_MODE_TURBO_A]._param = _v;           \
1484     else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)     \
1485             _base.params[IEEE80211_MODE_TURBO_G]._param = _v;           \
1486     else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)         \
1487             _base.params[IEEE80211_MODE_STURBO_A]._param = _v;          \
1488     else if (_flags & IEEE80211_CHAN_HALF)                              \
1489             _base.params[IEEE80211_MODE_HALF]._param = _v;              \
1490     else if (_flags & IEEE80211_CHAN_QUARTER)                           \
1491             _base.params[IEEE80211_MODE_QUARTER]._param = _v;           \
1492     else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)           \
1493             _base.params[IEEE80211_MODE_11A]._param = _v;               \
1494     else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)           \
1495             _base.params[IEEE80211_MODE_11G]._param = _v;               \
1496     else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)           \
1497             _base.params[IEEE80211_MODE_11B]._param = _v;               \
1498 } while (0)
1499 #define _APPLY_RATE(_flags, _base, _param, _v) do {                     \
1500     if (_flags & IEEE80211_CHAN_HT) {                                   \
1501         (_v) = (_v / 2) | IEEE80211_RATE_MCS;                           \
1502     }                                                                   \
1503     _APPLY(_flags, _base, _param, _v);                                  \
1504 } while (0)
1505 #define _APPLY_RATE1(_flags, _base, _param, _v) do {                    \
1506     if (_flags & IEEE80211_CHAN_HT) {                                   \
1507         (_v) = (_v / 2) | IEEE80211_RATE_MCS;                           \
1508     }                                                                   \
1509     _APPLY1(_flags, _base, _param, _v);                                 \
1510 } while (0)
1511
1512 static
1513 DECL_CMD_FUNC(set80211roamrssi, val, d)
1514 {
1515         double v = atof(val);
1516         int rssi, flags;
1517
1518         rssi = (int) (2*v);
1519         if (rssi != 2*v)
1520                 errx(-1, "invalid rssi (must be .5 dBm units)");
1521         flags = getmodeflags(val);
1522         getroam(s);
1523         if (flags == 0) {               /* NB: no flags => current channel */
1524                 flags = getcurchan(s)->ic_flags;
1525                 _APPLY1(flags, roamparams, rssi, rssi);
1526         } else
1527                 _APPLY(flags, roamparams, rssi, rssi);
1528         callback_register(setroam_cb, &roamparams);
1529 }
1530
1531 static int
1532 getrate(const char *val, const char *tag)
1533 {
1534         double v = atof(val);
1535         int rate;
1536
1537         rate = (int) (2*v);
1538         if (rate != 2*v)
1539                 errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag);
1540         return rate;            /* NB: returns 2x the specified value */
1541 }
1542
1543 static
1544 DECL_CMD_FUNC(set80211roamrate, val, d)
1545 {
1546         int rate, flags;
1547
1548         rate = getrate(val, "roam");
1549         flags = getmodeflags(val);
1550         getroam(s);
1551         if (flags == 0) {               /* NB: no flags => current channel */
1552                 flags = getcurchan(s)->ic_flags;
1553                 _APPLY_RATE1(flags, roamparams, rate, rate);
1554         } else
1555                 _APPLY_RATE(flags, roamparams, rate, rate);
1556         callback_register(setroam_cb, &roamparams);
1557 }
1558
1559 static
1560 DECL_CMD_FUNC(set80211mcastrate, val, d)
1561 {
1562         int rate, flags;
1563
1564         rate = getrate(val, "mcast");
1565         flags = getmodeflags(val);
1566         gettxparams(s);
1567         if (flags == 0) {               /* NB: no flags => current channel */
1568                 flags = getcurchan(s)->ic_flags;
1569                 _APPLY_RATE1(flags, txparams, mcastrate, rate);
1570         } else
1571                 _APPLY_RATE(flags, txparams, mcastrate, rate);
1572         callback_register(settxparams_cb, &txparams);
1573 }
1574
1575 static
1576 DECL_CMD_FUNC(set80211mgtrate, val, d)
1577 {
1578         int rate, flags;
1579
1580         rate = getrate(val, "mgmt");
1581         flags = getmodeflags(val);
1582         gettxparams(s);
1583         if (flags == 0) {               /* NB: no flags => current channel */
1584                 flags = getcurchan(s)->ic_flags;
1585                 _APPLY_RATE1(flags, txparams, mgmtrate, rate);
1586         } else
1587                 _APPLY_RATE(flags, txparams, mgmtrate, rate);
1588         callback_register(settxparams_cb, &txparams);
1589 }
1590
1591 static
1592 DECL_CMD_FUNC(set80211ucastrate, val, d)
1593 {
1594         int flags;
1595
1596         gettxparams(s);
1597         flags = getmodeflags(val);
1598         if (isanyarg(val)) {
1599                 if (flags == 0) {       /* NB: no flags => current channel */
1600                         flags = getcurchan(s)->ic_flags;
1601                         _APPLY1(flags, txparams, ucastrate,
1602                             IEEE80211_FIXED_RATE_NONE);
1603                 } else
1604                         _APPLY(flags, txparams, ucastrate,
1605                             IEEE80211_FIXED_RATE_NONE);
1606         } else {
1607                 int rate = getrate(val, "ucast");
1608                 if (flags == 0) {       /* NB: no flags => current channel */
1609                         flags = getcurchan(s)->ic_flags;
1610                         _APPLY_RATE1(flags, txparams, ucastrate, rate);
1611                 } else
1612                         _APPLY_RATE(flags, txparams, ucastrate, rate);
1613         }
1614         callback_register(settxparams_cb, &txparams);
1615 }
1616
1617 static
1618 DECL_CMD_FUNC(set80211maxretry, val, d)
1619 {
1620         int v = atoi(val), flags;
1621
1622         flags = getmodeflags(val);
1623         gettxparams(s);
1624         if (flags == 0) {               /* NB: no flags => current channel */
1625                 flags = getcurchan(s)->ic_flags;
1626                 _APPLY1(flags, txparams, maxretry, v);
1627         } else
1628                 _APPLY(flags, txparams, maxretry, v);
1629         callback_register(settxparams_cb, &txparams);
1630 }
1631 #undef _APPLY_RATE
1632 #undef _APPLY
1633 #undef IEEE80211_CHAN_HTA
1634 #undef IEEE80211_CHAN_HTG
1635
1636 static
1637 DECL_CMD_FUNC(set80211fragthreshold, val, d)
1638 {
1639         set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
1640                 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
1641 }
1642
1643 static
1644 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
1645 {
1646         set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
1647                 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
1648 }
1649
1650 static void
1651 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
1652 {
1653         set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
1654 }
1655
1656 static void
1657 set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
1658 {
1659         set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
1660 }
1661
1662 static void
1663 set80211dfs(const char *val, int d, int s, const struct afswtch *rafp)
1664 {
1665         set80211(s, IEEE80211_IOC_DFS, d, 0, NULL);
1666 }
1667
1668 static void
1669 set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp)
1670 {
1671         set80211(s, IEEE80211_IOC_SHORTGI,
1672                 d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
1673                 0, NULL);
1674 }
1675
1676 static void
1677 set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp)
1678 {
1679         int ampdu;
1680
1681         if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
1682                 errx(-1, "cannot get AMPDU setting");
1683         if (d < 0) {
1684                 d = -d;
1685                 ampdu &= ~d;
1686         } else
1687                 ampdu |= d;
1688         set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
1689 }
1690
1691 static
1692 DECL_CMD_FUNC(set80211ampdulimit, val, d)
1693 {
1694         int v;
1695
1696         switch (atoi(val)) {
1697         case 8:
1698         case 8*1024:
1699                 v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
1700                 break;
1701         case 16:
1702         case 16*1024:
1703                 v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
1704                 break;
1705         case 32:
1706         case 32*1024:
1707                 v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
1708                 break;
1709         case 64:
1710         case 64*1024:
1711                 v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
1712                 break;
1713         default:
1714                 errx(-1, "invalid A-MPDU limit %s", val);
1715         }
1716         set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
1717 }
1718
1719 static
1720 DECL_CMD_FUNC(set80211ampdudensity, val, d)
1721 {
1722         int v;
1723
1724         if (isanyarg(val) || iseq(val, "na"))
1725                 v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1726         else switch ((int)(atof(val)*4)) {
1727         case 0:
1728                 v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1729                 break;
1730         case 1:
1731                 v = IEEE80211_HTCAP_MPDUDENSITY_025;
1732                 break;
1733         case 2:
1734                 v = IEEE80211_HTCAP_MPDUDENSITY_05;
1735                 break;
1736         case 4:
1737                 v = IEEE80211_HTCAP_MPDUDENSITY_1;
1738                 break;
1739         case 8:
1740                 v = IEEE80211_HTCAP_MPDUDENSITY_2;
1741                 break;
1742         case 16:
1743                 v = IEEE80211_HTCAP_MPDUDENSITY_4;
1744                 break;
1745         case 32:
1746                 v = IEEE80211_HTCAP_MPDUDENSITY_8;
1747                 break;
1748         case 64:
1749                 v = IEEE80211_HTCAP_MPDUDENSITY_16;
1750                 break;
1751         default:
1752                 errx(-1, "invalid A-MPDU density %s", val);
1753         }
1754         set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
1755 }
1756
1757 static void
1758 set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
1759 {
1760         int amsdu;
1761
1762         if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
1763                 err(-1, "cannot get AMSDU setting");
1764         if (d < 0) {
1765                 d = -d;
1766                 amsdu &= ~d;
1767         } else
1768                 amsdu |= d;
1769         set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
1770 }
1771
1772 static
1773 DECL_CMD_FUNC(set80211amsdulimit, val, d)
1774 {
1775         set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
1776 }
1777
1778 static void
1779 set80211puren(const char *val, int d, int s, const struct afswtch *rafp)
1780 {
1781         set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
1782 }
1783
1784 static void
1785 set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp)
1786 {
1787         set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
1788 }
1789
1790 static void
1791 set80211htconf(const char *val, int d, int s, const struct afswtch *rafp)
1792 {
1793         set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
1794         htconf = d;
1795 }
1796
1797 static void
1798 set80211dwds(const char *val, int d, int s, const struct afswtch *rafp)
1799 {
1800         set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL);
1801 }
1802
1803 static void
1804 set80211inact(const char *val, int d, int s, const struct afswtch *rafp)
1805 {
1806         set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
1807 }
1808
1809 static void
1810 set80211tsn(const char *val, int d, int s, const struct afswtch *rafp)
1811 {
1812         set80211(s, IEEE80211_IOC_TSN, d, 0, NULL);
1813 }
1814
1815 static void
1816 set80211dotd(const char *val, int d, int s, const struct afswtch *rafp)
1817 {
1818         set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL);
1819 }
1820
1821 static void
1822 set80211smps(const char *val, int d, int s, const struct afswtch *rafp)
1823 {
1824         set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL);
1825 }
1826
1827 static void
1828 set80211rifs(const char *val, int d, int s, const struct afswtch *rafp)
1829 {
1830         set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
1831 }
1832
1833 static
1834 DECL_CMD_FUNC(set80211tdmaslot, val, d)
1835 {
1836         set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
1837 }
1838
1839 static
1840 DECL_CMD_FUNC(set80211tdmaslotcnt, val, d)
1841 {
1842         set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
1843 }
1844
1845 static
1846 DECL_CMD_FUNC(set80211tdmaslotlen, val, d)
1847 {
1848         set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
1849 }
1850
1851 static
1852 DECL_CMD_FUNC(set80211tdmabintval, val, d)
1853 {
1854         set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
1855 }
1856
1857 static
1858 DECL_CMD_FUNC(set80211meshttl, val, d)
1859 {
1860         set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
1861 }
1862
1863 static
1864 DECL_CMD_FUNC(set80211meshforward, val, d)
1865 {
1866         set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL);
1867 }
1868
1869 static
1870 DECL_CMD_FUNC(set80211meshpeering, val, d)
1871 {
1872         set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL);
1873 }
1874
1875 static
1876 DECL_CMD_FUNC(set80211meshmetric, val, d)
1877 {
1878         char v[12];
1879
1880         memcpy(v, val, sizeof(v));
1881         set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
1882 }
1883
1884 static
1885 DECL_CMD_FUNC(set80211meshpath, val, d)
1886 {
1887         char v[12];
1888
1889         memcpy(v, val, sizeof(v));
1890         set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
1891 }
1892
1893 static int
1894 regdomain_sort(const void *a, const void *b)
1895 {
1896 #define CHAN_ALL \
1897         (IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)
1898         const struct ieee80211_channel *ca = a;
1899         const struct ieee80211_channel *cb = b;
1900
1901         return ca->ic_freq == cb->ic_freq ?
1902             ((int)ca->ic_flags & CHAN_ALL) - ((int)cb->ic_flags & CHAN_ALL) :
1903             ca->ic_freq - cb->ic_freq;
1904 #undef CHAN_ALL
1905 }
1906
1907 static const struct ieee80211_channel *
1908 chanlookup(const struct ieee80211_channel chans[], int nchans,
1909         int freq, int flags)
1910 {
1911         int i;
1912
1913         flags &= IEEE80211_CHAN_ALLTURBO;
1914         for (i = 0; i < nchans; i++) {
1915                 const struct ieee80211_channel *c = &chans[i];
1916                 if (c->ic_freq == freq &&
1917                     ((int)c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
1918                         return c;
1919         }
1920         return NULL;
1921 }
1922
1923 static int
1924 chanfind(const struct ieee80211_channel chans[], int nchans, int flags)
1925 {
1926         int i;
1927
1928         for (i = 0; i < nchans; i++) {
1929                 const struct ieee80211_channel *c = &chans[i];
1930                 if (((int)c->ic_flags & flags) == flags)
1931                         return 1;
1932         }
1933         return 0;
1934 }
1935
1936 /*
1937  * Check channel compatibility.
1938  */
1939 static int
1940 checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags)
1941 {
1942         flags &= ~REQ_FLAGS;
1943         /*
1944          * Check if exact channel is in the calibration table;
1945          * everything below is to deal with channels that we
1946          * want to include but that are not explicitly listed.
1947          */
1948         if (flags & IEEE80211_CHAN_HT40) {
1949                 /* NB: we use an HT40 channel center that matches HT20 */
1950                 flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20;
1951         }
1952         if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL)
1953                 return 1;
1954         if (flags & IEEE80211_CHAN_GSM) {
1955                 /*
1956                  * XXX GSM frequency mapping is handled in the kernel
1957                  * so we cannot find them in the calibration table;
1958                  * just accept the channel and the kernel will reject
1959                  * the channel list if it's wrong.
1960                  */
1961                 return 1;
1962         }
1963         /*
1964          * If this is a 1/2 or 1/4 width channel allow it if a full
1965          * width channel is present for this frequency, and the device
1966          * supports fractional channels on this band.  This is a hack
1967          * that avoids bloating the calibration table; it may be better
1968          * by per-band attributes though (we are effectively calculating
1969          * this attribute by scanning the channel list ourself).
1970          */
1971         if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0)
1972                 return 0;
1973         if (chanlookup(avail->ic_chans, avail->ic_nchans, freq,
1974             flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL)
1975                 return 0;
1976         if (flags & IEEE80211_CHAN_HALF) {
1977                 return chanfind(avail->ic_chans, avail->ic_nchans,
1978                     IEEE80211_CHAN_HALF |
1979                        (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
1980         } else {
1981                 return chanfind(avail->ic_chans, avail->ic_nchans,
1982                     IEEE80211_CHAN_QUARTER |
1983                         (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
1984         }
1985 }
1986
1987 static void
1988 regdomain_addchans(struct ieee80211req_chaninfo *ci,
1989         const netband_head *bands,
1990         const struct ieee80211_regdomain *reg,
1991         uint32_t chanFlags,
1992         const struct ieee80211req_chaninfo *avail)
1993 {
1994         const struct netband *nb;
1995         const struct freqband *b;
1996         struct ieee80211_channel *c, *prev;
1997         int freq, hi_adj, lo_adj, channelSep;
1998         uint32_t flags;
1999
2000         hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
2001         lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
2002         channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
2003         LIST_FOREACH(nb, bands, next) {
2004                 b = nb->band;
2005                 if (verbose) {
2006                         printf("%s:", __func__);
2007                         printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
2008                         printb(" bandFlags", nb->flags | b->flags,
2009                             IEEE80211_CHAN_BITS);
2010                         putchar('\n');
2011                 }
2012                 prev = NULL;
2013                 for (freq = b->freqStart + lo_adj;
2014                      freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
2015                         /*
2016                          * Construct flags for the new channel.  We take
2017                          * the attributes from the band descriptions except
2018                          * for HT40 which is enabled generically (i.e. +/-
2019                          * extension channel) in the band description and
2020                          * then constrained according by channel separation.
2021                          */
2022                         flags = nb->flags | b->flags;
2023                         if (flags & IEEE80211_CHAN_HT) {
2024                                 /*
2025                                  * HT channels are generated specially; we're
2026                                  * called to add HT20, HT40+, and HT40- chan's
2027                                  * so we need to expand only band specs for
2028                                  * the HT channel type being added.
2029                                  */
2030                                 if ((chanFlags & IEEE80211_CHAN_HT20) &&
2031                                     (flags & IEEE80211_CHAN_HT20) == 0) {
2032                                         if (verbose)
2033                                                 printf("%u: skip, not an "
2034                                                     "HT20 channel\n", freq);
2035                                         continue;
2036                                 }
2037                                 if ((chanFlags & IEEE80211_CHAN_HT40) &&
2038                                     (flags & IEEE80211_CHAN_HT40) == 0) {
2039                                         if (verbose)
2040                                                 printf("%u: skip, not an "
2041                                                     "HT40 channel\n", freq);
2042                                         continue;
2043                                 }
2044                                 /*
2045                                  * DFS and HT40 don't mix.  This should be
2046                                  * expressed in the regdomain database but
2047                                  * just in case enforce it here.
2048                                  */
2049                                 if ((chanFlags & IEEE80211_CHAN_HT40) &&
2050                                     (flags & IEEE80211_CHAN_DFS)) {
2051                                         if (verbose)
2052                                                 printf("%u: skip, HT40+DFS "
2053                                                     "not permitted\n", freq);
2054                                         continue;
2055                                 }
2056                                 /* NB: HT attribute comes from caller */
2057                                 flags &= ~IEEE80211_CHAN_HT;
2058                                 flags |= chanFlags & IEEE80211_CHAN_HT;
2059                         }
2060                         /*
2061                          * Check if device can operate on this frequency.
2062                          */
2063                         if (!checkchan(avail, freq, flags)) {
2064                                 if (verbose) {
2065                                         printf("%u: skip, ", freq);
2066                                         printb("flags", flags,
2067                                             IEEE80211_CHAN_BITS);
2068                                         printf(" not available\n");
2069                                 }
2070                                 continue;
2071                         }
2072                         if ((flags & REQ_ECM) && !reg->ecm) {
2073                                 if (verbose)
2074                                         printf("%u: skip, ECM channel\n", freq);
2075                                 continue;
2076                         }
2077                         if ((flags & REQ_INDOOR) && reg->location == 'O') {
2078                                 if (verbose)
2079                                         printf("%u: skip, indoor channel\n",
2080                                             freq);
2081                                 continue;
2082                         }
2083                         if ((flags & REQ_OUTDOOR) && reg->location == 'I') {
2084                                 if (verbose)
2085                                         printf("%u: skip, outdoor channel\n",
2086                                             freq);
2087                                 continue;
2088                         }
2089                         if ((flags & IEEE80211_CHAN_HT40) &&
2090                             prev != NULL && (freq - prev->ic_freq) < channelSep) {
2091                                 if (verbose)
2092                                         printf("%u: skip, only %u channel "
2093                                             "separation, need %d\n", freq,
2094                                             freq - prev->ic_freq, channelSep);
2095                                 continue;
2096                         }
2097                         if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
2098                                 if (verbose)
2099                                         printf("%u: skip, channel table full\n",
2100                                             freq);
2101                                 break;
2102                         }
2103                         c = &ci->ic_chans[ci->ic_nchans++];
2104                         memset(c, 0, sizeof(*c));
2105                         c->ic_freq = freq;
2106                         c->ic_flags = flags;
2107                         if (c->ic_flags & IEEE80211_CHAN_DFS)
2108                                 c->ic_maxregpower = nb->maxPowerDFS;
2109                         else
2110                                 c->ic_maxregpower = nb->maxPower;
2111                         if (verbose) {
2112                                 printf("[%3d] add freq %u ",
2113                                     ci->ic_nchans-1, c->ic_freq);
2114                                 printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
2115                                 printf(" power %u\n", c->ic_maxregpower);
2116                         }
2117                         /* NB: kernel fills in other fields */
2118                         prev = c;
2119                 }
2120         }
2121 }
2122
2123 static void
2124 regdomain_makechannels(
2125         struct ieee80211_regdomain_req *req,
2126         const struct ieee80211_devcaps_req *dc)
2127 {
2128         struct regdata *rdp = getregdata();
2129         const struct country *cc;
2130         const struct ieee80211_regdomain *reg = &req->rd;
2131         struct ieee80211req_chaninfo *ci = &req->chaninfo;
2132         const struct regdomain *rd;
2133
2134         /*
2135          * Locate construction table for new channel list.  We treat
2136          * the regdomain/SKU as definitive so a country can be in
2137          * multiple with different properties (e.g. US in FCC+FCC3).
2138          * If no regdomain is specified then we fallback on the country
2139          * code to find the associated regdomain since countries always
2140          * belong to at least one regdomain.
2141          */
2142         if (reg->regdomain == 0) {
2143                 cc = lib80211_country_findbycc(rdp, reg->country);
2144                 if (cc == NULL)
2145                         errx(1, "internal error, country %d not found",
2146                             reg->country);
2147                 rd = cc->rd;
2148         } else
2149                 rd = lib80211_regdomain_findbysku(rdp, reg->regdomain);
2150         if (rd == NULL)
2151                 errx(1, "internal error, regdomain %d not found",
2152                             reg->regdomain);
2153         if (rd->sku != SKU_DEBUG) {
2154                 /*
2155                  * regdomain_addchans incrememnts the channel count for
2156                  * each channel it adds so initialize ic_nchans to zero.
2157                  * Note that we know we have enough space to hold all possible
2158                  * channels because the devcaps list size was used to
2159                  * allocate our request.
2160                  */
2161                 ci->ic_nchans = 0;
2162                 if (!LIST_EMPTY(&rd->bands_11b))
2163                         regdomain_addchans(ci, &rd->bands_11b, reg,
2164                             IEEE80211_CHAN_B, &dc->dc_chaninfo);
2165                 if (!LIST_EMPTY(&rd->bands_11g))
2166                         regdomain_addchans(ci, &rd->bands_11g, reg,
2167                             IEEE80211_CHAN_G, &dc->dc_chaninfo);
2168                 if (!LIST_EMPTY(&rd->bands_11a))
2169                         regdomain_addchans(ci, &rd->bands_11a, reg,
2170                             IEEE80211_CHAN_A, &dc->dc_chaninfo);
2171                 if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) {
2172                         regdomain_addchans(ci, &rd->bands_11na, reg,
2173                             IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
2174                             &dc->dc_chaninfo);
2175                         if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2176                                 regdomain_addchans(ci, &rd->bands_11na, reg,
2177                                     IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,
2178                                     &dc->dc_chaninfo);
2179                                 regdomain_addchans(ci, &rd->bands_11na, reg,
2180                                     IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,
2181                                     &dc->dc_chaninfo);
2182                         }
2183                 }
2184                 if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
2185                         regdomain_addchans(ci, &rd->bands_11ng, reg,
2186                             IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
2187                             &dc->dc_chaninfo);
2188                         if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2189                                 regdomain_addchans(ci, &rd->bands_11ng, reg,
2190                                     IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,
2191                                     &dc->dc_chaninfo);
2192                                 regdomain_addchans(ci, &rd->bands_11ng, reg,
2193                                     IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,
2194                                     &dc->dc_chaninfo);
2195                         }
2196                 }
2197                 qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
2198                     regdomain_sort);
2199         } else
2200                 memcpy(ci, &dc->dc_chaninfo,
2201                     IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
2202 }
2203
2204 static void
2205 list_countries(void)
2206 {
2207         struct regdata *rdp = getregdata();
2208         const struct country *cp;
2209         const struct regdomain *dp;
2210         int i;
2211
2212         i = 0;
2213         printf("\nCountry codes:\n");
2214         LIST_FOREACH(cp, &rdp->countries, next) {
2215                 printf("%2s %-15.15s%s", cp->isoname,
2216                     cp->name, ((i+1)%4) == 0 ? "\n" : " ");
2217                 i++;
2218         }
2219         i = 0;
2220         printf("\nRegulatory domains:\n");
2221         LIST_FOREACH(dp, &rdp->domains, next) {
2222                 printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " ");
2223                 i++;
2224         }
2225         printf("\n");
2226 }
2227
2228 static void
2229 defaultcountry(const struct regdomain *rd)
2230 {
2231         struct regdata *rdp = getregdata();
2232         const struct country *cc;
2233
2234         cc = lib80211_country_findbycc(rdp, rd->cc->code);
2235         if (cc == NULL)
2236                 errx(1, "internal error, ISO country code %d not "
2237                     "defined for regdomain %s", rd->cc->code, rd->name);
2238         regdomain.country = cc->code;
2239         regdomain.isocc[0] = cc->isoname[0];
2240         regdomain.isocc[1] = cc->isoname[1];
2241 }
2242
2243 static
2244 DECL_CMD_FUNC(set80211regdomain, val, d)
2245 {
2246         struct regdata *rdp = getregdata();
2247         const struct regdomain *rd;
2248
2249         rd = lib80211_regdomain_findbyname(rdp, val);
2250         if (rd == NULL) {
2251                 char *eptr;
2252                 long sku = strtol(val, &eptr, 0);
2253
2254                 if (eptr != val)
2255                         rd = lib80211_regdomain_findbysku(rdp, sku);
2256                 if (eptr == val || rd == NULL)
2257                         errx(1, "unknown regdomain %s", val);
2258         }
2259         getregdomain(s);
2260         regdomain.regdomain = rd->sku;
2261         if (regdomain.country == 0 && rd->cc != NULL) {
2262                 /*
2263                  * No country code setup and there's a default
2264                  * one for this regdomain fill it in.
2265                  */
2266                 defaultcountry(rd);
2267         }
2268         callback_register(setregdomain_cb, &regdomain);
2269 }
2270
2271 static
2272 DECL_CMD_FUNC(set80211country, val, d)
2273 {
2274         struct regdata *rdp = getregdata();
2275         const struct country *cc;
2276
2277         cc = lib80211_country_findbyname(rdp, val);
2278         if (cc == NULL) {
2279                 char *eptr;
2280                 long code = strtol(val, &eptr, 0);
2281
2282                 if (eptr != val)
2283                         cc = lib80211_country_findbycc(rdp, code);
2284                 if (eptr == val || cc == NULL)
2285                         errx(1, "unknown ISO country code %s", val);
2286         }
2287         getregdomain(s);
2288         regdomain.regdomain = cc->rd->sku;
2289         regdomain.country = cc->code;
2290         regdomain.isocc[0] = cc->isoname[0];
2291         regdomain.isocc[1] = cc->isoname[1];
2292         callback_register(setregdomain_cb, &regdomain);
2293 }
2294
2295 static void
2296 set80211location(const char *val, int d, int s, const struct afswtch *rafp)
2297 {
2298         getregdomain(s);
2299         regdomain.location = d;
2300         callback_register(setregdomain_cb, &regdomain);
2301 }
2302
2303 static void
2304 set80211ecm(const char *val, int d, int s, const struct afswtch *rafp)
2305 {
2306         getregdomain(s);
2307         regdomain.ecm = d;
2308         callback_register(setregdomain_cb, &regdomain);
2309 }
2310
2311 static void
2312 LINE_INIT(char c)
2313 {
2314         spacer = c;
2315         if (c == '\t')
2316                 col = 8;
2317         else
2318                 col = 1;
2319 }
2320
2321 static void
2322 LINE_BREAK(void)
2323 {
2324         if (spacer != '\t') {
2325                 printf("\n");
2326                 spacer = '\t';
2327         }
2328         col = 8;                /* 8-col tab */
2329 }
2330
2331 static void
2332 LINE_CHECK(const char *fmt, ...)
2333 {
2334         char buf[80];
2335         va_list ap;
2336         int n;
2337
2338         va_start(ap, fmt);
2339         n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
2340         va_end(ap);
2341         col += 1+n;
2342         if (col > MAXCOL) {
2343                 LINE_BREAK();
2344                 col += n;
2345         }
2346         buf[0] = spacer;
2347         printf("%s", buf);
2348         spacer = ' ';
2349 }
2350
2351 static int
2352 getmaxrate(const uint8_t rates[15], uint8_t nrates)
2353 {
2354         int i, maxrate = -1;
2355
2356         for (i = 0; i < nrates; i++) {
2357                 int rate = rates[i] & IEEE80211_RATE_VAL;
2358                 if (rate > maxrate)
2359                         maxrate = rate;
2360         }
2361         return maxrate / 2;
2362 }
2363
2364 static const char *
2365 getcaps(int capinfo)
2366 {
2367         static char capstring[32];
2368         char *cp = capstring;
2369
2370         if (capinfo & IEEE80211_CAPINFO_ESS)
2371                 *cp++ = 'E';
2372         if (capinfo & IEEE80211_CAPINFO_IBSS)
2373                 *cp++ = 'I';
2374         if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
2375                 *cp++ = 'c';
2376         if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
2377                 *cp++ = 'C';
2378         if (capinfo & IEEE80211_CAPINFO_PRIVACY)
2379                 *cp++ = 'P';
2380         if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
2381                 *cp++ = 'S';
2382         if (capinfo & IEEE80211_CAPINFO_PBCC)
2383                 *cp++ = 'B';
2384         if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
2385                 *cp++ = 'A';
2386         if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
2387                 *cp++ = 's';
2388         if (capinfo & IEEE80211_CAPINFO_RSN)
2389                 *cp++ = 'R';
2390         if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
2391                 *cp++ = 'D';
2392         *cp = '\0';
2393         return capstring;
2394 }
2395
2396 static const char *
2397 getflags(int flags)
2398 {
2399         static char flagstring[32];
2400         char *cp = flagstring;
2401
2402         if (flags & IEEE80211_NODE_AUTH)
2403                 *cp++ = 'A';
2404         if (flags & IEEE80211_NODE_QOS)
2405                 *cp++ = 'Q';
2406         if (flags & IEEE80211_NODE_ERP)
2407                 *cp++ = 'E';
2408         if (flags & IEEE80211_NODE_PWR_MGT)
2409                 *cp++ = 'P';
2410         if (flags & IEEE80211_NODE_HT) {
2411                 *cp++ = 'H';
2412                 if (flags & IEEE80211_NODE_HTCOMPAT)
2413                         *cp++ = '+';
2414         }
2415         if (flags & IEEE80211_NODE_WPS)
2416                 *cp++ = 'W';
2417         if (flags & IEEE80211_NODE_TSN)
2418                 *cp++ = 'N';
2419         if (flags & IEEE80211_NODE_AMPDU_TX)
2420                 *cp++ = 'T';
2421         if (flags & IEEE80211_NODE_AMPDU_RX)
2422                 *cp++ = 'R';
2423         if (flags & IEEE80211_NODE_MIMO_PS) {
2424                 *cp++ = 'M';
2425                 if (flags & IEEE80211_NODE_MIMO_RTS)
2426                         *cp++ = '+';
2427         }
2428         if (flags & IEEE80211_NODE_RIFS)
2429                 *cp++ = 'I';
2430         if (flags & IEEE80211_NODE_SGI40) {
2431                 *cp++ = 'S';
2432                 if (flags & IEEE80211_NODE_SGI20)
2433                         *cp++ = '+';
2434         } else if (flags & IEEE80211_NODE_SGI20)
2435                 *cp++ = 's';
2436         if (flags & IEEE80211_NODE_AMSDU_TX)
2437                 *cp++ = 't';
2438         if (flags & IEEE80211_NODE_AMSDU_RX)
2439                 *cp++ = 'r';
2440         *cp = '\0';
2441         return flagstring;
2442 }
2443
2444 static void
2445 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
2446 {
2447         printf("%s", tag);
2448         if (verbose) {
2449                 maxlen -= strlen(tag)+2;
2450                 if (2*ielen > (size_t)maxlen)
2451                         maxlen--;
2452                 printf("<");
2453                 for (; ielen > 0; ie++, ielen--) {
2454                         if (maxlen-- <= 0)
2455                                 break;
2456                         printf("%02x", *ie);
2457                 }
2458                 if (ielen != 0)
2459                         printf("-");
2460                 printf(">");
2461         }
2462 }
2463
2464 #define LE_READ_2(p)                                    \
2465         ((u_int16_t)                                    \
2466          ((((const u_int8_t *)(p))[0]      ) |          \
2467           (((const u_int8_t *)(p))[1] <<  8)))
2468 #define LE_READ_4(p)                                    \
2469         ((u_int32_t)                                    \
2470          ((((const u_int8_t *)(p))[0]      ) |          \
2471           (((const u_int8_t *)(p))[1] <<  8) |          \
2472           (((const u_int8_t *)(p))[2] << 16) |          \
2473           (((const u_int8_t *)(p))[3] << 24)))
2474
2475 /*
2476  * NB: The decoding routines assume a properly formatted ie
2477  *     which should be safe as the kernel only retains them
2478  *     if they parse ok.
2479  */
2480
2481 static void
2482 printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2483 {
2484 #define MS(_v, _f)      (((_v) & _f) >> _f##_S)
2485         static const char *acnames[] = { "BE", "BK", "VO", "VI" };
2486         const struct ieee80211_wme_param *wme =
2487             (const struct ieee80211_wme_param *) ie;
2488         int i;
2489
2490         printf("%s", tag);
2491         if (!verbose)
2492                 return;
2493         printf("<qosinfo 0x%x", wme->param_qosInfo);
2494         ie += offsetof(struct ieee80211_wme_param, params_acParams);
2495         for (i = 0; i < WME_NUM_AC; i++) {
2496                 const struct ieee80211_wme_acparams *ac =
2497                     &wme->params_acParams[i];
2498
2499                 printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
2500                         , acnames[i]
2501                         , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
2502                         , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
2503                         , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
2504                         , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
2505                         , LE_READ_2(&ac->acp_txop)
2506                 );
2507         }
2508         printf(">");
2509 #undef MS
2510 }
2511
2512 static void
2513 printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2514 {
2515         printf("%s", tag);
2516         if (verbose) {
2517                 const struct ieee80211_wme_info *wme =
2518                     (const struct ieee80211_wme_info *) ie;
2519                 printf("<version 0x%x info 0x%x>",
2520                     wme->wme_version, wme->wme_info);
2521         }
2522 }
2523
2524 static void
2525 printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2526 {
2527         printf("%s", tag);
2528         if (verbose) {
2529                 const struct ieee80211_ie_htcap *htcap =
2530                     (const struct ieee80211_ie_htcap *) ie;
2531                 const char *sep;
2532                 int i, j;
2533
2534                 printf("<cap 0x%x param 0x%x",
2535                     LE_READ_2(&htcap->hc_cap), htcap->hc_param);
2536                 printf(" mcsset[");
2537                 sep = "";
2538                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
2539                         if (isset(htcap->hc_mcsset, i)) {
2540                                 for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
2541                                         if (isclr(htcap->hc_mcsset, j))
2542                                                 break;
2543                                 j--;
2544                                 if (i == j)
2545                                         printf("%s%u", sep, i);
2546                                 else
2547                                         printf("%s%u-%u", sep, i, j);
2548                                 i += j-i;
2549                                 sep = ",";
2550                         }
2551                 printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
2552                     LE_READ_2(&htcap->hc_extcap),
2553                     LE_READ_4(&htcap->hc_txbf),
2554                     htcap->hc_antenna);
2555         }
2556 }
2557
2558 static void
2559 printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2560 {
2561         printf("%s", tag);
2562         if (verbose) {
2563                 const struct ieee80211_ie_htinfo *htinfo =
2564                     (const struct ieee80211_ie_htinfo *) ie;
2565                 const char *sep;
2566                 int i, j;
2567
2568                 printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
2569                     htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
2570                     LE_READ_2(&htinfo->hi_byte45));
2571                 printf(" basicmcs[");
2572                 sep = "";
2573                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
2574                         if (isset(htinfo->hi_basicmcsset, i)) {
2575                                 for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
2576                                         if (isclr(htinfo->hi_basicmcsset, j))
2577                                                 break;
2578                                 j--;
2579                                 if (i == j)
2580                                         printf("%s%u", sep, i);
2581                                 else
2582                                         printf("%s%u-%u", sep, i, j);
2583                                 i += j-i;
2584                                 sep = ",";
2585                         }
2586                 printf("]>");
2587         }
2588 }
2589
2590 static void
2591 printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2592 {
2593
2594         printf("%s", tag);
2595         if (verbose) {
2596                 const struct ieee80211_ath_ie *ath =
2597                         (const struct ieee80211_ath_ie *)ie;
2598
2599                 printf("<");
2600                 if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
2601                         printf("DTURBO,");
2602                 if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
2603                         printf("COMP,");
2604                 if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
2605                         printf("FF,");
2606                 if (ath->ath_capability & ATHEROS_CAP_XR)
2607                         printf("XR,");
2608                 if (ath->ath_capability & ATHEROS_CAP_AR)
2609                         printf("AR,");
2610                 if (ath->ath_capability & ATHEROS_CAP_BURST)
2611                         printf("BURST,");
2612                 if (ath->ath_capability & ATHEROS_CAP_WME)
2613                         printf("WME,");
2614                 if (ath->ath_capability & ATHEROS_CAP_BOOST)
2615                         printf("BOOST,");
2616                 printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
2617         }
2618 }
2619
2620
2621 static void
2622 printmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen)
2623 {
2624 #define MATCHOUI(field, oui, string)                                    \
2625 do {                                                                    \
2626         if (memcmp(field, oui, 4) == 0)                                 \
2627                 printf("%s", string);                                   \
2628 } while (0)
2629
2630         printf("%s", tag);
2631         if (verbose) {
2632                 const struct ieee80211_meshconf_ie *mconf =
2633                         (const struct ieee80211_meshconf_ie *)ie;
2634                 printf("<PATH:");
2635                 if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP)
2636                         printf("HWMP");
2637                 else
2638                         printf("UNKNOWN");
2639                 printf(" LINK:");
2640                 if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME)
2641                         printf("AIRTIME");
2642                 else
2643                         printf("UNKNOWN");
2644                 printf(" CONGESTION:");
2645                 if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED)
2646                         printf("DISABLED");
2647                 else
2648                         printf("UNKNOWN");
2649                 printf(" SYNC:");
2650                 if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF)
2651                         printf("NEIGHOFF");
2652                 else
2653                         printf("UNKNOWN");
2654                 printf(" AUTH:");
2655                 if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED)
2656                         printf("DISABLED");
2657                 else
2658                         printf("UNKNOWN");
2659                 printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
2660                     mconf->conf_cap);
2661         }
2662 #undef MATCHOUI
2663 }
2664
2665 static const char *
2666 wpa_cipher(const u_int8_t *sel)
2667 {
2668 #define WPA_SEL(x)      (((x)<<24)|WPA_OUI)
2669         u_int32_t w = LE_READ_4(sel);
2670
2671         switch (w) {
2672         case WPA_SEL(WPA_CSE_NULL):
2673                 return "NONE";
2674         case WPA_SEL(WPA_CSE_WEP40):
2675                 return "WEP40";
2676         case WPA_SEL(WPA_CSE_WEP104):
2677                 return "WEP104";
2678         case WPA_SEL(WPA_CSE_TKIP):
2679                 return "TKIP";
2680         case WPA_SEL(WPA_CSE_CCMP):
2681                 return "AES-CCMP";
2682         }
2683         return "?";             /* NB: so 1<< is discarded */
2684 #undef WPA_SEL
2685 }
2686
2687 static const char *
2688 wpa_keymgmt(const u_int8_t *sel)
2689 {
2690 #define WPA_SEL(x)      (((x)<<24)|WPA_OUI)
2691         u_int32_t w = LE_READ_4(sel);
2692
2693         switch (w) {
2694         case WPA_SEL(WPA_ASE_8021X_UNSPEC):
2695                 return "8021X-UNSPEC";
2696         case WPA_SEL(WPA_ASE_8021X_PSK):
2697                 return "8021X-PSK";
2698         case WPA_SEL(WPA_ASE_NONE):
2699                 return "NONE";
2700         }
2701         return "?";
2702 #undef WPA_SEL
2703 }
2704
2705 static void
2706 printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2707 {
2708         u_int8_t len = ie[1];
2709
2710         printf("%s", tag);
2711         if (verbose) {
2712                 const char *sep;
2713                 int n;
2714
2715                 ie += 6, len -= 4;              /* NB: len is payload only */
2716
2717                 printf("<v%u", LE_READ_2(ie));
2718                 ie += 2, len -= 2;
2719
2720                 printf(" mc:%s", wpa_cipher(ie));
2721                 ie += 4, len -= 4;
2722
2723                 /* unicast ciphers */
2724                 n = LE_READ_2(ie);
2725                 ie += 2, len -= 2;
2726                 sep = " uc:";
2727                 for (; n > 0; n--) {
2728                         printf("%s%s", sep, wpa_cipher(ie));
2729                         ie += 4, len -= 4;
2730                         sep = "+";
2731                 }
2732
2733                 /* key management algorithms */
2734                 n = LE_READ_2(ie);
2735                 ie += 2, len -= 2;
2736                 sep = " km:";
2737                 for (; n > 0; n--) {
2738                         printf("%s%s", sep, wpa_keymgmt(ie));
2739                         ie += 4, len -= 4;
2740                         sep = "+";
2741                 }
2742
2743                 if (len > 2)            /* optional capabilities */
2744                         printf(", caps 0x%x", LE_READ_2(ie));
2745                 printf(">");
2746         }
2747 }
2748
2749 static const char *
2750 rsn_cipher(const u_int8_t *sel)
2751 {
2752 #define RSN_SEL(x)      (((x)<<24)|RSN_OUI)
2753         u_int32_t w = LE_READ_4(sel);
2754
2755         switch (w) {
2756         case RSN_SEL(RSN_CSE_NULL):
2757                 return "NONE";
2758         case RSN_SEL(RSN_CSE_WEP40):
2759                 return "WEP40";
2760         case RSN_SEL(RSN_CSE_WEP104):
2761                 return "WEP104";
2762         case RSN_SEL(RSN_CSE_TKIP):
2763                 return "TKIP";
2764         case RSN_SEL(RSN_CSE_CCMP):
2765                 return "AES-CCMP";
2766         case RSN_SEL(RSN_CSE_WRAP):
2767                 return "AES-OCB";
2768         }
2769         return "?";
2770 #undef WPA_SEL
2771 }
2772
2773 static const char *
2774 rsn_keymgmt(const u_int8_t *sel)
2775 {
2776 #define RSN_SEL(x)      (((x)<<24)|RSN_OUI)
2777         u_int32_t w = LE_READ_4(sel);
2778
2779         switch (w) {
2780         case RSN_SEL(RSN_ASE_8021X_UNSPEC):
2781                 return "8021X-UNSPEC";
2782         case RSN_SEL(RSN_ASE_8021X_PSK):
2783                 return "8021X-PSK";
2784         case RSN_SEL(RSN_ASE_NONE):
2785                 return "NONE";
2786         }
2787         return "?";
2788 #undef RSN_SEL
2789 }
2790
2791 static void
2792 printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2793 {
2794         printf("%s", tag);
2795         if (verbose) {
2796                 const char *sep;
2797                 int n;
2798
2799                 ie += 2, ielen -= 2;
2800
2801                 printf("<v%u", LE_READ_2(ie));
2802                 ie += 2, ielen -= 2;
2803
2804                 printf(" mc:%s", rsn_cipher(ie));
2805                 ie += 4, ielen -= 4;
2806
2807                 /* unicast ciphers */
2808                 n = LE_READ_2(ie);
2809                 ie += 2, ielen -= 2;
2810                 sep = " uc:";
2811                 for (; n > 0; n--) {
2812                         printf("%s%s", sep, rsn_cipher(ie));
2813                         ie += 4, ielen -= 4;
2814                         sep = "+";
2815                 }
2816
2817                 /* key management algorithms */
2818                 n = LE_READ_2(ie);
2819                 ie += 2, ielen -= 2;
2820                 sep = " km:";
2821                 for (; n > 0; n--) {
2822                         printf("%s%s", sep, rsn_keymgmt(ie));
2823                         ie += 4, ielen -= 4;
2824                         sep = "+";
2825                 }
2826
2827                 if (ielen > 2)          /* optional capabilities */
2828                         printf(", caps 0x%x", LE_READ_2(ie));
2829                 /* XXXPMKID */
2830                 printf(">");
2831         }
2832 }
2833
2834 /* XXX move to a public include file */
2835 #define IEEE80211_WPS_DEV_PASS_ID       0x1012
2836 #define IEEE80211_WPS_SELECTED_REG      0x1041
2837 #define IEEE80211_WPS_SETUP_STATE       0x1044
2838 #define IEEE80211_WPS_UUID_E            0x1047
2839 #define IEEE80211_WPS_VERSION           0x104a
2840
2841 #define BE_READ_2(p)                                    \
2842         ((u_int16_t)                                    \
2843          ((((const u_int8_t *)(p))[1]      ) |          \
2844           (((const u_int8_t *)(p))[0] <<  8)))
2845
2846 static void
2847 printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2848 {
2849         u_int8_t len = ie[1];
2850         size_t n;
2851         uint16_t tlv_type;
2852         uint16_t tlv_len;
2853
2854         printf("%s", tag);
2855         if (verbose) {
2856                 static const char *dev_pass_id[] = {
2857                         "D",    /* Default (PIN) */
2858                         "U",    /* User-specified */
2859                         "M",    /* Machine-specified */
2860                         "K",    /* Rekey */
2861                         "P",    /* PushButton */
2862                         "R"     /* Registrar-specified */
2863                 };
2864
2865                 ie +=6, len -= 4;               /* NB: len is payload only */
2866
2867                 /* WPS IE in Beacon and Probe Resp frames have different fields */
2868                 printf("<");
2869                 while (len) {
2870                         tlv_type = BE_READ_2(ie);
2871                         tlv_len  = BE_READ_2(ie + 2);
2872
2873                         ie += 4, len -= 4;
2874
2875                         switch (tlv_type) {
2876                         case IEEE80211_WPS_VERSION:
2877                                 printf("v:%d.%d", *ie >> 4, *ie & 0xf);
2878                                 break;
2879                         case IEEE80211_WPS_SETUP_STATE:
2880                                 /* Only 1 and 2 are valid */
2881                                 if (*ie == 0 || *ie >= 3)
2882                                         printf(" state:B");
2883                                 else
2884                                         printf(" st:%s", *ie == 1 ? "N" : "C");
2885                                 break;
2886                         case IEEE80211_WPS_SELECTED_REG:
2887                                 printf(" sel:%s", *ie ? "T" : "F");
2888                                 break;
2889                         case IEEE80211_WPS_DEV_PASS_ID:
2890                                 n = LE_READ_2(ie);
2891                                 if (n < nitems(dev_pass_id))
2892                                         printf(" dpi:%s", dev_pass_id[n]);
2893                                 break;
2894                         case IEEE80211_WPS_UUID_E:
2895                                 printf(" uuid-e:");
2896                                 for (n = 0; n < (size_t)(tlv_len - 1); n++)
2897                                         printf("%02x-", ie[n]);
2898                                 printf("%02x", ie[n]);
2899                                 break;
2900                         }
2901                         ie += tlv_len, len -= tlv_len;
2902                 }
2903                 printf(">");
2904         }
2905 }
2906
2907 static void
2908 printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2909 {
2910         printf("%s", tag);
2911         if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
2912                 const struct ieee80211_tdma_param *tdma =
2913                    (const struct ieee80211_tdma_param *) ie;
2914
2915                 /* XXX tstamp */
2916                 printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
2917                     tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
2918                     LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
2919                     tdma->tdma_inuse[0]);
2920         }
2921 }
2922
2923 /*
2924  * Copy the ssid string contents into buf, truncating to fit.  If the
2925  * ssid is entirely printable then just copy intact.  Otherwise convert
2926  * to hexadecimal.  If the result is truncated then replace the last
2927  * three characters with "...".
2928  */
2929 static int
2930 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
2931 {
2932         const u_int8_t *p;
2933         size_t maxlen;
2934         size_t i;
2935
2936         if (essid_len > bufsize)
2937                 maxlen = bufsize;
2938         else
2939                 maxlen = essid_len;
2940         /* determine printable or not */
2941         for (i = 0, p = essid; i < maxlen; i++, p++) {
2942                 if (*p < ' ' || *p > 0x7e)
2943                         break;
2944         }
2945         if (i != maxlen) {              /* not printable, print as hex */
2946                 if (bufsize < 3)
2947                         return 0;
2948                 strlcpy(buf, "0x", bufsize);
2949                 bufsize -= 2;
2950                 p = essid;
2951                 for (i = 0; i < maxlen && bufsize >= 2; i++) {
2952                         sprintf(&buf[2+2*i], "%02x", p[i]);
2953                         bufsize -= 2;
2954                 }
2955                 if (i != essid_len)
2956                         memcpy(&buf[2+2*i-3], "...", 3);
2957         } else {                        /* printable, truncate as needed */
2958                 memcpy(buf, essid, maxlen);
2959                 if (maxlen != essid_len)
2960                         memcpy(&buf[maxlen-3], "...", 3);
2961         }
2962         return maxlen;
2963 }
2964
2965 static void
2966 printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2967 {
2968         char ssid[2*IEEE80211_NWID_LEN+1];
2969
2970         printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
2971 }
2972
2973 static void
2974 printrates(const char *tag, const u_int8_t *ie, size_t ielen,
2975            __unused int maxlen)
2976 {
2977         const char *sep;
2978         size_t i;
2979
2980         printf("%s", tag);
2981         sep = "<";
2982         for (i = 2; i < ielen; i++) {
2983                 printf("%s%s%d", sep,
2984                     ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
2985                     ie[i] & IEEE80211_RATE_VAL);
2986                 sep = ",";
2987         }
2988         printf(">");
2989 }
2990
2991 static void
2992 printcountry(const char *tag, const u_int8_t *ie, size_t ielen,
2993              __unused int maxlen)
2994 {
2995         const struct ieee80211_country_ie *cie =
2996            (const struct ieee80211_country_ie *) ie;
2997         size_t i, nbands, schan, nchan;
2998
2999         printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
3000         nbands = (cie->len - 3) / sizeof(cie->band[0]);
3001         for (i = 0; i < nbands; i++) {
3002                 schan = cie->band[i].schan;
3003                 nchan = cie->band[i].nchan;
3004                 if (nchan != 1)
3005                         printf(" %zu-%zu,%u", schan, schan + nchan-1,
3006                             cie->band[i].maxtxpwr);
3007                 else
3008                         printf(" %zu,%u", schan, cie->band[i].maxtxpwr);
3009         }
3010         printf(">");
3011 }
3012
3013 /* unaligned little endian access */
3014 #define LE_READ_4(p)                                    \
3015         ((u_int32_t)                                    \
3016          ((((const u_int8_t *)(p))[0]      ) |          \
3017           (((const u_int8_t *)(p))[1] <<  8) |          \
3018           (((const u_int8_t *)(p))[2] << 16) |          \
3019           (((const u_int8_t *)(p))[3] << 24)))
3020
3021 static __inline int
3022 iswpaoui(const u_int8_t *frm)
3023 {
3024         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
3025 }
3026
3027 static __inline int
3028 iswmeinfo(const u_int8_t *frm)
3029 {
3030         return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3031                 frm[6] == WME_INFO_OUI_SUBTYPE;
3032 }
3033
3034 static __inline int
3035 iswmeparam(const u_int8_t *frm)
3036 {
3037         return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3038                 frm[6] == WME_PARAM_OUI_SUBTYPE;
3039 }
3040
3041 static __inline int
3042 isatherosoui(const u_int8_t *frm)
3043 {
3044         return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
3045 }
3046
3047 static __inline int
3048 istdmaoui(const uint8_t *frm)
3049 {
3050         return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
3051 }
3052
3053 static __inline int
3054 iswpsoui(const uint8_t *frm)
3055 {
3056         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
3057 }
3058
3059 static const char *
3060 iename(int elemid)
3061 {
3062         switch (elemid) {
3063         case IEEE80211_ELEMID_FHPARMS:  return " FHPARMS";
3064         case IEEE80211_ELEMID_CFPARMS:  return " CFPARMS";
3065         case IEEE80211_ELEMID_TIM:      return " TIM";
3066         case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
3067         case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
3068         case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR";
3069         case IEEE80211_ELEMID_PWRCAP:   return " PWRCAP";
3070         case IEEE80211_ELEMID_TPCREQ:   return " TPCREQ";
3071         case IEEE80211_ELEMID_TPCREP:   return " TPCREP";
3072         case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN";
3073         case IEEE80211_ELEMID_CSA:      return " CSA";
3074         case IEEE80211_ELEMID_MEASREQ:  return " MEASREQ";
3075         case IEEE80211_ELEMID_MEASREP:  return " MEASREP";
3076         case IEEE80211_ELEMID_QUIET:    return " QUIET";
3077         case IEEE80211_ELEMID_IBSSDFS:  return " IBSSDFS";
3078         case IEEE80211_ELEMID_TPC:      return " TPC";
3079         case IEEE80211_ELEMID_CCKM:     return " CCKM";
3080         }
3081         return " ???";
3082 }
3083
3084 static void
3085 printies(const u_int8_t *vp, int ielen, int maxcols)
3086 {
3087         while (ielen > 0) {
3088                 switch (vp[0]) {
3089                 case IEEE80211_ELEMID_SSID:
3090                         if (verbose)
3091                                 printssid(" SSID", vp, 2+vp[1], maxcols);
3092                         break;
3093                 case IEEE80211_ELEMID_RATES:
3094                 case IEEE80211_ELEMID_XRATES:
3095                         if (verbose)
3096                                 printrates(vp[0] == IEEE80211_ELEMID_RATES ?
3097                                     " RATES" : " XRATES", vp, 2+vp[1], maxcols);
3098                         break;
3099                 case IEEE80211_ELEMID_DSPARMS:
3100                         if (verbose)
3101                                 printf(" DSPARMS<%u>", vp[2]);
3102                         break;
3103                 case IEEE80211_ELEMID_COUNTRY:
3104                         if (verbose)
3105                                 printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
3106                         break;
3107                 case IEEE80211_ELEMID_ERP:
3108                         if (verbose)
3109                                 printf(" ERP<0x%x>", vp[2]);
3110                         break;
3111                 case IEEE80211_ELEMID_VENDOR:
3112                         if (iswpaoui(vp))
3113                                 printwpaie(" WPA", vp, 2+vp[1], maxcols);
3114                         else if (iswmeinfo(vp))
3115                                 printwmeinfo(" WME", vp, 2+vp[1], maxcols);
3116                         else if (iswmeparam(vp))
3117                                 printwmeparam(" WME", vp, 2+vp[1], maxcols);
3118                         else if (isatherosoui(vp))
3119                                 printathie(" ATH", vp, 2+vp[1], maxcols);
3120                         else if (iswpsoui(vp))
3121                                 printwpsie(" WPS", vp, 2+vp[1], maxcols);
3122                         else if (istdmaoui(vp))
3123                                 printtdmaie(" TDMA", vp, 2+vp[1], maxcols);
3124                         else if (verbose)
3125                                 printie(" VEN", vp, 2+vp[1], maxcols);
3126                         break;
3127                 case IEEE80211_ELEMID_RSN:
3128                         printrsnie(" RSN", vp, 2+vp[1], maxcols);
3129                         break;
3130                 case IEEE80211_ELEMID_HTCAP:
3131                         printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
3132                         break;
3133                 case IEEE80211_ELEMID_HTINFO:
3134                         if (verbose)
3135                                 printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
3136                         break;
3137                 case IEEE80211_ELEMID_MESHID:
3138                         if (verbose)
3139                                 printssid(" MESHID", vp, 2+vp[1], maxcols);
3140                         break;
3141                 case IEEE80211_ELEMID_MESHCONF:
3142                         printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols);
3143                         break;
3144                 default:
3145                         if (verbose)
3146                                 printie(iename(vp[0]), vp, 2+vp[1], maxcols);
3147                         break;
3148                 }
3149                 ielen -= 2+vp[1];
3150                 vp += 2+vp[1];
3151         }
3152 }
3153
3154 static void
3155 printmimo(const struct ieee80211_mimo_info *mi)
3156 {
3157         /* NB: don't muddy display unless there's something to show */
3158         if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) {
3159                 /* XXX ignore EVM for now */
3160                 printf(" (rssi %d:%d:%d nf %d:%d:%d)",
3161                     mi->rssi[0], mi->rssi[1], mi->rssi[2],
3162                     mi->noise[0], mi->noise[1], mi->noise[2]);
3163         }
3164 }
3165
3166 static void
3167 list_scan(int s, int long_ssids)
3168 {
3169         uint8_t buf[24*1024];
3170         char ssid[IEEE80211_NWID_LEN+1];
3171         const uint8_t *cp;
3172         size_t len, ssidmax, idlen;
3173
3174         if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
3175                 errx(1, "unable to get scan results");
3176         if (len < sizeof(struct ieee80211req_scan_result))
3177                 return;
3178
3179         getchaninfo(s);
3180
3181         ssidmax = (verbose || long_ssids) ? IEEE80211_NWID_LEN - 1 : 14;
3182         printf("%-*.*s  %-17.17s  %4s %4s  %-7s  %3s %4s\n"
3183                 , (int)ssidmax, (int)ssidmax, "SSID/MESH ID"
3184                 , "BSSID"
3185                 , "CHAN"
3186                 , "RATE"
3187                 , " S:N"
3188                 , "INT"
3189                 , "CAPS"
3190         );
3191         cp = buf;
3192         do {
3193                 const struct ieee80211req_scan_result *sr;
3194                 const uint8_t *vp, *idp;
3195
3196                 sr = (const struct ieee80211req_scan_result *) cp;
3197                 vp = cp + sr->isr_ie_off;
3198                 if (sr->isr_meshid_len) {
3199                         idp = vp + sr->isr_ssid_len;
3200                         idlen = sr->isr_meshid_len;
3201                 } else {
3202                         idp = vp;
3203                         idlen = sr->isr_ssid_len;
3204                 }
3205                 printf("%-*.*s  %s  %3d  %3dM %3d:%-3d  %3d %-4.4s"
3206                         , (int)ssidmax
3207                         , copy_essid(ssid, ssidmax, idp, idlen)
3208                         , ssid
3209                         , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
3210                         , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
3211                         , getmaxrate(sr->isr_rates, sr->isr_nrates)
3212                         , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
3213                         , sr->isr_intval
3214                         , getcaps(sr->isr_capinfo)
3215                 );
3216                 printies(vp + sr->isr_ssid_len + sr->isr_meshid_len,
3217                     sr->isr_ie_len, 24);
3218                 printf("\n");
3219                 cp += sr->isr_len, len -= sr->isr_len;
3220         } while (len >= sizeof(struct ieee80211req_scan_result));
3221 }
3222
3223 static void
3224 scan_and_wait(int s)
3225 {
3226         struct ieee80211_scan_req sr;
3227         struct ieee80211req ireq;
3228         int sroute;
3229
3230         sroute = socket(PF_ROUTE, SOCK_RAW, 0);
3231         if (sroute < 0) {
3232                 perror("socket(PF_ROUTE,SOCK_RAW)");
3233                 return;
3234         }
3235         memset(&ireq, 0, sizeof(ireq));
3236         strlcpy(ireq.i_name, name, sizeof(ireq.i_name));
3237         ireq.i_type = IEEE80211_IOC_SCAN_REQ;
3238
3239         memset(&sr, 0, sizeof(sr));
3240         sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
3241                     | IEEE80211_IOC_SCAN_NOPICK
3242                     | IEEE80211_IOC_SCAN_ONCE;
3243         sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
3244         sr.sr_nssid = 0;
3245
3246         ireq.i_data = &sr;
3247         ireq.i_len = sizeof(sr);
3248         /* NB: only root can trigger a scan so ignore errors */
3249         if (ioctl(s, SIOCS80211, &ireq) >= 0) {
3250                 char buf[2048];
3251                 struct if_announcemsghdr *ifan;
3252                 struct rt_msghdr *rtm;
3253
3254                 do {
3255                         if (read(sroute, buf, sizeof(buf)) < 0) {
3256                                 perror("read(PF_ROUTE)");
3257                                 break;
3258                         }
3259                         rtm = (struct rt_msghdr *) buf;
3260                         if (rtm->rtm_version != RTM_VERSION)
3261                                 break;
3262                         ifan = (struct if_announcemsghdr *) rtm;
3263                 } while (rtm->rtm_type != RTM_IEEE80211 ||
3264                     ifan->ifan_what != RTM_IEEE80211_SCAN);
3265         }
3266         close(sroute);
3267 }
3268
3269 static
3270 DECL_CMD_FUNC(set80211scan, val, d)
3271 {
3272         scan_and_wait(s);
3273         list_scan(s, 0);
3274 }
3275
3276 static enum ieee80211_opmode get80211opmode(int s);
3277
3278 static int
3279 gettxseq(const struct ieee80211req_sta_info *si)
3280 {
3281         int i, txseq;
3282
3283         if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
3284                 return si->isi_txseqs[0];
3285         /* XXX not right but usually what folks want */
3286         txseq = 0;
3287         for (i = 0; i < IEEE80211_TID_SIZE; i++)
3288                 if (si->isi_txseqs[i] > txseq)
3289                         txseq = si->isi_txseqs[i];
3290         return txseq;
3291 }
3292
3293 static int
3294 getrxseq(const struct ieee80211req_sta_info *si)
3295 {
3296         int i, rxseq;
3297
3298         if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
3299                 return si->isi_rxseqs[0];
3300         /* XXX not right but usually what folks want */
3301         rxseq = 0;
3302         for (i = 0; i < IEEE80211_TID_SIZE; i++)
3303                 if (si->isi_rxseqs[i] > rxseq)
3304                         rxseq = si->isi_rxseqs[i];
3305         return rxseq;
3306 }
3307
3308 static void
3309 list_stations(int s)
3310 {
3311         union {
3312                 struct ieee80211req_sta_req req;
3313                 uint8_t buf[24*1024];
3314         } u;
3315         enum ieee80211_opmode opmode = get80211opmode(s);
3316         const uint8_t *cp;
3317         size_t len;
3318
3319         /* broadcast address =>'s get all stations */
3320         memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
3321         if (opmode == IEEE80211_M_STA) {
3322                 /*
3323                  * Get information about the associated AP.
3324                  */
3325                 get80211(s, IEEE80211_IOC_BSSID,
3326                          u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
3327         }
3328         if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
3329                 errx(1, "unable to get station information");
3330         if (len < sizeof(struct ieee80211req_sta_info))
3331                 return;
3332
3333         getchaninfo(s);
3334
3335         if (opmode == IEEE80211_M_MBSS) {
3336                 printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
3337                         , "ADDR"
3338                         , "CHAN"
3339                         , "LOCAL"
3340                         , "PEER"
3341                         , "STATE"
3342                         , "RATE"
3343                         , "RSSI"
3344                         , "IDLE"
3345                         , "TXSEQ"
3346                         , "RXSEQ"
3347                 );
3348         } else {
3349                 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
3350                         , "ADDR"
3351                         , "AID"
3352                         , "CHAN"
3353                         , "RATE"
3354                         , "RSSI"
3355                         , "IDLE"
3356                         , "TXSEQ"
3357                         , "RXSEQ"
3358                         , "CAPS"
3359                         , "FLAG"
3360                 );
3361         }
3362         cp = (const uint8_t *) u.req.info;
3363         do {
3364                 const struct ieee80211req_sta_info *si;
3365
3366                 si = (const struct ieee80211req_sta_info *) cp;
3367                 if (si->isi_len < sizeof(*si))
3368                         break;
3369                 if (opmode == IEEE80211_M_MBSS) {
3370                         printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
3371                                 , ether_ntoa((const struct ether_addr*)
3372                                     si->isi_macaddr)
3373                                 , ieee80211_mhz2ieee(si->isi_freq,
3374                                     si->isi_flags)
3375                                 , si->isi_localid
3376                                 , si->isi_peerid
3377                                 , mesh_linkstate_string(si->isi_peerstate)
3378                                 , si->isi_txmbps/2
3379                                 , si->isi_rssi/2.
3380                                 , si->isi_inact
3381                                 , gettxseq(si)
3382                                 , getrxseq(si)
3383                         );
3384                 } else {
3385                         printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
3386                                 , ether_ntoa((const struct ether_addr*)
3387                                     si->isi_macaddr)
3388                                 , IEEE80211_AID(si->isi_associd)
3389                                 , ieee80211_mhz2ieee(si->isi_freq,
3390                                     si->isi_flags)
3391                                 , si->isi_txmbps/2
3392                                 , si->isi_rssi/2.
3393                                 , si->isi_inact
3394                                 , gettxseq(si)
3395                                 , getrxseq(si)
3396                                 , getcaps(si->isi_capinfo)
3397                                 , getflags(si->isi_state)
3398                         );
3399                 }
3400                 printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
3401                 printmimo(&si->isi_mimo);
3402                 printf("\n");
3403                 cp += si->isi_len, len -= si->isi_len;
3404         } while (len >= sizeof(struct ieee80211req_sta_info));
3405 }
3406
3407 static const char *
3408 mesh_linkstate_string(uint8_t state)
3409 {
3410         static const char *state_names[] = {
3411             [0] = "IDLE",
3412             [1] = "OPEN-TX",
3413             [2] = "OPEN-RX",
3414             [3] = "CONF-RX",
3415             [4] = "ESTAB",
3416             [5] = "HOLDING",
3417         };
3418
3419         if (state >= nitems(state_names)) {
3420                 static char buf[10];
3421                 snprintf(buf, sizeof(buf), "#%u", state);
3422                 return buf;
3423         } else {
3424                 return state_names[state];
3425         }
3426 }
3427
3428 static const char *
3429 get_chaninfo(const struct ieee80211_channel *c, int precise,
3430         char buf[], size_t bsize)
3431 {
3432         buf[0] = '\0';
3433         if (IEEE80211_IS_CHAN_FHSS(c))
3434                 strlcat(buf, " FHSS", bsize);
3435         if (IEEE80211_IS_CHAN_A(c))
3436                 strlcat(buf, " 11a", bsize);
3437         else if (IEEE80211_IS_CHAN_ANYG(c))
3438                 strlcat(buf, " 11g", bsize);
3439         else if (IEEE80211_IS_CHAN_B(c))
3440                 strlcat(buf, " 11b", bsize);
3441         if (IEEE80211_IS_CHAN_HALF(c))
3442                 strlcat(buf, "/10MHz", bsize);
3443         if (IEEE80211_IS_CHAN_QUARTER(c))
3444                 strlcat(buf, "/5MHz", bsize);
3445         if (IEEE80211_IS_CHAN_TURBO(c))
3446                 strlcat(buf, " Turbo", bsize);
3447         if (precise) {
3448                 if (IEEE80211_IS_CHAN_HT20(c))
3449                         strlcat(buf, " ht/20", bsize);
3450                 else if (IEEE80211_IS_CHAN_HT40D(c))
3451                         strlcat(buf, " ht/40-", bsize);
3452                 else if (IEEE80211_IS_CHAN_HT40U(c))
3453                         strlcat(buf, " ht/40+", bsize);
3454         } else {
3455                 if (IEEE80211_IS_CHAN_HT(c))
3456                         strlcat(buf, " ht", bsize);
3457         }
3458         return buf;
3459 }
3460
3461 static void
3462 print_chaninfo(const struct ieee80211_channel *c, int verb)
3463 {
3464         char buf[14];
3465
3466         printf("Channel %3u : %u%c MHz%-14.14s",
3467                 ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
3468                 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
3469                 get_chaninfo(c, verb, buf, sizeof(buf)));
3470 }
3471
3472 static int
3473 chanpref(const struct ieee80211_channel *c)
3474 {
3475         if (IEEE80211_IS_CHAN_HT40(c))
3476                 return 40;
3477         if (IEEE80211_IS_CHAN_HT20(c))
3478                 return 30;
3479         if (IEEE80211_IS_CHAN_HALF(c))
3480                 return 10;
3481         if (IEEE80211_IS_CHAN_QUARTER(c))
3482                 return 5;
3483         if (IEEE80211_IS_CHAN_TURBO(c))
3484                 return 25;
3485         if (IEEE80211_IS_CHAN_A(c))
3486                 return 20;
3487         if (IEEE80211_IS_CHAN_G(c))
3488                 return 20;
3489         if (IEEE80211_IS_CHAN_B(c))
3490                 return 15;
3491         if (IEEE80211_IS_CHAN_PUREG(c))
3492                 return 15;
3493         return 0;
3494 }
3495
3496 static void
3497 print_channels(int s, const struct ieee80211req_chaninfo *chans,
3498         int allchans, int verb)
3499 {
3500         struct ieee80211req_chaninfo *achans;
3501         uint8_t reported[IEEE80211_CHAN_BYTES];
3502         const struct ieee80211_channel *c;
3503         size_t i, half;
3504
3505         achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
3506         if (achans == NULL)
3507                 errx(1, "no space for active channel list");
3508         achans->ic_nchans = 0;
3509         memset(reported, 0, sizeof(reported));
3510         if (!allchans) {
3511                 struct ieee80211req_chanlist active;
3512
3513                 if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
3514                         errx(1, "unable to get active channel list");
3515                 for (i = 0; i < chans->ic_nchans; i++) {
3516                         c = &chans->ic_chans[i];
3517                         if (!isset(active.ic_channels, c->ic_ieee))
3518                                 continue;
3519                         /*
3520                          * Suppress compatible duplicates unless
3521                          * verbose.  The kernel gives us it's
3522                          * complete channel list which has separate
3523                          * entries for 11g/11b and 11a/turbo.
3524                          */
3525                         if (isset(reported, c->ic_ieee) && !verb) {
3526                                 /* XXX we assume duplicates are adjacent */
3527                                 achans->ic_chans[achans->ic_nchans-1] = *c;
3528                         } else {
3529                                 achans->ic_chans[achans->ic_nchans++] = *c;
3530                                 setbit(reported, c->ic_ieee);
3531                         }
3532                 }
3533         } else {
3534                 for (i = 0; i < chans->ic_nchans; i++) {
3535                         c = &chans->ic_chans[i];
3536                         /* suppress duplicates as above */
3537                         if (isset(reported, c->ic_ieee) && !verb) {
3538                                 /* XXX we assume duplicates are adjacent */
3539                                 struct ieee80211_channel *a =
3540                                     &achans->ic_chans[achans->ic_nchans-1];
3541                                 if (chanpref(c) > chanpref(a))
3542                                         *a = *c;
3543                         } else {
3544                                 achans->ic_chans[achans->ic_nchans++] = *c;
3545                                 setbit(reported, c->ic_ieee);
3546                         }
3547                 }
3548         }
3549         half = achans->ic_nchans / 2;
3550         if (achans->ic_nchans % 2)
3551                 half++;
3552
3553         for (i = 0; i < achans->ic_nchans / 2; i++) {
3554                 print_chaninfo(&achans->ic_chans[i], verb);
3555                 print_chaninfo(&achans->ic_chans[half+i], verb);
3556                 printf("\n");
3557         }
3558         if (achans->ic_nchans % 2) {
3559                 print_chaninfo(&achans->ic_chans[i], verb);
3560                 printf("\n");
3561         }
3562         free(achans);
3563 }
3564
3565 static void
3566 list_channels(int s, int allchans)
3567 {
3568         getchaninfo(s);
3569         print_channels(s, chaninfo, allchans, verbose);
3570 }
3571
3572 static void
3573 print_txpow(const struct ieee80211_channel *c)
3574 {
3575         printf("Channel %3u : %u MHz %3.1f reg %2d  ",
3576             c->ic_ieee, c->ic_freq,
3577             c->ic_maxpower/2., c->ic_maxregpower);
3578 }
3579
3580 static void
3581 print_txpow_verbose(const struct ieee80211_channel *c)
3582 {
3583         print_chaninfo(c, 1);
3584         printf("min %4.1f dBm  max %3.1f dBm  reg %2d dBm",
3585             c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
3586         /* indicate where regulatory cap limits power use */
3587         if (c->ic_maxpower > 2*c->ic_maxregpower)
3588                 printf(" <");
3589 }
3590
3591 static void
3592 list_txpow(int s)
3593 {
3594         struct ieee80211req_chaninfo *achans;
3595         uint8_t reported[IEEE80211_CHAN_BYTES];
3596         struct ieee80211_channel *c, *prev;
3597         size_t i, half;
3598
3599         getchaninfo(s);
3600         achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
3601         if (achans == NULL)
3602                 errx(1, "no space for active channel list");
3603         achans->ic_nchans = 0;
3604         memset(reported, 0, sizeof(reported));
3605         for (i = 0; i < chaninfo->ic_nchans; i++) {
3606                 c = &chaninfo->ic_chans[i];
3607                 /* suppress duplicates as above */
3608                 if (isset(reported, c->ic_ieee) && !verbose) {
3609                         /* XXX we assume duplicates are adjacent */
3610                         prev = &achans->ic_chans[achans->ic_nchans-1];
3611                         /* display highest power on channel */
3612                         if (c->ic_maxpower > prev->ic_maxpower)
3613                                 *prev = *c;
3614                 } else {
3615                         achans->ic_chans[achans->ic_nchans++] = *c;
3616                         setbit(reported, c->ic_ieee);
3617                 }
3618         }
3619         if (!verbose) {
3620                 half = achans->ic_nchans / 2;
3621                 if (achans->ic_nchans % 2)
3622                         half++;
3623
3624                 for (i = 0; i < achans->ic_nchans / 2; i++) {
3625                         print_txpow(&achans->ic_chans[i]);
3626                         print_txpow(&achans->ic_chans[half+i]);
3627                         printf("\n");
3628                 }
3629                 if (achans->ic_nchans % 2) {
3630                         print_txpow(&achans->ic_chans[i]);
3631                         printf("\n");
3632                 }
3633         } else {
3634                 for (i = 0; i < achans->ic_nchans; i++) {
3635                         print_txpow_verbose(&achans->ic_chans[i]);
3636                         printf("\n");
3637                 }
3638         }
3639         free(achans);
3640 }
3641
3642 static void
3643 list_keys(int s)
3644 {
3645 }
3646
3647 #define IEEE80211_C_BITS \
3648         "\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
3649         "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
3650         "\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
3651         "\37TXFRAG\40TDMA"
3652
3653 static void
3654 list_capabilities(int s)
3655 {
3656         struct ieee80211_devcaps_req *dc;
3657
3658         if (verbose)
3659                 dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
3660         else
3661                 dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
3662         if (dc == NULL)
3663                 errx(1, "no space for device capabilities");
3664         dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
3665         getdevcaps(s, dc);
3666         printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
3667         if (dc->dc_cryptocaps != 0 || verbose) {
3668                 putchar('\n');
3669                 printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
3670         }
3671         if (dc->dc_htcaps != 0 || verbose) {
3672                 putchar('\n');
3673                 printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
3674         }
3675         putchar('\n');
3676         if (verbose) {
3677                 chaninfo = &dc->dc_chaninfo;    /* XXX */
3678                 print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose);
3679         }
3680         free(dc);
3681 }
3682
3683 static int
3684 get80211wme(int s, int param, int ac, int *val)
3685 {
3686         struct ieee80211req ireq;
3687
3688         memset(&ireq, 0, sizeof(ireq));
3689         strlcpy(ireq.i_name, name, sizeof(ireq.i_name));
3690         ireq.i_type = param;
3691         ireq.i_len = ac;
3692         if (ioctl(s, SIOCG80211, &ireq) < 0) {
3693                 warn("cannot get WME parameter %d, ac %d%s",
3694                     param, ac & IEEE80211_WMEPARAM_VAL,
3695                     ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
3696                 return -1;
3697         }
3698         *val = ireq.i_val;
3699         return 0;
3700 }
3701
3702 static void
3703 list_wme_aci(int s, const char *tag, int ac)
3704 {
3705         int val;
3706
3707         printf("\t%s", tag);
3708
3709         /* show WME BSS parameters */
3710         if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
3711                 printf(" cwmin %2u", val);
3712         if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
3713                 printf(" cwmax %2u", val);
3714         if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
3715                 printf(" aifs %2u", val);
3716         if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
3717                 printf(" txopLimit %3u", val);
3718         if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
3719                 if (val)
3720                         printf(" acm");
3721                 else if (verbose)
3722                         printf(" -acm");
3723         }
3724         /* !BSS only */
3725         if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
3726                 if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
3727                         if (!val)
3728                                 printf(" -ack");
3729                         else if (verbose)
3730                                 printf(" ack");
3731                 }
3732         }
3733         printf("\n");
3734 }
3735
3736 static void
3737 list_wme(int s)
3738 {
3739         static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
3740         int ac;
3741
3742         if (verbose) {
3743                 /* display both BSS and local settings */
3744                 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
3745         again:
3746                         if (ac & IEEE80211_WMEPARAM_BSS)
3747                                 list_wme_aci(s, "     ", ac);
3748                         else
3749                                 list_wme_aci(s, acnames[ac], ac);
3750                         if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
3751                                 ac |= IEEE80211_WMEPARAM_BSS;
3752                                 goto again;
3753                         } else
3754                                 ac &= ~IEEE80211_WMEPARAM_BSS;
3755                 }
3756         } else {
3757                 /* display only channel settings */
3758                 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++)
3759                         list_wme_aci(s, acnames[ac], ac);
3760         }
3761 }
3762
3763 static void
3764 list_roam(int s)
3765 {
3766         const struct ieee80211_roamparam *rp;
3767         int mode;
3768
3769         getroam(s);
3770         for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
3771                 rp = &roamparams.params[mode];
3772                 if (rp->rssi == 0 && rp->rate == 0)
3773                         continue;
3774                 if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
3775                         if (rp->rssi & 1)
3776                                 LINE_CHECK("roam:%-7.7s rssi %2u.5dBm  MCS %2u    ",
3777                                     modename[mode], rp->rssi/2,
3778                                     rp->rate &~ IEEE80211_RATE_MCS);
3779                         else
3780                                 LINE_CHECK("roam:%-7.7s rssi %4udBm  MCS %2u    ",
3781                                     modename[mode], rp->rssi/2,
3782                                     rp->rate &~ IEEE80211_RATE_MCS);
3783                 } else {
3784                         if (rp->rssi & 1)
3785                                 LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s",
3786                                     modename[mode], rp->rssi/2, rp->rate/2);
3787                         else
3788                                 LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s",
3789                                     modename[mode], rp->rssi/2, rp->rate/2);
3790                 }
3791         }
3792 }
3793
3794 static void
3795 list_txparams(int s)
3796 {
3797         const struct ieee80211_txparam *tp;
3798         int mode;
3799
3800         gettxparams(s);
3801         for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
3802                 tp = &txparams.params[mode];
3803                 if (tp->mgmtrate == 0 && tp->mcastrate == 0)
3804                         continue;
3805                 if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
3806                         if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
3807                                 LINE_CHECK("%-7.7s ucast NONE    mgmt %2u MCS  "
3808                                     "mcast %2u MCS  maxretry %u",
3809                                     modename[mode],
3810                                     tp->mgmtrate &~ IEEE80211_RATE_MCS,
3811                                     tp->mcastrate &~ IEEE80211_RATE_MCS,
3812                                     tp->maxretry);
3813                         else
3814                                 LINE_CHECK("%-7.7s ucast %2u MCS  mgmt %2u MCS  "
3815                                     "mcast %2u MCS  maxretry %u",
3816                                     modename[mode],
3817                                     tp->ucastrate &~ IEEE80211_RATE_MCS,
3818                                     tp->mgmtrate &~ IEEE80211_RATE_MCS,
3819                                     tp->mcastrate &~ IEEE80211_RATE_MCS,
3820                                     tp->maxretry);
3821                 } else {
3822                         if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
3823                                 LINE_CHECK("%-7.7s ucast NONE    mgmt %2u Mb/s "
3824                                     "mcast %2u Mb/s maxretry %u",
3825                                     modename[mode],
3826                                     tp->mgmtrate/2,
3827                                     tp->mcastrate/2, tp->maxretry);
3828                         else
3829                                 LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s "
3830                                     "mcast %2u Mb/s maxretry %u",
3831                                     modename[mode],
3832                                     tp->ucastrate/2, tp->mgmtrate/2,
3833                                     tp->mcastrate/2, tp->maxretry);
3834                 }
3835         }
3836 }
3837
3838 static void
3839 printpolicy(int policy)
3840 {
3841         switch (policy) {
3842         case IEEE80211_MACCMD_POLICY_OPEN:
3843                 printf("policy: open\n");
3844                 break;
3845         case IEEE80211_MACCMD_POLICY_ALLOW:
3846                 printf("policy: allow\n");
3847                 break;
3848         case IEEE80211_MACCMD_POLICY_DENY:
3849                 printf("policy: deny\n");
3850                 break;
3851         case IEEE80211_MACCMD_POLICY_RADIUS:
3852                 printf("policy: radius\n");
3853                 break;
3854         default:
3855                 printf("policy: unknown (%u)\n", policy);
3856                 break;
3857         }
3858 }
3859
3860 static void
3861 list_mac(int s)
3862 {
3863         struct ieee80211req ireq;
3864         struct ieee80211req_maclist *acllist;
3865         int i, nacls, policy, len;
3866         uint8_t *data;
3867         char c;
3868
3869         memset(&ireq, 0, sizeof(ireq));
3870         strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
3871         ireq.i_type = IEEE80211_IOC_MACCMD;
3872         ireq.i_val = IEEE80211_MACCMD_POLICY;
3873         if (ioctl(s, SIOCG80211, &ireq) < 0) {
3874                 if (errno == EINVAL) {
3875                         printf("No acl policy loaded\n");
3876                         return;
3877 &