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