1b917600551e3ec218d229c292ee8e7ec8ee49a9
[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 _APPLY(_flags, _base, _param, _v) do {                          \
1442     if (_flags & IEEE80211_CHAN_HT) {                                   \
1443             if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1444                     _base.params[IEEE80211_MODE_11NA]._param = _v;      \
1445                     _base.params[IEEE80211_MODE_11NG]._param = _v;      \
1446             } else if (_flags & IEEE80211_CHAN_5GHZ)                    \
1447                     _base.params[IEEE80211_MODE_11NA]._param = _v;      \
1448             else                                                        \
1449                     _base.params[IEEE80211_MODE_11NG]._param = _v;      \
1450     }                                                                   \
1451     if (_flags & IEEE80211_CHAN_TURBO) {                                \
1452             if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1453                     _base.params[IEEE80211_MODE_TURBO_A]._param = _v;   \
1454                     _base.params[IEEE80211_MODE_TURBO_G]._param = _v;   \
1455             } else if (_flags & IEEE80211_CHAN_5GHZ)                    \
1456                     _base.params[IEEE80211_MODE_TURBO_A]._param = _v;   \
1457             else                                                        \
1458                     _base.params[IEEE80211_MODE_TURBO_G]._param = _v;   \
1459     }                                                                   \
1460     if (_flags & IEEE80211_CHAN_STURBO)                                 \
1461             _base.params[IEEE80211_MODE_STURBO_A]._param = _v;          \
1462     if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)                \
1463             _base.params[IEEE80211_MODE_11A]._param = _v;               \
1464     if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)                \
1465             _base.params[IEEE80211_MODE_11G]._param = _v;               \
1466     if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)                \
1467             _base.params[IEEE80211_MODE_11B]._param = _v;               \
1468     if (_flags & IEEE80211_CHAN_HALF)                                   \
1469             _base.params[IEEE80211_MODE_HALF]._param = _v;              \
1470     if (_flags & IEEE80211_CHAN_QUARTER)                                \
1471             _base.params[IEEE80211_MODE_QUARTER]._param = _v;           \
1472 } while (0)
1473 #define _APPLY1(_flags, _base, _param, _v) do {                         \
1474     if (_flags & IEEE80211_CHAN_HT) {                                   \
1475             if (_flags & IEEE80211_CHAN_5GHZ)                           \
1476                     _base.params[IEEE80211_MODE_11NA]._param = _v;      \
1477             else                                                        \
1478                     _base.params[IEEE80211_MODE_11NG]._param = _v;      \
1479     } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)   \
1480             _base.params[IEEE80211_MODE_TURBO_A]._param = _v;           \
1481     else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)     \
1482             _base.params[IEEE80211_MODE_TURBO_G]._param = _v;           \
1483     else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)         \
1484             _base.params[IEEE80211_MODE_STURBO_A]._param = _v;          \
1485     else if (_flags & IEEE80211_CHAN_HALF)                              \
1486             _base.params[IEEE80211_MODE_HALF]._param = _v;              \
1487     else if (_flags & IEEE80211_CHAN_QUARTER)                           \
1488             _base.params[IEEE80211_MODE_QUARTER]._param = _v;           \
1489     else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)           \
1490             _base.params[IEEE80211_MODE_11A]._param = _v;               \
1491     else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)           \
1492             _base.params[IEEE80211_MODE_11G]._param = _v;               \
1493     else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)           \
1494             _base.params[IEEE80211_MODE_11B]._param = _v;               \
1495 } while (0)
1496 #define _APPLY_RATE(_flags, _base, _param, _v) do {                     \
1497     if (_flags & IEEE80211_CHAN_HT) {                                   \
1498         (_v) = (_v / 2) | IEEE80211_RATE_MCS;                           \
1499     }                                                                   \
1500     _APPLY(_flags, _base, _param, _v);                                  \
1501 } while (0)
1502 #define _APPLY_RATE1(_flags, _base, _param, _v) do {                    \
1503     if (_flags & IEEE80211_CHAN_HT) {                                   \
1504         (_v) = (_v / 2) | IEEE80211_RATE_MCS;                           \
1505     }                                                                   \
1506     _APPLY1(_flags, _base, _param, _v);                                 \
1507 } while (0)
1508
1509 static
1510 DECL_CMD_FUNC(set80211roamrssi, val, d)
1511 {
1512         double v = atof(val);
1513         int rssi, flags;
1514
1515         rssi = (int) (2*v);
1516         if (rssi != 2*v)
1517                 errx(-1, "invalid rssi (must be .5 dBm units)");
1518         flags = getmodeflags(val);
1519         getroam(s);
1520         if (flags == 0) {               /* NB: no flags => current channel */
1521                 flags = getcurchan(s)->ic_flags;
1522                 _APPLY1(flags, roamparams, rssi, rssi);
1523         } else
1524                 _APPLY(flags, roamparams, rssi, rssi);
1525         callback_register(setroam_cb, &roamparams);
1526 }
1527
1528 static int
1529 getrate(const char *val, const char *tag)
1530 {
1531         double v = atof(val);
1532         int rate;
1533
1534         rate = (int) (2*v);
1535         if (rate != 2*v)
1536                 errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag);
1537         return rate;            /* NB: returns 2x the specified value */
1538 }
1539
1540 static
1541 DECL_CMD_FUNC(set80211roamrate, val, d)
1542 {
1543         int rate, flags;
1544
1545         rate = getrate(val, "roam");
1546         flags = getmodeflags(val);
1547         getroam(s);
1548         if (flags == 0) {               /* NB: no flags => current channel */
1549                 flags = getcurchan(s)->ic_flags;
1550                 _APPLY_RATE1(flags, roamparams, rate, rate);
1551         } else
1552                 _APPLY_RATE(flags, roamparams, rate, rate);
1553         callback_register(setroam_cb, &roamparams);
1554 }
1555
1556 static
1557 DECL_CMD_FUNC(set80211mcastrate, val, d)
1558 {
1559         int rate, flags;
1560
1561         rate = getrate(val, "mcast");
1562         flags = getmodeflags(val);
1563         gettxparams(s);
1564         if (flags == 0) {               /* NB: no flags => current channel */
1565                 flags = getcurchan(s)->ic_flags;
1566                 _APPLY_RATE1(flags, txparams, mcastrate, rate);
1567         } else
1568                 _APPLY_RATE(flags, txparams, mcastrate, rate);
1569         callback_register(settxparams_cb, &txparams);
1570 }
1571
1572 static
1573 DECL_CMD_FUNC(set80211mgtrate, val, d)
1574 {
1575         int rate, flags;
1576
1577         rate = getrate(val, "mgmt");
1578         flags = getmodeflags(val);
1579         gettxparams(s);
1580         if (flags == 0) {               /* NB: no flags => current channel */
1581                 flags = getcurchan(s)->ic_flags;
1582                 _APPLY_RATE1(flags, txparams, mgmtrate, rate);
1583         } else
1584                 _APPLY_RATE(flags, txparams, mgmtrate, rate);
1585         callback_register(settxparams_cb, &txparams);
1586 }
1587
1588 static
1589 DECL_CMD_FUNC(set80211ucastrate, val, d)
1590 {
1591         int flags;
1592
1593         gettxparams(s);
1594         flags = getmodeflags(val);
1595         if (isanyarg(val)) {
1596                 if (flags == 0) {       /* NB: no flags => current channel */
1597                         flags = getcurchan(s)->ic_flags;
1598                         _APPLY1(flags, txparams, ucastrate,
1599                             IEEE80211_FIXED_RATE_NONE);
1600                 } else
1601                         _APPLY(flags, txparams, ucastrate,
1602                             IEEE80211_FIXED_RATE_NONE);
1603         } else {
1604                 int rate = getrate(val, "ucast");
1605                 if (flags == 0) {       /* NB: no flags => current channel */
1606                         flags = getcurchan(s)->ic_flags;
1607                         _APPLY_RATE1(flags, txparams, ucastrate, rate);
1608                 } else
1609                         _APPLY_RATE(flags, txparams, ucastrate, rate);
1610         }
1611         callback_register(settxparams_cb, &txparams);
1612 }
1613
1614 static
1615 DECL_CMD_FUNC(set80211maxretry, val, d)
1616 {
1617         int v = atoi(val), flags;
1618
1619         flags = getmodeflags(val);
1620         gettxparams(s);
1621         if (flags == 0) {               /* NB: no flags => current channel */
1622                 flags = getcurchan(s)->ic_flags;
1623                 _APPLY1(flags, txparams, maxretry, v);
1624         } else
1625                 _APPLY(flags, txparams, maxretry, v);
1626         callback_register(settxparams_cb, &txparams);
1627 }
1628 #undef _APPLY_RATE
1629 #undef _APPLY
1630
1631 static
1632 DECL_CMD_FUNC(set80211fragthreshold, val, d)
1633 {
1634         set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
1635                 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
1636 }
1637
1638 static
1639 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
1640 {
1641         set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
1642                 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
1643 }
1644
1645 static void
1646 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
1647 {
1648         set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
1649 }
1650
1651 static void
1652 set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
1653 {
1654         set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
1655 }
1656
1657 static void
1658 set80211dfs(const char *val, int d, int s, const struct afswtch *rafp)
1659 {
1660         set80211(s, IEEE80211_IOC_DFS, d, 0, NULL);
1661 }
1662
1663 static void
1664 set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp)
1665 {
1666         set80211(s, IEEE80211_IOC_SHORTGI,
1667                 d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
1668                 0, NULL);
1669 }
1670
1671 static void
1672 set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp)
1673 {
1674         int ampdu;
1675
1676         if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
1677                 errx(-1, "cannot get AMPDU setting");
1678         if (d < 0) {
1679                 d = -d;
1680                 ampdu &= ~d;
1681         } else
1682                 ampdu |= d;
1683         set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
1684 }
1685
1686 static
1687 DECL_CMD_FUNC(set80211ampdulimit, val, d)
1688 {
1689         int v;
1690
1691         switch (atoi(val)) {
1692         case 8:
1693         case 8*1024:
1694                 v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
1695                 break;
1696         case 16:
1697         case 16*1024:
1698                 v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
1699                 break;
1700         case 32:
1701         case 32*1024:
1702                 v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
1703                 break;
1704         case 64:
1705         case 64*1024:
1706                 v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
1707                 break;
1708         default:
1709                 errx(-1, "invalid A-MPDU limit %s", val);
1710         }
1711         set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
1712 }
1713
1714 static
1715 DECL_CMD_FUNC(set80211ampdudensity, val, d)
1716 {
1717         int v;
1718
1719         if (isanyarg(val) || iseq(val, "na"))
1720                 v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1721         else switch ((int)(atof(val)*4)) {
1722         case 0:
1723                 v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1724                 break;
1725         case 1:
1726                 v = IEEE80211_HTCAP_MPDUDENSITY_025;
1727                 break;
1728         case 2:
1729                 v = IEEE80211_HTCAP_MPDUDENSITY_05;
1730                 break;
1731         case 4:
1732                 v = IEEE80211_HTCAP_MPDUDENSITY_1;
1733                 break;
1734         case 8:
1735                 v = IEEE80211_HTCAP_MPDUDENSITY_2;
1736                 break;
1737         case 16:
1738                 v = IEEE80211_HTCAP_MPDUDENSITY_4;
1739                 break;
1740         case 32:
1741                 v = IEEE80211_HTCAP_MPDUDENSITY_8;
1742                 break;
1743         case 64:
1744                 v = IEEE80211_HTCAP_MPDUDENSITY_16;
1745                 break;
1746         default:
1747                 errx(-1, "invalid A-MPDU density %s", val);
1748         }
1749         set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
1750 }
1751
1752 static void
1753 set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
1754 {
1755         int amsdu;
1756
1757         if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
1758                 err(-1, "cannot get AMSDU setting");
1759         if (d < 0) {
1760                 d = -d;
1761                 amsdu &= ~d;
1762         } else
1763                 amsdu |= d;
1764         set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
1765 }
1766
1767 static
1768 DECL_CMD_FUNC(set80211amsdulimit, val, d)
1769 {
1770         set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
1771 }
1772
1773 static void
1774 set80211puren(const char *val, int d, int s, const struct afswtch *rafp)
1775 {
1776         set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
1777 }
1778
1779 static void
1780 set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp)
1781 {
1782         set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
1783 }
1784
1785 static void
1786 set80211htconf(const char *val, int d, int s, const struct afswtch *rafp)
1787 {
1788         set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
1789         htconf = d;
1790 }
1791
1792 static void
1793 set80211dwds(const char *val, int d, int s, const struct afswtch *rafp)
1794 {
1795         set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL);
1796 }
1797
1798 static void
1799 set80211inact(const char *val, int d, int s, const struct afswtch *rafp)
1800 {
1801         set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
1802 }
1803
1804 static void
1805 set80211tsn(const char *val, int d, int s, const struct afswtch *rafp)
1806 {
1807         set80211(s, IEEE80211_IOC_TSN, d, 0, NULL);
1808 }
1809
1810 static void
1811 set80211dotd(const char *val, int d, int s, const struct afswtch *rafp)
1812 {
1813         set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL);
1814 }
1815
1816 static void
1817 set80211smps(const char *val, int d, int s, const struct afswtch *rafp)
1818 {
1819         set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL);
1820 }
1821
1822 static void
1823 set80211rifs(const char *val, int d, int s, const struct afswtch *rafp)
1824 {
1825         set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
1826 }
1827
1828 static
1829 DECL_CMD_FUNC(set80211tdmaslot, val, d)
1830 {
1831         set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
1832 }
1833
1834 static
1835 DECL_CMD_FUNC(set80211tdmaslotcnt, val, d)
1836 {
1837         set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
1838 }
1839
1840 static
1841 DECL_CMD_FUNC(set80211tdmaslotlen, val, d)
1842 {
1843         set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
1844 }
1845
1846 static
1847 DECL_CMD_FUNC(set80211tdmabintval, val, d)
1848 {
1849         set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
1850 }
1851
1852 static
1853 DECL_CMD_FUNC(set80211meshttl, val, d)
1854 {
1855         set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
1856 }
1857
1858 static
1859 DECL_CMD_FUNC(set80211meshforward, val, d)
1860 {
1861         set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL);
1862 }
1863
1864 static
1865 DECL_CMD_FUNC(set80211meshpeering, val, d)
1866 {
1867         set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL);
1868 }
1869
1870 static
1871 DECL_CMD_FUNC(set80211meshmetric, val, d)
1872 {
1873         char v[12];
1874
1875         memcpy(v, val, sizeof(v));
1876         set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
1877 }
1878
1879 static
1880 DECL_CMD_FUNC(set80211meshpath, val, d)
1881 {
1882         char v[12];
1883
1884         memcpy(v, val, sizeof(v));
1885         set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
1886 }
1887
1888 static int
1889 regdomain_sort(const void *a, const void *b)
1890 {
1891 #define CHAN_ALL \
1892         (IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)
1893         const struct ieee80211_channel *ca = a;
1894         const struct ieee80211_channel *cb = b;
1895
1896         return ca->ic_freq == cb->ic_freq ?
1897             ((int)ca->ic_flags & CHAN_ALL) - ((int)cb->ic_flags & CHAN_ALL) :
1898             ca->ic_freq - cb->ic_freq;
1899 #undef CHAN_ALL
1900 }
1901
1902 static const struct ieee80211_channel *
1903 chanlookup(const struct ieee80211_channel chans[], int nchans,
1904         int freq, int flags)
1905 {
1906         int i;
1907
1908         flags &= IEEE80211_CHAN_ALLTURBO;
1909         for (i = 0; i < nchans; i++) {
1910                 const struct ieee80211_channel *c = &chans[i];
1911                 if (c->ic_freq == freq &&
1912                     ((int)c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
1913                         return c;
1914         }
1915         return NULL;
1916 }
1917
1918 static int
1919 chanfind(const struct ieee80211_channel chans[], int nchans, int flags)
1920 {
1921         int i;
1922
1923         for (i = 0; i < nchans; i++) {
1924                 const struct ieee80211_channel *c = &chans[i];
1925                 if (((int)c->ic_flags & flags) == flags)
1926                         return 1;
1927         }
1928         return 0;
1929 }
1930
1931 /*
1932  * Check channel compatibility.
1933  */
1934 static int
1935 checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags)
1936 {
1937         flags &= ~REQ_FLAGS;
1938         /*
1939          * Check if exact channel is in the calibration table;
1940          * everything below is to deal with channels that we
1941          * want to include but that are not explicitly listed.
1942          */
1943         if (flags & IEEE80211_CHAN_HT40) {
1944                 /* NB: we use an HT40 channel center that matches HT20 */
1945                 flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20;
1946         }
1947         if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL)
1948                 return 1;
1949         if (flags & IEEE80211_CHAN_GSM) {
1950                 /*
1951                  * XXX GSM frequency mapping is handled in the kernel
1952                  * so we cannot find them in the calibration table;
1953                  * just accept the channel and the kernel will reject
1954                  * the channel list if it's wrong.
1955                  */
1956                 return 1;
1957         }
1958         /*
1959          * If this is a 1/2 or 1/4 width channel allow it if a full
1960          * width channel is present for this frequency, and the device
1961          * supports fractional channels on this band.  This is a hack
1962          * that avoids bloating the calibration table; it may be better
1963          * by per-band attributes though (we are effectively calculating
1964          * this attribute by scanning the channel list ourself).
1965          */
1966         if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0)
1967                 return 0;
1968         if (chanlookup(avail->ic_chans, avail->ic_nchans, freq,
1969             flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL)
1970                 return 0;
1971         if (flags & IEEE80211_CHAN_HALF) {
1972                 return chanfind(avail->ic_chans, avail->ic_nchans,
1973                     IEEE80211_CHAN_HALF |
1974                        (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
1975         } else {
1976                 return chanfind(avail->ic_chans, avail->ic_nchans,
1977                     IEEE80211_CHAN_QUARTER |
1978                         (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
1979         }
1980 }
1981
1982 static void
1983 regdomain_addchans(struct ieee80211req_chaninfo *ci,
1984         const netband_head *bands,
1985         const struct ieee80211_regdomain *reg,
1986         uint32_t chanFlags,
1987         const struct ieee80211req_chaninfo *avail)
1988 {
1989         const struct netband *nb;
1990         const struct freqband *b;
1991         struct ieee80211_channel *c, *prev;
1992         int freq, hi_adj, lo_adj, channelSep;
1993         uint32_t flags;
1994
1995         hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
1996         lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
1997         channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
1998         LIST_FOREACH(nb, bands, next) {
1999                 b = nb->band;
2000                 if (verbose) {
2001                         printf("%s:", __func__);
2002                         printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
2003                         printb(" bandFlags", nb->flags | b->flags,
2004                             IEEE80211_CHAN_BITS);
2005                         putchar('\n');
2006                 }
2007                 prev = NULL;
2008                 for (freq = b->freqStart + lo_adj;
2009                      freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
2010                         /*
2011                          * Construct flags for the new channel.  We take
2012                          * the attributes from the band descriptions except
2013                          * for HT40 which is enabled generically (i.e. +/-
2014                          * extension channel) in the band description and
2015                          * then constrained according by channel separation.
2016                          */
2017                         flags = nb->flags | b->flags;
2018                         if (flags & IEEE80211_CHAN_HT) {
2019                                 /*
2020                                  * HT channels are generated specially; we're
2021                                  * called to add HT20, HT40+, and HT40- chan's
2022                                  * so we need to expand only band specs for
2023                                  * the HT channel type being added.
2024                                  */
2025                                 if ((chanFlags & IEEE80211_CHAN_HT20) &&
2026                                     (flags & IEEE80211_CHAN_HT20) == 0) {
2027                                         if (verbose)
2028                                                 printf("%u: skip, not an "
2029                                                     "HT20 channel\n", freq);
2030                                         continue;
2031                                 }
2032                                 if ((chanFlags & IEEE80211_CHAN_HT40) &&
2033                                     (flags & IEEE80211_CHAN_HT40) == 0) {
2034                                         if (verbose)
2035                                                 printf("%u: skip, not an "
2036                                                     "HT40 channel\n", freq);
2037                                         continue;
2038                                 }
2039                                 /*
2040                                  * DFS and HT40 don't mix.  This should be
2041                                  * expressed in the regdomain database but
2042                                  * just in case enforce it here.
2043                                  */
2044                                 if ((chanFlags & IEEE80211_CHAN_HT40) &&
2045                                     (flags & IEEE80211_CHAN_DFS)) {
2046                                         if (verbose)
2047                                                 printf("%u: skip, HT40+DFS "
2048                                                     "not permitted\n", freq);
2049                                         continue;
2050                                 }
2051                                 /* NB: HT attribute comes from caller */
2052                                 flags &= ~IEEE80211_CHAN_HT;
2053                                 flags |= chanFlags & IEEE80211_CHAN_HT;
2054                         }
2055                         /*
2056                          * Check if device can operate on this frequency.
2057                          */
2058                         if (!checkchan(avail, freq, flags)) {
2059                                 if (verbose) {
2060                                         printf("%u: skip, ", freq);
2061                                         printb("flags", flags,
2062                                             IEEE80211_CHAN_BITS);
2063                                         printf(" not available\n");
2064                                 }
2065                                 continue;
2066                         }
2067                         if ((flags & REQ_ECM) && !reg->ecm) {
2068                                 if (verbose)
2069                                         printf("%u: skip, ECM channel\n", freq);
2070                                 continue;
2071                         }
2072                         if ((flags & REQ_INDOOR) && reg->location == 'O') {
2073                                 if (verbose)
2074                                         printf("%u: skip, indoor channel\n",
2075                                             freq);
2076                                 continue;
2077                         }
2078                         if ((flags & REQ_OUTDOOR) && reg->location == 'I') {
2079                                 if (verbose)
2080                                         printf("%u: skip, outdoor channel\n",
2081                                             freq);
2082                                 continue;
2083                         }
2084                         if ((flags & IEEE80211_CHAN_HT40) &&
2085                             prev != NULL && (freq - prev->ic_freq) < channelSep) {
2086                                 if (verbose)
2087                                         printf("%u: skip, only %u channel "
2088                                             "separation, need %d\n", freq,
2089                                             freq - prev->ic_freq, channelSep);
2090                                 continue;
2091                         }
2092                         if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
2093                                 if (verbose)
2094                                         printf("%u: skip, channel table full\n",
2095                                             freq);
2096                                 break;
2097                         }
2098                         c = &ci->ic_chans[ci->ic_nchans++];
2099                         memset(c, 0, sizeof(*c));
2100                         c->ic_freq = freq;
2101                         c->ic_flags = flags;
2102                         if (c->ic_flags & IEEE80211_CHAN_DFS)
2103                                 c->ic_maxregpower = nb->maxPowerDFS;
2104                         else
2105                                 c->ic_maxregpower = nb->maxPower;
2106                         if (verbose) {
2107                                 printf("[%3d] add freq %u ",
2108                                     ci->ic_nchans-1, c->ic_freq);
2109                                 printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
2110                                 printf(" power %u\n", c->ic_maxregpower);
2111                         }
2112                         /* NB: kernel fills in other fields */
2113                         prev = c;
2114                 }
2115         }
2116 }
2117
2118 static void
2119 regdomain_makechannels(
2120         struct ieee80211_regdomain_req *req,
2121         const struct ieee80211_devcaps_req *dc)
2122 {
2123         struct regdata *rdp = getregdata();
2124         const struct country *cc;
2125         const struct ieee80211_regdomain *reg = &req->rd;
2126         struct ieee80211req_chaninfo *ci = &req->chaninfo;
2127         const struct regdomain *rd;
2128
2129         /*
2130          * Locate construction table for new channel list.  We treat
2131          * the regdomain/SKU as definitive so a country can be in
2132          * multiple with different properties (e.g. US in FCC+FCC3).
2133          * If no regdomain is specified then we fallback on the country
2134          * code to find the associated regdomain since countries always
2135          * belong to at least one regdomain.
2136          */
2137         if (reg->regdomain == 0) {
2138                 cc = lib80211_country_findbycc(rdp, reg->country);
2139                 if (cc == NULL)
2140                         errx(1, "internal error, country %d not found",
2141                             reg->country);
2142                 rd = cc->rd;
2143         } else
2144                 rd = lib80211_regdomain_findbysku(rdp, reg->regdomain);
2145         if (rd == NULL)
2146                 errx(1, "internal error, regdomain %d not found",
2147                             reg->regdomain);
2148         if (rd->sku != SKU_DEBUG) {
2149                 /*
2150                  * regdomain_addchans incrememnts the channel count for
2151                  * each channel it adds so initialize ic_nchans to zero.
2152                  * Note that we know we have enough space to hold all possible
2153                  * channels because the devcaps list size was used to
2154                  * allocate our request.
2155                  */
2156                 ci->ic_nchans = 0;
2157                 if (!LIST_EMPTY(&rd->bands_11b))
2158                         regdomain_addchans(ci, &rd->bands_11b, reg,
2159                             IEEE80211_CHAN_B, &dc->dc_chaninfo);
2160                 if (!LIST_EMPTY(&rd->bands_11g))
2161                         regdomain_addchans(ci, &rd->bands_11g, reg,
2162                             IEEE80211_CHAN_G, &dc->dc_chaninfo);
2163                 if (!LIST_EMPTY(&rd->bands_11a))
2164                         regdomain_addchans(ci, &rd->bands_11a, reg,
2165                             IEEE80211_CHAN_A, &dc->dc_chaninfo);
2166                 if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) {
2167                         regdomain_addchans(ci, &rd->bands_11na, reg,
2168                             IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
2169                             &dc->dc_chaninfo);
2170                         if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2171                                 regdomain_addchans(ci, &rd->bands_11na, reg,
2172                                     IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,
2173                                     &dc->dc_chaninfo);
2174                                 regdomain_addchans(ci, &rd->bands_11na, reg,
2175                                     IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,
2176                                     &dc->dc_chaninfo);
2177                         }
2178                 }
2179                 if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
2180                         regdomain_addchans(ci, &rd->bands_11ng, reg,
2181                             IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
2182                             &dc->dc_chaninfo);
2183                         if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2184                                 regdomain_addchans(ci, &rd->bands_11ng, reg,
2185                                     IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,
2186                                     &dc->dc_chaninfo);
2187                                 regdomain_addchans(ci, &rd->bands_11ng, reg,
2188                                     IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,
2189                                     &dc->dc_chaninfo);
2190                         }
2191                 }
2192                 qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
2193                     regdomain_sort);
2194         } else
2195                 memcpy(ci, &dc->dc_chaninfo,
2196                     IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
2197 }
2198
2199 static void
2200 list_countries(void)
2201 {
2202         struct regdata *rdp = getregdata();
2203         const struct country *cp;
2204         const struct regdomain *dp;
2205         int i;
2206
2207         i = 0;
2208         printf("\nCountry codes:\n");
2209         LIST_FOREACH(cp, &rdp->countries, next) {
2210                 printf("%2s %-15.15s%s", cp->isoname,
2211                     cp->name, ((i+1)%4) == 0 ? "\n" : " ");
2212                 i++;
2213         }
2214         i = 0;
2215         printf("\nRegulatory domains:\n");
2216         LIST_FOREACH(dp, &rdp->domains, next) {
2217                 printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " ");
2218                 i++;
2219         }
2220         printf("\n");
2221 }
2222
2223 static void
2224 defaultcountry(const struct regdomain *rd)
2225 {
2226         struct regdata *rdp = getregdata();
2227         const struct country *cc;
2228
2229         cc = lib80211_country_findbycc(rdp, rd->cc->code);
2230         if (cc == NULL)
2231                 errx(1, "internal error, ISO country code %d not "
2232                     "defined for regdomain %s", rd->cc->code, rd->name);
2233         regdomain.country = cc->code;
2234         regdomain.isocc[0] = cc->isoname[0];
2235         regdomain.isocc[1] = cc->isoname[1];
2236 }
2237
2238 static
2239 DECL_CMD_FUNC(set80211regdomain, val, d)
2240 {
2241         struct regdata *rdp = getregdata();
2242         const struct regdomain *rd;
2243
2244         rd = lib80211_regdomain_findbyname(rdp, val);
2245         if (rd == NULL) {
2246                 char *eptr;
2247                 long sku = strtol(val, &eptr, 0);
2248
2249                 if (eptr != val)
2250                         rd = lib80211_regdomain_findbysku(rdp, sku);
2251                 if (eptr == val || rd == NULL)
2252                         errx(1, "unknown regdomain %s", val);
2253         }
2254         getregdomain(s);
2255         regdomain.regdomain = rd->sku;
2256         if (regdomain.country == 0 && rd->cc != NULL) {
2257                 /*
2258                  * No country code setup and there's a default
2259                  * one for this regdomain fill it in.
2260                  */
2261                 defaultcountry(rd);
2262         }
2263         callback_register(setregdomain_cb, &regdomain);
2264 }
2265
2266 static
2267 DECL_CMD_FUNC(set80211country, val, d)
2268 {
2269         struct regdata *rdp = getregdata();
2270         const struct country *cc;
2271
2272         cc = lib80211_country_findbyname(rdp, val);
2273         if (cc == NULL) {
2274                 char *eptr;
2275                 long code = strtol(val, &eptr, 0);
2276
2277                 if (eptr != val)
2278                         cc = lib80211_country_findbycc(rdp, code);
2279                 if (eptr == val || cc == NULL)
2280                         errx(1, "unknown ISO country code %s", val);
2281         }
2282         getregdomain(s);
2283         regdomain.regdomain = cc->rd->sku;
2284         regdomain.country = cc->code;
2285         regdomain.isocc[0] = cc->isoname[0];
2286         regdomain.isocc[1] = cc->isoname[1];
2287         callback_register(setregdomain_cb, &regdomain);
2288 }
2289
2290 static void
2291 set80211location(const char *val, int d, int s, const struct afswtch *rafp)
2292 {
2293         getregdomain(s);
2294         regdomain.location = d;
2295         callback_register(setregdomain_cb, &regdomain);
2296 }
2297
2298 static void
2299 set80211ecm(const char *val, int d, int s, const struct afswtch *rafp)
2300 {
2301         getregdomain(s);
2302         regdomain.ecm = d;
2303         callback_register(setregdomain_cb, &regdomain);
2304 }
2305
2306 static void
2307 LINE_INIT(char c)
2308 {
2309         spacer = c;
2310         if (c == '\t')
2311                 col = 8;
2312         else
2313                 col = 1;
2314 }
2315
2316 static void
2317 LINE_BREAK(void)
2318 {
2319         if (spacer != '\t') {
2320                 printf("\n");
2321                 spacer = '\t';
2322         }
2323         col = 8;                /* 8-col tab */
2324 }
2325
2326 static void
2327 LINE_CHECK(const char *fmt, ...)
2328 {
2329         char buf[80];
2330         va_list ap;
2331         int n;
2332
2333         va_start(ap, fmt);
2334         n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
2335         va_end(ap);
2336         col += 1+n;
2337         if (col > MAXCOL) {
2338                 LINE_BREAK();
2339                 col += n;
2340         }
2341         buf[0] = spacer;
2342         printf("%s", buf);
2343         spacer = ' ';
2344 }
2345
2346 static int
2347 getmaxrate(const uint8_t rates[15], uint8_t nrates)
2348 {
2349         int i, maxrate = -1;
2350
2351         for (i = 0; i < nrates; i++) {
2352                 int rate = rates[i] & IEEE80211_RATE_VAL;
2353                 if (rate > maxrate)
2354                         maxrate = rate;
2355         }
2356         return maxrate / 2;
2357 }
2358
2359 static const char *
2360 getcaps(int capinfo)
2361 {
2362         static char capstring[32];
2363         char *cp = capstring;
2364
2365         if (capinfo & IEEE80211_CAPINFO_ESS)
2366                 *cp++ = 'E';
2367         if (capinfo & IEEE80211_CAPINFO_IBSS)
2368                 *cp++ = 'I';
2369         if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
2370                 *cp++ = 'c';
2371         if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
2372                 *cp++ = 'C';
2373         if (capinfo & IEEE80211_CAPINFO_PRIVACY)
2374                 *cp++ = 'P';
2375         if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
2376                 *cp++ = 'S';
2377         if (capinfo & IEEE80211_CAPINFO_PBCC)
2378                 *cp++ = 'B';
2379         if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
2380                 *cp++ = 'A';
2381         if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
2382                 *cp++ = 's';
2383         if (capinfo & IEEE80211_CAPINFO_RSN)
2384                 *cp++ = 'R';
2385         if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
2386                 *cp++ = 'D';
2387         *cp = '\0';
2388         return capstring;
2389 }
2390
2391 static const char *
2392 getflags(int flags)
2393 {
2394         static char flagstring[32];
2395         char *cp = flagstring;
2396
2397         if (flags & IEEE80211_NODE_AUTH)
2398                 *cp++ = 'A';
2399         if (flags & IEEE80211_NODE_QOS)
2400                 *cp++ = 'Q';
2401         if (flags & IEEE80211_NODE_ERP)
2402                 *cp++ = 'E';
2403         if (flags & IEEE80211_NODE_PWR_MGT)
2404                 *cp++ = 'P';
2405         if (flags & IEEE80211_NODE_HT) {
2406                 *cp++ = 'H';
2407                 if (flags & IEEE80211_NODE_HTCOMPAT)
2408                         *cp++ = '+';
2409         }
2410         if (flags & IEEE80211_NODE_WPS)
2411                 *cp++ = 'W';
2412         if (flags & IEEE80211_NODE_TSN)
2413                 *cp++ = 'N';
2414         if (flags & IEEE80211_NODE_AMPDU_TX)
2415                 *cp++ = 'T';
2416         if (flags & IEEE80211_NODE_AMPDU_RX)
2417                 *cp++ = 'R';
2418         if (flags & IEEE80211_NODE_MIMO_PS) {
2419                 *cp++ = 'M';
2420                 if (flags & IEEE80211_NODE_MIMO_RTS)
2421                         *cp++ = '+';
2422         }
2423         if (flags & IEEE80211_NODE_RIFS)
2424                 *cp++ = 'I';
2425         if (flags & IEEE80211_NODE_SGI40) {
2426                 *cp++ = 'S';
2427                 if (flags & IEEE80211_NODE_SGI20)
2428                         *cp++ = '+';
2429         } else if (flags & IEEE80211_NODE_SGI20)
2430                 *cp++ = 's';
2431         if (flags & IEEE80211_NODE_AMSDU_TX)
2432                 *cp++ = 't';
2433         if (flags & IEEE80211_NODE_AMSDU_RX)
2434                 *cp++ = 'r';
2435         *cp = '\0';
2436         return flagstring;
2437 }
2438
2439 static void
2440 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
2441 {
2442         printf("%s", tag);
2443         if (verbose) {
2444                 maxlen -= strlen(tag)+2;
2445                 if (2*ielen > (size_t)maxlen)
2446                         maxlen--;
2447                 printf("<");
2448                 for (; ielen > 0; ie++, ielen--) {
2449                         if (maxlen-- <= 0)
2450                                 break;
2451                         printf("%02x", *ie);
2452                 }
2453                 if (ielen != 0)
2454                         printf("-");
2455                 printf(">");
2456         }
2457 }
2458
2459 #define LE_READ_2(p)                                    \
2460         ((u_int16_t)                                    \
2461          ((((const u_int8_t *)(p))[0]      ) |          \
2462           (((const u_int8_t *)(p))[1] <<  8)))
2463 #define LE_READ_4(p)                                    \
2464         ((u_int32_t)                                    \
2465          ((((const u_int8_t *)(p))[0]      ) |          \
2466           (((const u_int8_t *)(p))[1] <<  8) |          \
2467           (((const u_int8_t *)(p))[2] << 16) |          \
2468           (((const u_int8_t *)(p))[3] << 24)))
2469
2470 /*
2471  * NB: The decoding routines assume a properly formatted ie
2472  *     which should be safe as the kernel only retains them
2473  *     if they parse ok.
2474  */
2475
2476 static void
2477 printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2478 {
2479 #define MS(_v, _f)      (((_v) & _f) >> _f##_S)
2480         static const char *acnames[] = { "BE", "BK", "VO", "VI" };
2481         const struct ieee80211_wme_param *wme =
2482             (const struct ieee80211_wme_param *) ie;
2483         int i;
2484
2485         printf("%s", tag);
2486         if (!verbose)
2487                 return;
2488         printf("<qosinfo 0x%x", wme->param_qosInfo);
2489         ie += offsetof(struct ieee80211_wme_param, params_acParams);
2490         for (i = 0; i < WME_NUM_AC; i++) {
2491                 const struct ieee80211_wme_acparams *ac =
2492                     &wme->params_acParams[i];
2493
2494                 printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
2495                         , acnames[i]
2496                         , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
2497                         , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
2498                         , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
2499                         , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
2500                         , LE_READ_2(&ac->acp_txop)
2501                 );
2502         }
2503         printf(">");
2504 #undef MS
2505 }
2506
2507 static void
2508 printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2509 {
2510         printf("%s", tag);
2511         if (verbose) {
2512                 const struct ieee80211_wme_info *wme =
2513                     (const struct ieee80211_wme_info *) ie;
2514                 printf("<version 0x%x info 0x%x>",
2515                     wme->wme_version, wme->wme_info);
2516         }
2517 }
2518
2519 static void
2520 printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2521 {
2522         printf("%s", tag);
2523         if (verbose) {
2524                 const struct ieee80211_ie_htcap *htcap =
2525                     (const struct ieee80211_ie_htcap *) ie;
2526                 const char *sep;
2527                 int i, j;
2528
2529                 printf("<cap 0x%x param 0x%x",
2530                     LE_READ_2(&htcap->hc_cap), htcap->hc_param);
2531                 printf(" mcsset[");
2532                 sep = "";
2533                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
2534                         if (isset(htcap->hc_mcsset, i)) {
2535                                 for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
2536                                         if (isclr(htcap->hc_mcsset, j))
2537                                                 break;
2538                                 j--;
2539                                 if (i == j)
2540                                         printf("%s%u", sep, i);
2541                                 else
2542                                         printf("%s%u-%u", sep, i, j);
2543                                 i += j-i;
2544                                 sep = ",";
2545                         }
2546                 printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
2547                     LE_READ_2(&htcap->hc_extcap),
2548                     LE_READ_4(&htcap->hc_txbf),
2549                     htcap->hc_antenna);
2550         }
2551 }
2552
2553 static void
2554 printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2555 {
2556         printf("%s", tag);
2557         if (verbose) {
2558                 const struct ieee80211_ie_htinfo *htinfo =
2559                     (const struct ieee80211_ie_htinfo *) ie;
2560                 const char *sep;
2561                 int i, j;
2562
2563                 printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
2564                     htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
2565                     LE_READ_2(&htinfo->hi_byte45));
2566                 printf(" basicmcs[");
2567                 sep = "";
2568                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
2569                         if (isset(htinfo->hi_basicmcsset, i)) {
2570                                 for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
2571                                         if (isclr(htinfo->hi_basicmcsset, j))
2572                                                 break;
2573                                 j--;
2574                                 if (i == j)
2575                                         printf("%s%u", sep, i);
2576                                 else
2577                                         printf("%s%u-%u", sep, i, j);
2578                                 i += j-i;
2579                                 sep = ",";
2580                         }
2581                 printf("]>");
2582         }
2583 }
2584
2585 static void
2586 printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2587 {
2588
2589         printf("%s", tag);
2590         if (verbose) {
2591                 const struct ieee80211_ath_ie *ath =
2592                         (const struct ieee80211_ath_ie *)ie;
2593
2594                 printf("<");
2595                 if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
2596                         printf("DTURBO,");
2597                 if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
2598                         printf("COMP,");
2599                 if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
2600                         printf("FF,");
2601                 if (ath->ath_capability & ATHEROS_CAP_XR)
2602                         printf("XR,");
2603                 if (ath->ath_capability & ATHEROS_CAP_AR)
2604                         printf("AR,");
2605                 if (ath->ath_capability & ATHEROS_CAP_BURST)
2606                         printf("BURST,");
2607                 if (ath->ath_capability & ATHEROS_CAP_WME)
2608                         printf("WME,");
2609                 if (ath->ath_capability & ATHEROS_CAP_BOOST)
2610                         printf("BOOST,");
2611                 printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
2612         }
2613 }
2614
2615
2616 static void
2617 printmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen)
2618 {
2619 #define MATCHOUI(field, oui, string)                                    \
2620 do {                                                                    \
2621         if (memcmp(field, oui, 4) == 0)                                 \
2622                 printf("%s", string);                                   \
2623 } while (0)
2624
2625         printf("%s", tag);
2626         if (verbose) {
2627                 const struct ieee80211_meshconf_ie *mconf =
2628                         (const struct ieee80211_meshconf_ie *)ie;
2629                 printf("<PATH:");
2630                 if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP)
2631                         printf("HWMP");
2632                 else
2633                         printf("UNKNOWN");
2634                 printf(" LINK:");
2635                 if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME)
2636                         printf("AIRTIME");
2637                 else
2638                         printf("UNKNOWN");
2639                 printf(" CONGESTION:");
2640                 if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED)
2641                         printf("DISABLED");
2642                 else
2643                         printf("UNKNOWN");
2644                 printf(" SYNC:");
2645                 if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF)
2646                         printf("NEIGHOFF");
2647                 else
2648                         printf("UNKNOWN");
2649                 printf(" AUTH:");
2650                 if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED)
2651                         printf("DISABLED");
2652                 else
2653                         printf("UNKNOWN");
2654                 printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
2655                     mconf->conf_cap);
2656         }
2657 #undef MATCHOUI
2658 }
2659
2660 static const char *
2661 wpa_cipher(const u_int8_t *sel)
2662 {
2663 #define WPA_SEL(x)      (((x)<<24)|WPA_OUI)
2664         u_int32_t w = LE_READ_4(sel);
2665
2666         switch (w) {
2667         case WPA_SEL(WPA_CSE_NULL):
2668                 return "NONE";
2669         case WPA_SEL(WPA_CSE_WEP40):
2670                 return "WEP40";
2671         case WPA_SEL(WPA_CSE_WEP104):
2672                 return "WEP104";
2673         case WPA_SEL(WPA_CSE_TKIP):
2674                 return "TKIP";
2675         case WPA_SEL(WPA_CSE_CCMP):
2676                 return "AES-CCMP";
2677         }
2678         return "?";             /* NB: so 1<< is discarded */
2679 #undef WPA_SEL
2680 }
2681
2682 static const char *
2683 wpa_keymgmt(const u_int8_t *sel)
2684 {
2685 #define WPA_SEL(x)      (((x)<<24)|WPA_OUI)
2686         u_int32_t w = LE_READ_4(sel);
2687
2688         switch (w) {
2689         case WPA_SEL(WPA_ASE_8021X_UNSPEC):
2690                 return "8021X-UNSPEC";
2691         case WPA_SEL(WPA_ASE_8021X_PSK):
2692                 return "8021X-PSK";
2693         case WPA_SEL(WPA_ASE_NONE):
2694                 return "NONE";
2695         }
2696         return "?";
2697 #undef WPA_SEL
2698 }
2699
2700 static void
2701 printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2702 {
2703         u_int8_t len = ie[1];
2704
2705         printf("%s", tag);
2706         if (verbose) {
2707                 const char *sep;
2708                 int n;
2709
2710                 ie += 6, len -= 4;              /* NB: len is payload only */
2711
2712                 printf("<v%u", LE_READ_2(ie));
2713                 ie += 2, len -= 2;
2714
2715                 printf(" mc:%s", wpa_cipher(ie));
2716                 ie += 4, len -= 4;
2717
2718                 /* unicast ciphers */
2719                 n = LE_READ_2(ie);
2720                 ie += 2, len -= 2;
2721                 sep = " uc:";
2722                 for (; n > 0; n--) {
2723                         printf("%s%s", sep, wpa_cipher(ie));
2724                         ie += 4, len -= 4;
2725                         sep = "+";
2726                 }
2727
2728                 /* key management algorithms */
2729                 n = LE_READ_2(ie);
2730                 ie += 2, len -= 2;
2731                 sep = " km:";
2732                 for (; n > 0; n--) {
2733                         printf("%s%s", sep, wpa_keymgmt(ie));
2734                         ie += 4, len -= 4;
2735                         sep = "+";
2736                 }
2737
2738                 if (len > 2)            /* optional capabilities */
2739                         printf(", caps 0x%x", LE_READ_2(ie));
2740                 printf(">");
2741         }
2742 }
2743
2744 static const char *
2745 rsn_cipher(const u_int8_t *sel)
2746 {
2747 #define RSN_SEL(x)      (((x)<<24)|RSN_OUI)
2748         u_int32_t w = LE_READ_4(sel);
2749
2750         switch (w) {
2751         case RSN_SEL(RSN_CSE_NULL):
2752                 return "NONE";
2753         case RSN_SEL(RSN_CSE_WEP40):
2754                 return "WEP40";
2755         case RSN_SEL(RSN_CSE_WEP104):
2756                 return "WEP104";
2757         case RSN_SEL(RSN_CSE_TKIP):
2758                 return "TKIP";
2759         case RSN_SEL(RSN_CSE_CCMP):
2760                 return "AES-CCMP";
2761         case RSN_SEL(RSN_CSE_WRAP):
2762                 return "AES-OCB";
2763         }
2764         return "?";
2765 #undef WPA_SEL
2766 }
2767
2768 static const char *
2769 rsn_keymgmt(const u_int8_t *sel)
2770 {
2771 #define RSN_SEL(x)      (((x)<<24)|RSN_OUI)
2772         u_int32_t w = LE_READ_4(sel);
2773
2774         switch (w) {
2775         case RSN_SEL(RSN_ASE_8021X_UNSPEC):
2776                 return "8021X-UNSPEC";
2777         case RSN_SEL(RSN_ASE_8021X_PSK):
2778                 return "8021X-PSK";
2779         case RSN_SEL(RSN_ASE_NONE):
2780                 return "NONE";
2781         }
2782         return "?";
2783 #undef RSN_SEL
2784 }
2785
2786 static void
2787 printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2788 {
2789         printf("%s", tag);
2790         if (verbose) {
2791                 const char *sep;
2792                 int n;
2793
2794                 ie += 2, ielen -= 2;
2795
2796                 printf("<v%u", LE_READ_2(ie));
2797                 ie += 2, ielen -= 2;
2798
2799                 printf(" mc:%s", rsn_cipher(ie));
2800                 ie += 4, ielen -= 4;
2801
2802                 /* unicast ciphers */
2803                 n = LE_READ_2(ie);
2804                 ie += 2, ielen -= 2;
2805                 sep = " uc:";
2806                 for (; n > 0; n--) {
2807                         printf("%s%s", sep, rsn_cipher(ie));
2808                         ie += 4, ielen -= 4;
2809                         sep = "+";
2810                 }
2811
2812                 /* key management algorithms */
2813                 n = LE_READ_2(ie);
2814                 ie += 2, ielen -= 2;
2815                 sep = " km:";
2816                 for (; n > 0; n--) {
2817                         printf("%s%s", sep, rsn_keymgmt(ie));
2818                         ie += 4, ielen -= 4;
2819                         sep = "+";
2820                 }
2821
2822                 if (ielen > 2)          /* optional capabilities */
2823                         printf(", caps 0x%x", LE_READ_2(ie));
2824                 /* XXXPMKID */
2825                 printf(">");
2826         }
2827 }
2828
2829 /* XXX move to a public include file */
2830 #define IEEE80211_WPS_DEV_PASS_ID       0x1012
2831 #define IEEE80211_WPS_SELECTED_REG      0x1041
2832 #define IEEE80211_WPS_SETUP_STATE       0x1044
2833 #define IEEE80211_WPS_UUID_E            0x1047
2834 #define IEEE80211_WPS_VERSION           0x104a
2835
2836 #define BE_READ_2(p)                                    \
2837         ((u_int16_t)                                    \
2838          ((((const u_int8_t *)(p))[1]      ) |          \
2839           (((const u_int8_t *)(p))[0] <<  8)))
2840
2841 static void
2842 printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2843 {
2844         u_int8_t len = ie[1];
2845         size_t n;
2846         uint16_t tlv_type;
2847         uint16_t tlv_len;
2848
2849         printf("%s", tag);
2850         if (verbose) {
2851                 static const char *dev_pass_id[] = {
2852                         "D",    /* Default (PIN) */
2853                         "U",    /* User-specified */
2854                         "M",    /* Machine-specified */
2855                         "K",    /* Rekey */
2856                         "P",    /* PushButton */
2857                         "R"     /* Registrar-specified */
2858                 };
2859
2860                 ie +=6, len -= 4;               /* NB: len is payload only */
2861
2862                 /* WPS IE in Beacon and Probe Resp frames have different fields */
2863                 printf("<");
2864                 while (len) {
2865                         tlv_type = BE_READ_2(ie);
2866                         tlv_len  = BE_READ_2(ie + 2);
2867
2868                         ie += 4, len -= 4;
2869
2870                         switch (tlv_type) {
2871                         case IEEE80211_WPS_VERSION:
2872                                 printf("v:%d.%d", *ie >> 4, *ie & 0xf);
2873                                 break;
2874                         case IEEE80211_WPS_SETUP_STATE:
2875                                 /* Only 1 and 2 are valid */
2876                                 if (*ie == 0 || *ie >= 3)
2877                                         printf(" state:B");
2878                                 else
2879                                         printf(" st:%s", *ie == 1 ? "N" : "C");
2880                                 break;
2881                         case IEEE80211_WPS_SELECTED_REG:
2882                                 printf(" sel:%s", *ie ? "T" : "F");
2883                                 break;
2884                         case IEEE80211_WPS_DEV_PASS_ID:
2885                                 n = LE_READ_2(ie);
2886                                 if (n < nitems(dev_pass_id))
2887                                         printf(" dpi:%s", dev_pass_id[n]);
2888                                 break;
2889                         case IEEE80211_WPS_UUID_E:
2890                                 printf(" uuid-e:");
2891                                 for (n = 0; n < (size_t)(tlv_len - 1); n++)
2892                                         printf("%02x-", ie[n]);
2893                                 printf("%02x", ie[n]);
2894                                 break;
2895                         }
2896                         ie += tlv_len, len -= tlv_len;
2897                 }
2898                 printf(">");
2899         }
2900 }
2901
2902 static void
2903 printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2904 {
2905         printf("%s", tag);
2906         if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
2907                 const struct ieee80211_tdma_param *tdma =
2908                    (const struct ieee80211_tdma_param *) ie;
2909
2910                 /* XXX tstamp */
2911                 printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
2912                     tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
2913                     LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
2914                     tdma->tdma_inuse[0]);
2915         }
2916 }
2917
2918 /*
2919  * Copy the ssid string contents into buf, truncating to fit.  If the
2920  * ssid is entirely printable then just copy intact.  Otherwise convert
2921  * to hexadecimal.  If the result is truncated then replace the last
2922  * three characters with "...".
2923  */
2924 static int
2925 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
2926 {
2927         const u_int8_t *p;
2928         size_t maxlen;
2929         size_t i;
2930
2931         if (essid_len > bufsize)
2932                 maxlen = bufsize;
2933         else
2934                 maxlen = essid_len;
2935         /* determine printable or not */
2936         for (i = 0, p = essid; i < maxlen; i++, p++) {
2937                 if (*p < ' ' || *p > 0x7e)
2938                         break;
2939         }
2940         if (i != maxlen) {              /* not printable, print as hex */
2941                 if (bufsize < 3)
2942                         return 0;
2943                 strlcpy(buf, "0x", bufsize);
2944                 bufsize -= 2;
2945                 p = essid;
2946                 for (i = 0; i < maxlen && bufsize >= 2; i++) {
2947                         sprintf(&buf[2+2*i], "%02x", p[i]);
2948                         bufsize -= 2;
2949                 }
2950                 if (i != essid_len)
2951                         memcpy(&buf[2+2*i-3], "...", 3);
2952         } else {                        /* printable, truncate as needed */
2953                 memcpy(buf, essid, maxlen);
2954                 if (maxlen != essid_len)
2955                         memcpy(&buf[maxlen-3], "...", 3);
2956         }
2957         return maxlen;
2958 }
2959
2960 static void
2961 printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
2962 {
2963         char ssid[2*IEEE80211_NWID_LEN+1];
2964
2965         printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
2966 }
2967
2968 static void
2969 printrates(const char *tag, const u_int8_t *ie, size_t ielen,
2970            __unused int maxlen)
2971 {
2972         const char *sep;
2973         size_t i;
2974
2975         printf("%s", tag);
2976         sep = "<";
2977         for (i = 2; i < ielen; i++) {
2978                 printf("%s%s%d", sep,
2979                     ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
2980                     ie[i] & IEEE80211_RATE_VAL);
2981                 sep = ",";
2982         }
2983         printf(">");
2984 }
2985
2986 static void
2987 printcountry(const char *tag, const u_int8_t *ie, size_t ielen,
2988              __unused int maxlen)
2989 {
2990         const struct ieee80211_country_ie *cie =
2991            (const struct ieee80211_country_ie *) ie;
2992         size_t i, nbands, schan, nchan;
2993
2994         printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
2995         nbands = (cie->len - 3) / sizeof(cie->band[0]);
2996         for (i = 0; i < nbands; i++) {
2997                 schan = cie->band[i].schan;
2998                 nchan = cie->band[i].nchan;
2999                 if (nchan != 1)
3000                         printf(" %zu-%zu,%u", schan, schan + nchan-1,
3001                             cie->band[i].maxtxpwr);
3002                 else
3003                         printf(" %zu,%u", schan, cie->band[i].maxtxpwr);
3004         }
3005         printf(">");
3006 }
3007
3008 /* unaligned little endian access */
3009 #define LE_READ_4(p)                                    \
3010         ((u_int32_t)                                    \
3011          ((((const u_int8_t *)(p))[0]      ) |          \
3012           (((const u_int8_t *)(p))[1] <<  8) |          \
3013           (((const u_int8_t *)(p))[2] << 16) |          \
3014           (((const u_int8_t *)(p))[3] << 24)))
3015
3016 static __inline int
3017 iswpaoui(const u_int8_t *frm)
3018 {
3019         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
3020 }
3021
3022 static __inline int
3023 iswmeinfo(const u_int8_t *frm)
3024 {
3025         return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3026                 frm[6] == WME_INFO_OUI_SUBTYPE;
3027 }
3028
3029 static __inline int
3030 iswmeparam(const u_int8_t *frm)
3031 {
3032         return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3033                 frm[6] == WME_PARAM_OUI_SUBTYPE;
3034 }
3035
3036 static __inline int
3037 isatherosoui(const u_int8_t *frm)
3038 {
3039         return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
3040 }
3041
3042 static __inline int
3043 istdmaoui(const uint8_t *frm)
3044 {
3045         return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
3046 }
3047
3048 static __inline int
3049 iswpsoui(const uint8_t *frm)
3050 {
3051         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
3052 }
3053
3054 static const char *
3055 iename(int elemid)
3056 {
3057         switch (elemid) {
3058         case IEEE80211_ELEMID_FHPARMS:  return " FHPARMS";
3059         case IEEE80211_ELEMID_CFPARMS:  return " CFPARMS";
3060         case IEEE80211_ELEMID_TIM:      return " TIM";
3061         case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
3062         case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
3063         case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR";
3064         case IEEE80211_ELEMID_PWRCAP:   return " PWRCAP";
3065         case IEEE80211_ELEMID_TPCREQ:   return " TPCREQ";
3066         case IEEE80211_ELEMID_TPCREP:   return " TPCREP";
3067         case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN";
3068         case IEEE80211_ELEMID_CSA:      return " CSA";
3069         case IEEE80211_ELEMID_MEASREQ:  return " MEASREQ";
3070         case IEEE80211_ELEMID_MEASREP:  return " MEASREP";
3071         case IEEE80211_ELEMID_QUIET:    return " QUIET";
3072         case IEEE80211_ELEMID_IBSSDFS:  return " IBSSDFS";
3073         case IEEE80211_ELEMID_TPC:      return " TPC";
3074         case IEEE80211_ELEMID_CCKM:     return " CCKM";
3075         }
3076         return " ???";
3077 }
3078
3079 static void
3080 printies(const u_int8_t *vp, int ielen, int maxcols)
3081 {
3082         while (ielen > 0) {
3083                 switch (vp[0]) {
3084                 case IEEE80211_ELEMID_SSID:
3085                         if (verbose)
3086                                 printssid(" SSID", vp, 2+vp[1], maxcols);
3087                         break;
3088                 case IEEE80211_ELEMID_RATES:
3089                 case IEEE80211_ELEMID_XRATES:
3090                         if (verbose)
3091                                 printrates(vp[0] == IEEE80211_ELEMID_RATES ?
3092                                     " RATES" : " XRATES", vp, 2+vp[1], maxcols);
3093                         break;
3094                 case IEEE80211_ELEMID_DSPARMS:
3095                         if (verbose)
3096                                 printf(" DSPARMS<%u>", vp[2]);
3097                         break;
3098                 case IEEE80211_ELEMID_COUNTRY:
3099                         if (verbose)
3100                                 printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
3101                         break;
3102                 case IEEE80211_ELEMID_ERP:
3103                         if (verbose)
3104                                 printf(" ERP<0x%x>", vp[2]);
3105                         break;
3106                 case IEEE80211_ELEMID_VENDOR:
3107                         if (iswpaoui(vp))
3108                                 printwpaie(" WPA", vp, 2+vp[1], maxcols);
3109                         else if (iswmeinfo(vp))
3110                                 printwmeinfo(" WME", vp, 2+vp[1], maxcols);
3111                         else if (iswmeparam(vp))
3112                                 printwmeparam(" WME", vp, 2+vp[1], maxcols);
3113                         else if (isatherosoui(vp))
3114                                 printathie(" ATH", vp, 2+vp[1], maxcols);
3115                         else if (iswpsoui(vp))
3116                                 printwpsie(" WPS", vp, 2+vp[1], maxcols);
3117                         else if (istdmaoui(vp))
3118                                 printtdmaie(" TDMA", vp, 2+vp[1], maxcols);
3119                         else if (verbose)
3120                                 printie(" VEN", vp, 2+vp[1], maxcols);
3121                         break;
3122                 case IEEE80211_ELEMID_RSN:
3123                         printrsnie(" RSN", vp, 2+vp[1], maxcols);
3124                         break;
3125                 case IEEE80211_ELEMID_HTCAP:
3126                         printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
3127                         break;
3128                 case IEEE80211_ELEMID_HTINFO:
3129                         if (verbose)
3130                                 printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
3131                         break;
3132                 case IEEE80211_ELEMID_MESHID:
3133                         if (verbose)
3134                                 printssid(" MESHID", vp, 2+vp[1], maxcols);
3135                         break;
3136                 case IEEE80211_ELEMID_MESHCONF:
3137                         printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols);
3138                         break;
3139                 default:
3140                         if (verbose)
3141                                 printie(iename(vp[0]), vp, 2+vp[1], maxcols);
3142                         break;
3143                 }
3144                 ielen -= 2+vp[1];
3145                 vp += 2+vp[1];
3146         }
3147 }
3148
3149 static void
3150 printmimo(const struct ieee80211_mimo_info *mi)
3151 {
3152         /* NB: don't muddy display unless there's something to show */
3153         if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) {
3154                 /* XXX ignore EVM for now */
3155                 printf(" (rssi %d:%d:%d nf %d:%d:%d)",
3156                     mi->rssi[0], mi->rssi[1], mi->rssi[2],
3157                     mi->noise[0], mi->noise[1], mi->noise[2]);
3158         }
3159 }
3160
3161 static void
3162 list_scan(int s, int long_ssids)
3163 {
3164         uint8_t buf[24*1024];
3165         char ssid[IEEE80211_NWID_LEN+1];
3166         const uint8_t *cp;
3167         size_t len, ssidmax, idlen;
3168
3169         if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
3170                 errx(1, "unable to get scan results");
3171         if (len < sizeof(struct ieee80211req_scan_result))
3172                 return;
3173
3174         getchaninfo(s);
3175
3176         ssidmax = (verbose || long_ssids) ? IEEE80211_NWID_LEN - 1 : 14;
3177         printf("%-*.*s  %-17.17s  %4s %4s  %-7s  %3s %4s\n"
3178                 , (int)ssidmax, (int)ssidmax, "SSID/MESH ID"
3179                 , "BSSID"
3180                 , "CHAN"
3181                 , "RATE"
3182                 , " S:N"
3183                 , "INT"
3184                 , "CAPS"
3185         );
3186         cp = buf;
3187         do {
3188                 const struct ieee80211req_scan_result *sr;
3189                 const uint8_t *vp, *idp;
3190
3191                 sr = (const struct ieee80211req_scan_result *) cp;
3192                 vp = cp + sr->isr_ie_off;
3193                 if (sr->isr_meshid_len) {
3194                         idp = vp + sr->isr_ssid_len;
3195                         idlen = sr->isr_meshid_len;
3196                 } else {
3197                         idp = vp;
3198                         idlen = sr->isr_ssid_len;
3199                 }
3200                 printf("%-*.*s  %s  %3d  %3dM %3d:%-3d  %3d %-4.4s"
3201                         , (int)ssidmax
3202                         , copy_essid(ssid, ssidmax, idp, idlen)
3203                         , ssid
3204                         , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
3205                         , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
3206                         , getmaxrate(sr->isr_rates, sr->isr_nrates)
3207                         , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
3208                         , sr->isr_intval
3209                         , getcaps(sr->isr_capinfo)
3210                 );
3211                 printies(vp + sr->isr_ssid_len + sr->isr_meshid_len,
3212                     sr->isr_ie_len, 24);
3213                 printf("\n");
3214                 cp += sr->isr_len, len -= sr->isr_len;
3215         } while (len >= sizeof(struct ieee80211req_scan_result));
3216 }
3217
3218 static void
3219 scan_and_wait(int s)
3220 {
3221         struct ieee80211_scan_req sr;
3222         struct ieee80211req ireq;
3223         int sroute;
3224
3225         sroute = socket(PF_ROUTE, SOCK_RAW, 0);
3226         if (sroute < 0) {
3227                 perror("socket(PF_ROUTE,SOCK_RAW)");
3228                 return;
3229         }
3230         memset(&ireq, 0, sizeof(ireq));
3231         strlcpy(ireq.i_name, name, sizeof(ireq.i_name));
3232         ireq.i_type = IEEE80211_IOC_SCAN_REQ;
3233
3234         memset(&sr, 0, sizeof(sr));
3235         sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
3236                     | IEEE80211_IOC_SCAN_NOPICK
3237                     | IEEE80211_IOC_SCAN_ONCE;
3238         sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
3239         sr.sr_nssid = 0;
3240
3241         ireq.i_data = &sr;
3242         ireq.i_len = sizeof(sr);
3243         /* NB: only root can trigger a scan so ignore errors */
3244         if (ioctl(s, SIOCS80211, &ireq) >= 0) {
3245                 char buf[2048];
3246                 struct if_announcemsghdr *ifan;
3247                 struct rt_msghdr *rtm;
3248
3249                 do {
3250                         if (read(sroute, buf, sizeof(buf)) < 0) {
3251                                 perror("read(PF_ROUTE)");
3252                                 break;
3253                         }
3254                         rtm = (struct rt_msghdr *) buf;
3255                         if (rtm->rtm_version != RTM_VERSION)
3256                                 break;
3257                         ifan = (struct if_announcemsghdr *) rtm;
3258                 } while (rtm->rtm_type != RTM_IEEE80211 ||
3259                     ifan->ifan_what != RTM_IEEE80211_SCAN);
3260         }
3261         close(sroute);
3262 }
3263
3264 static
3265 DECL_CMD_FUNC(set80211scan, val, d)
3266 {
3267         scan_and_wait(s);
3268         list_scan(s, 0);
3269 }
3270
3271 static enum ieee80211_opmode get80211opmode(int s);
3272
3273 static int
3274 gettxseq(const struct ieee80211req_sta_info *si)
3275 {
3276         int i, txseq;
3277
3278         if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
3279                 return si->isi_txseqs[0];
3280         /* XXX not right but usually what folks want */
3281         txseq = 0;
3282         for (i = 0; i < IEEE80211_TID_SIZE; i++)
3283                 if (si->isi_txseqs[i] > txseq)
3284                         txseq = si->isi_txseqs[i];
3285         return txseq;
3286 }
3287
3288 static int
3289 getrxseq(const struct ieee80211req_sta_info *si)
3290 {
3291         int i, rxseq;
3292
3293         if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
3294                 return si->isi_rxseqs[0];
3295         /* XXX not right but usually what folks want */
3296         rxseq = 0;
3297         for (i = 0; i < IEEE80211_TID_SIZE; i++)
3298                 if (si->isi_rxseqs[i] > rxseq)
3299                         rxseq = si->isi_rxseqs[i];
3300         return rxseq;
3301 }
3302
3303 static void
3304 list_stations(int s)
3305 {
3306         union {
3307                 struct ieee80211req_sta_req req;
3308                 uint8_t buf[24*1024];
3309         } u;
3310         enum ieee80211_opmode opmode = get80211opmode(s);
3311         const uint8_t *cp;
3312         size_t len;
3313
3314         /* broadcast address =>'s get all stations */
3315         memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
3316         if (opmode == IEEE80211_M_STA) {
3317                 /*
3318                  * Get information about the associated AP.
3319                  */
3320                 get80211(s, IEEE80211_IOC_BSSID,
3321                          u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
3322         }
3323         if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
3324                 errx(1, "unable to get station information");
3325         if (len < sizeof(struct ieee80211req_sta_info))
3326                 return;
3327
3328         getchaninfo(s);
3329
3330         if (opmode == IEEE80211_M_MBSS) {
3331                 printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
3332                         , "ADDR"
3333                         , "CHAN"
3334                         , "LOCAL"
3335                         , "PEER"
3336                         , "STATE"
3337                         , "RATE"
3338                         , "RSSI"
3339                         , "IDLE"
3340                         , "TXSEQ"
3341                         , "RXSEQ"
3342                 );
3343         } else {
3344                 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
3345                         , "ADDR"
3346                         , "AID"
3347                         , "CHAN"
3348                         , "RATE"
3349                         , "RSSI"
3350                         , "IDLE"
3351                         , "TXSEQ"
3352                         , "RXSEQ"
3353                         , "CAPS"
3354                         , "FLAG"
3355                 );
3356         }
3357         cp = (const uint8_t *) u.req.info;
3358         do {
3359                 const struct ieee80211req_sta_info *si;
3360
3361                 si = (const struct ieee80211req_sta_info *) cp;
3362                 if (si->isi_len < sizeof(*si))
3363                         break;
3364                 if (opmode == IEEE80211_M_MBSS) {
3365                         printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
3366                                 , ether_ntoa((const struct ether_addr*)
3367                                     si->isi_macaddr)
3368                                 , ieee80211_mhz2ieee(si->isi_freq,
3369                                     si->isi_flags)
3370                                 , si->isi_localid
3371                                 , si->isi_peerid
3372                                 , mesh_linkstate_string(si->isi_peerstate)
3373                                 , si->isi_txmbps/2
3374                                 , si->isi_rssi/2.
3375                                 , si->isi_inact
3376                                 , gettxseq(si)
3377                                 , getrxseq(si)
3378                         );
3379                 } else {
3380                         printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
3381                                 , ether_ntoa((const struct ether_addr*)
3382                                     si->isi_macaddr)
3383                                 , IEEE80211_AID(si->isi_associd)
3384                                 , ieee80211_mhz2ieee(si->isi_freq,
3385                                     si->isi_flags)
3386                                 , si->isi_txmbps/2
3387                                 , si->isi_rssi/2.
3388                                 , si->isi_inact
3389                                 , gettxseq(si)
3390                                 , getrxseq(si)
3391                                 , getcaps(si->isi_capinfo)
3392                                 , getflags(si->isi_state)
3393                         );
3394                 }
3395                 printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
3396                 printmimo(&si->isi_mimo);
3397                 printf("\n");
3398                 cp += si->isi_len, len -= si->isi_len;
3399         } while (len >= sizeof(struct ieee80211req_sta_info));
3400 }
3401
3402 static const char *
3403 mesh_linkstate_string(uint8_t state)
3404 {
3405         static const char *state_names[] = {
3406             [0] = "IDLE",
3407             [1] = "OPEN-TX",
3408             [2] = "OPEN-RX",
3409             [3] = "CONF-RX",
3410             [4] = "ESTAB",
3411             [5] = "HOLDING",
3412         };
3413
3414         if (state >= nitems(state_names)) {
3415                 static char buf[10];
3416                 snprintf(buf, sizeof(buf), "#%u", state);
3417                 return buf;
3418         } else {
3419                 return state_names[state];
3420         }
3421 }
3422
3423 static const char *
3424 get_chaninfo(const struct ieee80211_channel *c, int precise,
3425         char buf[], size_t bsize)
3426 {
3427         buf[0] = '\0';
3428         if (IEEE80211_IS_CHAN_FHSS(c))
3429                 strlcat(buf, " FHSS", bsize);
3430         if (IEEE80211_IS_CHAN_A(c))
3431                 strlcat(buf, " 11a", bsize);
3432         else if (IEEE80211_IS_CHAN_ANYG(c))
3433                 strlcat(buf, " 11g", bsize);
3434         else if (IEEE80211_IS_CHAN_B(c))
3435                 strlcat(buf, " 11b", bsize);
3436         if (IEEE80211_IS_CHAN_HALF(c))
3437                 strlcat(buf, "/10MHz", bsize);
3438         if (IEEE80211_IS_CHAN_QUARTER(c))
3439                 strlcat(buf, "/5MHz", bsize);
3440         if (IEEE80211_IS_CHAN_TURBO(c))
3441                 strlcat(buf, " Turbo", bsize);
3442         if (precise) {
3443                 if (IEEE80211_IS_CHAN_HT20(c))
3444                         strlcat(buf, " ht/20", bsize);
3445                 else if (IEEE80211_IS_CHAN_HT40D(c))
3446                         strlcat(buf, " ht/40-", bsize);
3447                 else if (IEEE80211_IS_CHAN_HT40U(c))
3448                         strlcat(buf, " ht/40+", bsize);
3449         } else {
3450                 if (IEEE80211_IS_CHAN_HT(c))
3451                         strlcat(buf, " ht", bsize);
3452         }
3453         return buf;
3454 }
3455
3456 static void
3457 print_chaninfo(const struct ieee80211_channel *c, int verb)
3458 {
3459         char buf[14];
3460
3461         printf("Channel %3u : %u%c MHz%-14.14s",
3462                 ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
3463                 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
3464                 get_chaninfo(c, verb, buf, sizeof(buf)));
3465 }
3466
3467 static int
3468 chanpref(const struct ieee80211_channel *c)
3469 {
3470         if (IEEE80211_IS_CHAN_HT40(c))
3471                 return 40;
3472         if (IEEE80211_IS_CHAN_HT20(c))
3473                 return 30;
3474         if (IEEE80211_IS_CHAN_HALF(c))
3475                 return 10;
3476         if (IEEE80211_IS_CHAN_QUARTER(c))
3477                 return 5;
3478         if (IEEE80211_IS_CHAN_TURBO(c))
3479                 return 25;
3480         if (IEEE80211_IS_CHAN_A(c))
3481                 return 20;
3482         if (IEEE80211_IS_CHAN_G(c))
3483                 return 20;
3484         if (IEEE80211_IS_CHAN_B(c))
3485                 return 15;
3486         if (IEEE80211_IS_CHAN_PUREG(c))
3487                 return 15;
3488         return 0;
3489 }
3490
3491 static void
3492 print_channels(int s, const struct ieee80211req_chaninfo *chans,
3493         int allchans, int verb)
3494 {
3495         struct ieee80211req_chaninfo *achans;
3496         uint8_t reported[IEEE80211_CHAN_BYTES];
3497         const struct ieee80211_channel *c;
3498         size_t i, half;
3499
3500         achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
3501         if (achans == NULL)
3502                 errx(1, "no space for active channel list");
3503         achans->ic_nchans = 0;
3504         memset(reported, 0, sizeof(reported));
3505         if (!allchans) {
3506                 struct ieee80211req_chanlist active;
3507
3508                 if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
3509                         errx(1, "unable to get active channel list");
3510                 for (i = 0; i < chans->ic_nchans; i++) {
3511                         c = &chans->ic_chans[i];
3512                         if (!isset(active.ic_channels, c->ic_ieee))
3513                                 continue;
3514                         /*
3515                          * Suppress compatible duplicates unless
3516                          * verbose.  The kernel gives us it's
3517                          * complete channel list which has separate
3518                          * entries for 11g/11b and 11a/turbo.
3519                          */
3520                         if (isset(reported, c->ic_ieee) && !verb) {
3521                                 /* XXX we assume duplicates are adjacent */
3522                                 achans->ic_chans[achans->ic_nchans-1] = *c;
3523                         } else {
3524                                 achans->ic_chans[achans->ic_nchans++] = *c;
3525                                 setbit(reported, c->ic_ieee);
3526                         }
3527                 }
3528         } else {
3529                 for (i = 0; i < chans->ic_nchans; i++) {
3530                         c = &chans->ic_chans[i];
3531                         /* suppress duplicates as above */
3532                         if (isset(reported, c->ic_ieee) && !verb) {
3533                                 /* XXX we assume duplicates are adjacent */
3534                                 struct ieee80211_channel *a =
3535                                     &achans->ic_chans[achans->ic_nchans-1];
3536                                 if (chanpref(c) > chanpref(a))
3537                                         *a = *c;
3538                         } else {
3539                                 achans->ic_chans[achans->ic_nchans++] = *c;
3540                                 setbit(reported, c->ic_ieee);
3541                         }
3542                 }
3543         }
3544         half = achans->ic_nchans / 2;
3545         if (achans->ic_nchans % 2)
3546                 half++;
3547
3548         for (i = 0; i < achans->ic_nchans / 2; i++) {
3549                 print_chaninfo(&achans->ic_chans[i], verb);
3550                 print_chaninfo(&achans->ic_chans[half+i], verb);
3551                 printf("\n");
3552         }
3553         if (achans->ic_nchans % 2) {
3554                 print_chaninfo(&achans->ic_chans[i], verb);
3555                 printf("\n");
3556         }
3557         free(achans);
3558 }
3559
3560 static void
3561 list_channels(int s, int allchans)
3562 {
3563         getchaninfo(s);
3564         print_channels(s, chaninfo, allchans, verbose);
3565 }
3566
3567 static void
3568 print_txpow(const struct ieee80211_channel *c)
3569 {
3570         printf("Channel %3u : %u MHz %3.1f reg %2d  ",
3571             c->ic_ieee, c->ic_freq,
3572             c->ic_maxpower/2., c->ic_maxregpower);
3573 }
3574
3575 static void
3576 print_txpow_verbose(const struct ieee80211_channel *c)
3577 {
3578         print_chaninfo(c, 1);
3579         printf("min %4.1f dBm  max %3.1f dBm  reg %2d dBm",
3580             c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
3581         /* indicate where regulatory cap limits power use */
3582         if (c->ic_maxpower > 2*c->ic_maxregpower)
3583                 printf(" <");
3584 }
3585
3586 static void
3587 list_txpow(int s)
3588 {
3589         struct ieee80211req_chaninfo *achans;
3590         uint8_t reported[IEEE80211_CHAN_BYTES];
3591         struct ieee80211_channel *c, *prev;
3592         size_t i, half;
3593
3594         getchaninfo(s);
3595         achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
3596         if (achans == NULL)
3597                 errx(1, "no space for active channel list");
3598         achans->ic_nchans = 0;
3599         memset(reported, 0, sizeof(reported));
3600         for (i = 0; i < chaninfo->ic_nchans; i++) {
3601                 c = &chaninfo->ic_chans[i];
3602                 /* suppress duplicates as above */
3603                 if (isset(reported, c->ic_ieee) && !verbose) {
3604                         /* XXX we assume duplicates are adjacent */
3605                         prev = &achans->ic_chans[achans->ic_nchans-1];
3606                         /* display highest power on channel */
3607                         if (c->ic_maxpower > prev->ic_maxpower)
3608                                 *prev = *c;
3609                 } else {
3610                         achans->ic_chans[achans->ic_nchans++] = *c;
3611                         setbit(reported, c->ic_ieee);
3612                 }
3613         }
3614         if (!verbose) {
3615                 half = achans->ic_nchans / 2;
3616                 if (achans->ic_nchans % 2)
3617                         half++;
3618
3619                 for (i = 0; i < achans->ic_nchans / 2; i++) {
3620                         print_txpow(&achans->ic_chans[i]);
3621                         print_txpow(&achans->ic_chans[half+i]);
3622                         printf("\n");
3623                 }
3624                 if (achans->ic_nchans % 2) {
3625                         print_txpow(&achans->ic_chans[i]);
3626                         printf("\n");
3627                 }
3628         } else {
3629                 for (i = 0; i < achans->ic_nchans; i++) {
3630                         print_txpow_verbose(&achans->ic_chans[i]);
3631                         printf("\n");
3632                 }
3633         }
3634         free(achans);
3635 }
3636
3637 static void
3638 list_keys(int s)
3639 {
3640 }
3641
3642 #define IEEE80211_C_BITS \
3643         "\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
3644         "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
3645         "\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
3646         "\37TXFRAG\40TDMA"
3647
3648 static void
3649 list_capabilities(int s)
3650 {
3651         struct ieee80211_devcaps_req *dc;
3652
3653         if (verbose)
3654                 dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
3655         else
3656                 dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
3657         if (dc == NULL)
3658                 errx(1, "no space for device capabilities");
3659         dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
3660         getdevcaps(s, dc);
3661         printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
3662         if (dc->dc_cryptocaps != 0 || verbose) {
3663                 putchar('\n');
3664                 printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
3665         }
3666         if (dc->dc_htcaps != 0 || verbose) {
3667                 putchar('\n');
3668                 printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
3669         }
3670         putchar('\n');
3671         if (verbose) {
3672                 chaninfo = &dc->dc_chaninfo;    /* XXX */
3673                 print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose);
3674         }
3675         free(dc);
3676 }
3677
3678 static int
3679 get80211wme(int s, int param, int ac, int *val)
3680 {
3681         struct ieee80211req ireq;
3682
3683         memset(&ireq, 0, sizeof(ireq));
3684         strlcpy(ireq.i_name, name, sizeof(ireq.i_name));
3685         ireq.i_type = param;
3686         ireq.i_len = ac;
3687         if (ioctl(s, SIOCG80211, &ireq) < 0) {
3688                 warn("cannot get WME parameter %d, ac %d%s",
3689                     param, ac & IEEE80211_WMEPARAM_VAL,
3690                     ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
3691                 return -1;
3692         }
3693         *val = ireq.i_val;
3694         return 0;
3695 }
3696
3697 static void
3698 list_wme_aci(int s, const char *tag, int ac)
3699 {
3700         int val;
3701
3702         printf("\t%s", tag);
3703
3704         /* show WME BSS parameters */
3705         if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
3706                 printf(" cwmin %2u", val);
3707         if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
3708                 printf(" cwmax %2u", val);
3709         if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
3710                 printf(" aifs %2u", val);
3711         if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
3712                 printf(" txopLimit %3u", val);
3713         if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
3714                 if (val)
3715                         printf(" acm");
3716                 else if (verbose)
3717                         printf(" -acm");
3718         }
3719         /* !BSS only */
3720         if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
3721                 if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
3722                         if (!val)
3723                                 printf(" -ack");
3724                         else if (verbose)
3725                                 printf(" ack");
3726                 }
3727         }
3728         printf("\n");
3729 }
3730
3731 static void
3732 list_wme(int s)
3733 {
3734         static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
3735         int ac;
3736
3737         if (verbose) {
3738                 /* display both BSS and local settings */
3739                 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
3740         again:
3741                         if (ac & IEEE80211_WMEPARAM_BSS)
3742                                 list_wme_aci(s, "     ", ac);
3743                         else
3744                                 list_wme_aci(s, acnames[ac], ac);
3745                         if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
3746                                 ac |= IEEE80211_WMEPARAM_BSS;
3747                                 goto again;
3748                         } else
3749                                 ac &= ~IEEE80211_WMEPARAM_BSS;
3750                 }
3751         } else {
3752                 /* display only channel settings */
3753                 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++)
3754                         list_wme_aci(s, acnames[ac], ac);
3755         }
3756 }
3757
3758 static void
3759 list_roam(int s)
3760 {
3761         const struct ieee80211_roamparam *rp;
3762         int mode;
3763
3764         getroam(s);
3765         for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
3766                 rp = &roamparams.params[mode];
3767                 if (rp->rssi == 0 && rp->rate == 0)
3768                         continue;
3769                 if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
3770                         if (rp->rssi & 1)
3771                                 LINE_CHECK("roam:%-7.7s rssi %2u.5dBm  MCS %2u    ",
3772                                     modename[mode], rp->rssi/2,
3773                                     rp->rate &~ IEEE80211_RATE_MCS);
3774                         else
3775                                 LINE_CHECK("roam:%-7.7s rssi %4udBm  MCS %2u    ",
3776                                     modename[mode], rp->rssi/2,
3777                                     rp->rate &~ IEEE80211_RATE_MCS);
3778                 } else {
3779                         if (rp->rssi & 1)
3780                                 LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s",
3781                                     modename[mode], rp->rssi/2, rp->rate/2);
3782                         else
3783                                 LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s",
3784                                     modename[mode], rp->rssi/2, rp->rate/2);
3785                 }
3786         }
3787 }
3788
3789 static void
3790 list_txparams(int s)
3791 {
3792         const struct ieee80211_txparam *tp;
3793         int mode;
3794
3795         gettxparams(s);
3796         for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
3797                 tp = &txparams.params[mode];
3798                 if (tp->mgmtrate == 0 && tp->mcastrate == 0)
3799                         continue;
3800                 if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
3801                         if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
3802                                 LINE_CHECK("%-7.7s ucast NONE    mgmt %2u MCS  "
3803                                     "mcast %2u MCS  maxretry %u",
3804                                     modename[mode],
3805                                     tp->mgmtrate &~ IEEE80211_RATE_MCS,
3806                                     tp->mcastrate &~ IEEE80211_RATE_MCS,
3807                                     tp->maxretry);
3808                         else
3809                                 LINE_CHECK("%-7.7s ucast %2u MCS  mgmt %2u MCS  "
3810                                     "mcast %2u MCS  maxretry %u",
3811                                     modename[mode],
3812                                     tp->ucastrate &~ IEEE80211_RATE_MCS,
3813                                     tp->mgmtrate &~ IEEE80211_RATE_MCS,
3814                                     tp->mcastrate &~ IEEE80211_RATE_MCS,
3815                                     tp->maxretry);
3816                 } else {
3817                         if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
3818                                 LINE_CHECK("%-7.7s ucast NONE    mgmt %2u Mb/s "
3819                                     "mcast %2u Mb/s maxretry %u",
3820                                     modename[mode],
3821                                     tp->mgmtrate/2,
3822                                     tp->mcastrate/2, tp->maxretry);
3823                         else
3824                                 LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s "
3825                                     "mcast %2u Mb/s maxretry %u",
3826                                     modename[mode],
3827                                     tp->ucastrate/2, tp->mgmtrate/2,
3828                                     tp->mcastrate/2, tp->maxretry);
3829                 }
3830         }
3831 }
3832
3833 static void
3834 printpolicy(int policy)
3835 {
3836         switch (policy) {
3837         case IEEE80211_MACCMD_POLICY_OPEN:
3838                 printf("policy: open\n");
3839                 break;
3840         case IEEE80211_MACCMD_POLICY_ALLOW:
3841                 printf("policy: allow\n");
3842                 break;
3843         case IEEE80211_MACCMD_POLICY_DENY:
3844                 printf("policy: deny\n");
3845                 break;
3846         case IEEE80211_MACCMD_POLICY_RADIUS:
3847                 printf("policy: radius\n");
3848                 break;
3849         default:
3850                 printf("policy: unknown (%u)\n", policy);
3851                 break;
3852         }
3853 }
3854
3855 static void
3856 list_mac(int s)
3857 {
3858         struct ieee80211req ireq;
3859         struct ieee80211req_maclist *acllist;
3860         int i, nacls, policy, len;
3861         uint8_t *data;
3862         char c;
3863
3864         memset(&ireq, 0, sizeof(ireq));
3865         strlcpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
3866         ireq.i_type = IEEE80211_IOC_MACCMD;
3867         ireq.i_val = IEEE80211_MACCMD_POLICY;
3868         if (ioctl(s, SIOCG80211, &ireq) < 0) {
3869                 if (errno == EINVAL) {
3870                         printf("No acl policy loaded\n");
3871                         return;
3872                 }
3873                 err(1, "unable to get mac policy");
3874         }
3875         policy = ireq.i_val;
3876         i