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
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
27 * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 203970 2010-02-16 21:39:20Z imp $
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
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>
66 #include <net/ethernet.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>
97 #include "regdomain.h"
99 #ifndef IEEE80211_FIXED_RATE_NONE
100 #define IEEE80211_FIXED_RATE_NONE 0xff
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 */
126 #define MAXCHAN 1536 /* max 1.5K channels */
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;
179 iseq(const char *a
, const char *b
)
181 return (strcasecmp(a
, b
) == 0);
185 ismatch(const char *a
, const char *b
)
187 return (strncasecmp(a
, b
, strlen(b
)) == 0);
195 if (get80211val(s
, IEEE80211_IOC_HTCONF
, &htconf
) < 0)
196 warn("unable to get HT configuration information");
201 * Collect channel info from the kernel. We use this (mostly)
202 * to handle mapping between frequency and IEEE channel number.
207 if (chaninfo
!= NULL
)
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
);
219 static struct regdata
*
222 static struct regdata
*rdp
= NULL
;
225 rdp
= lib80211_alloc_regdata();
227 errx(-1, "missing or corrupted regdomain database");
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
240 canpromote(u_int i
, uint32_t from
, uint32_t to
)
242 const struct ieee80211_channel
*fc
= &chaninfo
->ic_chans
[i
];
245 if ((fc
->ic_flags
& from
) != from
)
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
)
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
];
256 tc
->ic_freq
== fc
->ic_freq
&& (tc
->ic_flags
& to
) == to
)
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.
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
) :
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
);
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
);
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
);
322 mapfreq(struct ieee80211_channel
*chan
, uint16_t freq
, uint32_t flags
)
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
) {
331 /* when ambiguous promote to ``best'' */
332 c
= &chaninfo
->ic_chans
[promote(i
)];
338 errx(1, "unknown/undefined frequency %u/0x%x", freq
, flags
);
342 mapchan(struct ieee80211_channel
*chan
, uint8_t ieee
, uint32_t flags
)
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
) {
351 /* when ambiguous promote to ``best'' */
352 c
= &chaninfo
->ic_chans
[promote(i
)];
358 errx(1, "unknown/undefined channel number %d flags 0x%x", ieee
, flags
);
361 static const struct ieee80211_channel
*
366 if (get80211(s
, IEEE80211_IOC_CURCHAN
, &curchan
, sizeof(curchan
)) < 0) {
368 /* fall back to legacy ioctl */
369 if (get80211val(s
, IEEE80211_IOC_CHANNEL
, &val
) < 0)
370 err(-1, "cannot figure out current channel");
372 mapchan(&curchan
, val
, 0);
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
;
411 if (get80211(s
, IEEE80211_IOC_ROAM
,
412 &roamparams
, sizeof(roamparams
)) < 0)
413 err(1, "unable to get roaming parameters");
418 setroam_cb(int s
, void *arg
)
420 struct ieee80211_roamparams_req
*roam
= arg
;
421 set80211(s
, IEEE80211_IOC_ROAM
, 0, sizeof(*roam
), roam
);
429 if (get80211(s
, IEEE80211_IOC_TXPARAMS
,
430 &txparams
, sizeof(txparams
)) < 0)
431 err(1, "unable to get transmit parameters");
436 settxparams_cb(int s
, void *arg
)
438 struct ieee80211_txparams_req
*txp
= arg
;
439 set80211(s
, IEEE80211_IOC_TXPARAMS
, 0, sizeof(*txp
), txp
);
447 if (get80211(s
, IEEE80211_IOC_REGDOMAIN
,
448 ®domain
, sizeof(regdomain
)) < 0)
449 err(1, "unable to get regulatory domain info");
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");
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
);
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
);
497 errx(1, "country %s (%s) is not usable with "
498 "regdomain %d", cc
->isoname
, cc
->name
,
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
,
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
));
514 errx(1, "no space for device capabilities");
515 dc
->dc_chaninfo
.ic_nchans
= MAXCHAN
;
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 */,
528 req
= malloc(IEEE80211_REGDOMAIN_SIZE(dc
->dc_chaninfo
.ic_nchans
));
530 errx(1, "no space for regdomain request");
532 regdomain_makechannels(req
, dc
);
535 print_regdomain(rd
, 1/*verbose*/);
537 /* blech, reallocate channel list for new data */
538 if (chaninfo
!= NULL
)
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 */,
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
);
557 ieee80211_mhz2ieee(int freq
, int flags
)
559 struct ieee80211_channel chan
;
560 mapfreq(&chan
, freq
, flags
);
565 isanyarg(const char *arg
)
567 return (ismatch(arg
, "-") ||
568 ismatch(arg
, "any") ||
569 ismatch(arg
, "off"));
573 set80211ssid(const char *val
, int d __unused
, int s
,
574 const struct afswtch
*rafp __unused
)
578 u_int8_t data
[IEEE80211_NWID_LEN
];
582 if (len
> 2 && isdigit((int)val
[0]) && val
[1] == ':') {
587 memset(data
, 0, sizeof(data
));
588 len
= (int)sizeof(data
);
589 if (get_string(val
, NULL
, data
, &len
) == NULL
)
592 set80211(s
, IEEE80211_IOC_SSID
, ssid
, len
, data
);
596 set80211meshid(const char *val
, int d __unused
, int s
,
597 const struct afswtch
*rafp __unused
)
600 u_int8_t data
[IEEE80211_NWID_LEN
];
602 memset(data
, 0, sizeof(data
));
604 if (get_string(val
, NULL
, data
, &len
) == NULL
)
607 set80211(s
, IEEE80211_IOC_MESH_ID
, 0, len
, data
);
611 set80211stationname(const char *val
, int d __unused
, int s
,
612 const struct afswtch
*rafp __unused
)
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.
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.
637 getchannelflags(const char *val
, int freq
)
639 #define _CHAN_HT 0x80000000
645 cp
= strchr(val
, ':');
647 for (cp
++; isalpha((int) *cp
); cp
++) {
648 /* accept mixed case */
653 case 'a': /* 802.11a */
654 flags
|= IEEE80211_CHAN_A
;
656 case 'b': /* 802.11b */
657 flags
|= IEEE80211_CHAN_B
;
659 case 'g': /* 802.11g */
660 flags
|= IEEE80211_CHAN_G
;
662 case 'h': /* ht = 802.11n */
663 case 'n': /* 802.11n */
664 flags
|= _CHAN_HT
; /* NB: private */
666 case 'd': /* dt = Atheros Dynamic Turbo */
667 flags
|= IEEE80211_CHAN_TURBO
;
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
;
674 case 's': /* st = Atheros Static Turbo */
675 flags
|= IEEE80211_CHAN_STURBO
;
678 errx(-1, "%s: Invalid channel attribute %c\n",
683 cp
= strchr(val
, '/');
686 u_long cw
= strtoul(cp
+1, &ep
, 10);
690 flags
|= IEEE80211_CHAN_QUARTER
;
693 flags
|= IEEE80211_CHAN_HALF
;
696 /* NB: this may be removed below */
697 flags
|= IEEE80211_CHAN_HT20
;
700 if (ep
!= NULL
&& *ep
== '+')
701 flags
|= IEEE80211_CHAN_HT40U
;
702 else if (ep
!= NULL
&& *ep
== '-')
703 flags
|= IEEE80211_CHAN_HT40D
;
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
;
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.
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).
735 mapfreq(&chan
, freq
, 0);
737 mapchan(&chan
, freq
, 0);
738 flags
|= (chan
.ic_flags
& IEEE80211_CHAN_HT
);
746 getchannel(int s
, struct ieee80211_channel
*chan
, const char *val
)
751 memset(chan
, 0, sizeof(*chan
));
753 chan
->ic_freq
= IEEE80211_CHAN_ANY
;
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
);
768 mapchan(chan
, v
, flags
);
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
);
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
);
791 set80211(s
, IEEE80211_IOC_CHANSWITCH
, 0, sizeof(csr
), &csr
);
795 set80211authmode(const char *val
, int d __unused
, int s
,
796 const struct afswtch
*rafp __unused
)
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
;
811 errx(1, "unknown authmode");
814 set80211(s
, IEEE80211_IOC_AUTHMODE
, mode
, 0, NULL
);
818 set80211powersavemode(const char *val
, int d __unused
, int s
,
819 const struct afswtch
*rafp __unused
)
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
;
834 errx(1, "unknown powersavemode");
837 set80211(s
, IEEE80211_IOC_POWERSAVE
, mode
, 0, NULL
);
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
),
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
);
857 set80211wepmode(const char *val
, int d __unused
, int s
,
858 const struct afswtch
*rafp __unused
)
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
;
869 errx(1, "unknown wep mode");
872 set80211(s
, IEEE80211_IOC_WEP
, mode
, 0, NULL
);
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
);
883 isundefarg(const char *arg
)
885 return (strcmp(arg
, "-") == 0 || ismatch(arg
, "undef"));
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),
898 set80211wepkey(const char *val
, int d __unused
, int s
,
899 const struct afswtch
*rafp __unused
)
903 u_int8_t data
[IEEE80211_KEYBUF_SIZE
];
905 if (isdigit((int)val
[0]) && val
[1] == ':') {
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.
923 set80211nwkey(const char *val
, int d __unused
, int s
,
924 const struct afswtch
*rafp __unused
)
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;
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
);
943 set80211(s
, IEEE80211_IOC_WEPKEY
, i
, len
, data
);
946 memset(data
, 0, sizeof(data
));
947 len
= (int)sizeof(data
);
948 get_string(val
, NULL
, data
, &len
);
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
);
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
)),
971 set80211protmode(const char *val
, int d __unused
, int s
,
972 const struct afswtch
*rafp __unused
)
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
;
983 errx(1, "unknown protection mode");
986 set80211(s
, IEEE80211_IOC_PROTMODE
, mode
, 0, NULL
);
990 set80211htprotmode(const char *val
, int d __unused
, int s
,
991 const struct afswtch
*rafp __unused
)
995 if (iseq(val
, "off")) {
996 mode
= IEEE80211_PROTMODE_OFF
;
997 } else if (ismatch(val
, "rts")) {
998 mode
= IEEE80211_PROTMODE_RTSCTS
;
1000 errx(1, "unknown protection mode");
1003 set80211(s
, IEEE80211_IOC_HTPROTMODE
, mode
, 0, NULL
);
1007 set80211txpower(const char *val
, int d __unused
, int s
,
1008 const struct afswtch
*rafp __unused
)
1010 double v
= atof(val
);
1013 txpow
= (int) (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
1024 set80211roaming(const char *val
, int d __unused
, int s
,
1025 const struct afswtch
*rafp __unused
)
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
;
1036 errx(1, "unknown roaming mode");
1038 set80211(s
, IEEE80211_IOC_ROAMING
, mode
, 0, NULL
);
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
);
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
);
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
);
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
);
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
);
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
;
1085 errx(1, "strdup failed");
1086 memset(&chanlist
, 0, sizeof(chanlist
));
1089 int first
, last
, f
, c
;
1091 tp
= strchr(cp
, ',');
1094 switch (sscanf(cp
, "%u-%u", &first
, &last
)) {
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
);
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
);
1109 errx(-1, "void channel range, %u > %u",
1111 for (f
= first
; f
<= last
; f
++)
1112 setbit(chanlist
.ic_channels
, f
);
1124 set80211(s
, IEEE80211_IOC_CHANLIST
, 0, sizeof(chanlist
), &chanlist
);
1128 set80211bssid(const char *val
, int d __unused
, int s
,
1129 const struct afswtch
*rafp __unused
)
1131 if (!isanyarg(val
)) {
1133 struct sockaddr_dl sdl
;
1135 temp
= malloc(strlen(val
) + 2); /* ':' and '\0' */
1137 errx(1, "malloc failed");
1139 strcpy(temp
+ 1, val
);
1140 sdl
.sdl_len
= sizeof(sdl
);
1141 link_addr(temp
, &sdl
);
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
));
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
);
1156 getac(const char *ac
)
1158 if (iseq(ac
, "ac_be") || iseq(ac
, "be"))
1160 if (iseq(ac
, "ac_bk") || iseq(ac
, "bk"))
1162 if (iseq(ac
, "ac_vi") || iseq(ac
, "vi"))
1164 if (iseq(ac
, "ac_vo") || iseq(ac
, "vo"))
1166 errx(1, "unknown wme access class %s", ac
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1272 set80211macmac(int s
, int op
, const char *val
)
1275 struct sockaddr_dl sdl
;
1277 temp
= malloc(strlen(val
) + 2); /* ':' and '\0' */
1279 errx(1, "malloc failed");
1281 strcpy(temp
+ 1, val
);
1282 sdl
.sdl_len
= sizeof(sdl
);
1283 link_addr(temp
, &sdl
);
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
));
1291 set80211addmac(const char *val
, int d __unused
, int s
,
1292 const struct afswtch
*afp __unused
)
1294 set80211macmac(s
, IEEE80211_IOC_ADDMAC
, val
);
1298 set80211delmac(const char *val
, int d __unused
, int s
,
1299 const struct afswtch
*afp __unused
)
1301 set80211macmac(s
, IEEE80211_IOC_DELMAC
, val
);
1305 set80211kickmac(const char *val
, int d __unused
, int s
,
1306 const struct afswtch
*afp __unused
)
1309 struct sockaddr_dl sdl
;
1310 struct ieee80211req_mlme mlme
;
1312 temp
= malloc(strlen(val
) + 2); /* ':' and '\0' */
1314 errx(1, "malloc failed");
1316 strcpy(temp
+ 1, val
);
1317 sdl
.sdl_len
= sizeof(sdl
);
1318 link_addr(temp
, &sdl
);
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
);
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
);
1337 set80211meshrtmac(int s
, int req
, const char *val
)
1340 struct sockaddr_dl sdl
;
1342 temp
= malloc(strlen(val
) + 2); /* ':' and '\0' */
1344 errx(1, "malloc failed");
1346 strcpy(temp
+ 1, val
);
1347 sdl
.sdl_len
= sizeof(sdl
);
1348 link_addr(temp
, &sdl
);
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
));
1357 set80211addmeshrt(const char *val
, int d __unused
, int s
,
1358 const struct afswtch
*afp __unused
)
1360 set80211meshrtmac(s
, IEEE80211_MESH_RTCMD_ADD
, val
);
1364 set80211delmeshrt(const char *val
, int d __unused
, int s
,
1365 const struct afswtch
*afp __unused
)
1367 set80211meshrtmac(s
, IEEE80211_MESH_RTCMD_DELETE
, val
);
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
);
1378 set80211hwmprootmode(const char *val
, int d __unused
, int s
,
1379 const struct afswtch
*afp __unused
)
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
;
1390 mode
= IEEE80211_HWMP_ROOTMODE_DISABLED
;
1391 set80211(s
, IEEE80211_IOC_HWMP_ROOTMODE
, mode
, 0, NULL
);
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
);
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
);
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
);
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
);
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
);
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.
1447 getmodeflags(const char *val
)
1454 cp
= strchr(val
, ':');
1456 for (cp
++; isalpha((int) *cp
); cp
++) {
1457 /* accept mixed case */
1462 case 'a': /* 802.11a */
1463 flags
|= IEEE80211_CHAN_A
;
1465 case 'b': /* 802.11b */
1466 flags
|= IEEE80211_CHAN_B
;
1468 case 'g': /* 802.11g */
1469 flags
|= IEEE80211_CHAN_G
;
1471 case 'n': /* 802.11n */
1472 flags
|= IEEE80211_CHAN_HT
;
1474 case 'd': /* dt = Atheros Dynamic Turbo */
1475 flags
|= IEEE80211_CHAN_TURBO
;
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
;
1482 case 's': /* st = Atheros Static Turbo */
1483 flags
|= IEEE80211_CHAN_STURBO
;
1485 case 'h': /* 1/2-width channels */
1486 flags
|= IEEE80211_CHAN_HALF
;
1488 case 'q': /* 1/4-width channels */
1489 flags
|= IEEE80211_CHAN_QUARTER
;
1492 errx(-1, "%s: Invalid mode attribute %c\n",
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; \
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; \
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; \
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; \
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; \
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); \
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); \
1569 set80211roamrssi(const char *val
, int d __unused
, int s
,
1570 const struct afswtch
*afp __unused
)
1572 double v
= atof(val
);
1577 errx(-1, "invalid rssi (must be .5 dBm units)");
1578 flags
= getmodeflags(val
);
1580 if (flags
== 0) { /* NB: no flags => current channel */
1581 flags
= getcurchan(s
)->ic_flags
;
1582 _APPLY1(flags
, roamparams
, rssi
, rssi
);
1584 _APPLY(flags
, roamparams
, rssi
, rssi
);
1585 callback_register(setroam_cb
, &roamparams
);
1589 getrate(const char *val
, const char *tag
)
1591 double v
= atof(val
);
1596 errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag
);
1597 return rate
; /* NB: returns 2x the specified value */
1601 set80211roamrate(const char *val
, int d __unused
, int s
,
1602 const struct afswtch
*afp __unused
)
1606 rate
= getrate(val
, "roam");
1607 flags
= getmodeflags(val
);
1609 if (flags
== 0) { /* NB: no flags => current channel */
1610 flags
= getcurchan(s
)->ic_flags
;
1611 _APPLY_RATE1(flags
, roamparams
, rate
, rate
);
1613 _APPLY_RATE(flags
, roamparams
, rate
, rate
);
1614 callback_register(setroam_cb
, &roamparams
);
1618 set80211mcastrate(const char *val
, int d __unused
, int s
,
1619 const struct afswtch
*afp __unused
)
1623 rate
= getrate(val
, "mcast");
1624 flags
= getmodeflags(val
);
1626 if (flags
== 0) { /* NB: no flags => current channel */
1627 flags
= getcurchan(s
)->ic_flags
;
1628 _APPLY_RATE1(flags
, txparams
, mcastrate
, rate
);
1630 _APPLY_RATE(flags
, txparams
, mcastrate
, rate
);
1631 callback_register(settxparams_cb
, &txparams
);
1635 set80211mgtrate(const char *val
, int d __unused
, int s
,
1636 const struct afswtch
*afp __unused
)
1640 rate
= getrate(val
, "mgmt");
1641 flags
= getmodeflags(val
);
1643 if (flags
== 0) { /* NB: no flags => current channel */
1644 flags
= getcurchan(s
)->ic_flags
;
1645 _APPLY_RATE1(flags
, txparams
, mgmtrate
, rate
);
1647 _APPLY_RATE(flags
, txparams
, mgmtrate
, rate
);
1648 callback_register(settxparams_cb
, &txparams
);
1652 set80211ucastrate(const char *val
, int d __unused
, int s
,
1653 const struct afswtch
*afp __unused
)
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
);
1665 _APPLY(flags
, txparams
, ucastrate
,
1666 IEEE80211_FIXED_RATE_NONE
);
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
);
1673 _APPLY_RATE(flags
, txparams
, ucastrate
, rate
);
1675 callback_register(settxparams_cb
, &txparams
);
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
);
1686 if (flags
== 0) { /* NB: no flags => current channel */
1687 flags
= getcurchan(s
)->ic_flags
;
1688 _APPLY1(flags
, txparams
, maxretry
, v
);
1690 _APPLY(flags
, txparams
, maxretry
, v
);
1691 callback_register(settxparams_cb
, &txparams
);
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
),
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
),
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
);
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
);
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
);
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,
1745 set80211ampdu(const char *val __unused
, int d
, int s
,
1746 const struct afswtch
*rafp __unused
)
1750 if (get80211val(s
, IEEE80211_IOC_AMPDU
, &du
) < 0)
1751 errx(-1, "cannot get AMPDU setting");
1757 set80211(s
, IEEE80211_IOC_AMPDU
, ampdu
, 0, NULL
);
1761 set80211ampdulimit(const char *val
, int d __unused
, int s
,
1762 const struct afswtch
*afp __unused
)
1766 switch (atoi(val
)) {
1769 v
= IEEE80211_HTCAP_MAXRXAMPDU_8K
;
1773 v
= IEEE80211_HTCAP_MAXRXAMPDU_16K
;
1777 v
= IEEE80211_HTCAP_MAXRXAMPDU_32K
;
1781 v
= IEEE80211_HTCAP_MAXRXAMPDU_64K
;
1784 errx(-1, "invalid A-MPDU limit %s", val
);
1786 set80211(s
, IEEE80211_IOC_AMPDU_LIMIT
, v
, 0, NULL
);
1790 set80211ampdudensity(const char *val
, int d __unused
, int s
,
1791 const struct afswtch
*afp __unused
)
1795 if (isanyarg(val
) || iseq(val
, "na"))
1796 v
= IEEE80211_HTCAP_MPDUDENSITY_NA
;
1797 else switch ((int)(atof(val
)*4)) {
1799 v
= IEEE80211_HTCAP_MPDUDENSITY_NA
;
1802 v
= IEEE80211_HTCAP_MPDUDENSITY_025
;
1805 v
= IEEE80211_HTCAP_MPDUDENSITY_05
;
1808 v
= IEEE80211_HTCAP_MPDUDENSITY_1
;
1811 v
= IEEE80211_HTCAP_MPDUDENSITY_2
;
1814 v
= IEEE80211_HTCAP_MPDUDENSITY_4
;
1817 v
= IEEE80211_HTCAP_MPDUDENSITY_8
;
1820 v
= IEEE80211_HTCAP_MPDUDENSITY_16
;
1823 errx(-1, "invalid A-MPDU density %s", val
);
1825 set80211(s
, IEEE80211_IOC_AMPDU_DENSITY
, v
, 0, NULL
);
1829 set80211amsdu(const char *val __unused
, int d
, int s
,
1830 const struct afswtch
*rafp __unused
)
1834 if (get80211val(s
, IEEE80211_IOC_AMSDU
, &amsdu
) < 0)
1835 err(-1, "cannot get AMSDU setting");
1841 set80211(s
, IEEE80211_IOC_AMSDU
, amsdu
, 0, NULL
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1965 set80211meshmetric(const char *val
, int d __unused
, int s
,
1966 const struct afswtch
*afp __unused
)
1970 memcpy(v
, val
, sizeof(v
));
1971 set80211(s
, IEEE80211_IOC_MESH_PR_METRIC
, 0, 0, v
);
1975 set80211meshpath(const char *val
, int d __unused
, int s
,
1976 const struct afswtch
*afp __unused
)
1980 memcpy(v
, val
, sizeof(v
));
1981 set80211(s
, IEEE80211_IOC_MESH_PR_PATH
, 0, 0, v
);
1985 regdomain_sort(const void *a
, const void *b
)
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
;
1998 static const struct ieee80211_channel
*
1999 chanlookup(const struct ieee80211_channel chans
[], int nchans
,
2000 int freq
, int flags
)
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
)
2015 chanfind(const struct ieee80211_channel chans
[], int nchans
, int flags
)
2019 for (i
= 0; i
< nchans
; i
++) {
2020 const struct ieee80211_channel
*c
= &chans
[i
];
2021 if (((int)c
->ic_flags
& flags
) == flags
)
2028 * Check channel compatibility.
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
)
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.
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)
2064 if (chanlookup(avail
->ic_chans
, avail
->ic_nchans
, freq
,
2065 flags
&~ (IEEE80211_CHAN_HALF
| IEEE80211_CHAN_QUARTER
)) == NULL
)
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
)));
2072 return chanfind(avail
->ic_chans
, avail
->ic_nchans
,
2073 IEEE80211_CHAN_QUARTER
|
2074 (flags
& (IEEE80211_CHAN_2GHZ
| IEEE80211_CHAN_5GHZ
)));
2079 regdomain_addchans(struct ieee80211req_chaninfo
*ci
,
2080 const netband_head
*bands
,
2081 const struct ieee80211_regdomain
*reg
,
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
;
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
) {
2097 printf("%s:", __func__
);
2098 printb(" chanFlags", chanFlags
, IEEE80211_CHAN_BITS
);
2099 printb(" bandFlags", nb
->flags
| b
->flags
,
2100 IEEE80211_CHAN_BITS
);
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) {
2124 printf("%u: skip, not an "
2125 "HT20 channel\n", freq
);
2128 if ((chanFlags
& IEEE80211_CHAN_HT40
) &&
2129 (flags
& IEEE80211_CHAN_HT40
) == 0) {
2131 printf("%u: skip, not an "
2132 "HT40 channel\n", freq
);
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
)) {
2143 printf("%u: skip, HT40+DFS "
2144 "not permitted\n", freq
);
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
)) {
2156 printf("%u: skip, ", freq
);
2157 printb("flags", flags
,
2158 IEEE80211_CHAN_BITS
);
2159 printf(" not available\n");
2163 if ((flags
& REQ_ECM
) && !reg
->ecm
) {
2165 printf("%u: skip, ECM channel\n", freq
);
2168 if ((flags
& REQ_INDOOR
) && reg
->location
== 'O') {
2170 printf("%u: skip, indoor channel\n",
2174 if ((flags
& REQ_OUTDOOR
) && reg
->location
== 'I') {
2176 printf("%u: skip, outdoor channel\n",
2180 if ((flags
& IEEE80211_CHAN_HT40
) &&
2181 prev
!= NULL
&& (freq
- prev
->ic_freq
) < channelSep
) {
2183 printf("%u: skip, only %u channel "
2184 "separation, need %d\n", freq
,
2185 freq
- prev
->ic_freq
, channelSep
);
2188 if (ci
->ic_nchans
== IEEE80211_CHAN_MAX
) {
2190 printf("%u: skip, channel table full\n",
2194 c
= &ci
->ic_chans
[ci
->ic_nchans
++];
2195 memset(c
, 0, sizeof(*c
));
2197 c
->ic_flags
= flags
;
2198 if (c
->ic_flags
& IEEE80211_CHAN_DFS
)
2199 c
->ic_maxregpower
= nb
->maxPowerDFS
;
2201 c
->ic_maxregpower
= nb
->maxPower
;
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 */
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
);
2236 errx(1, "internal error, country %d not found",
2240 rd
= lib80211_regdomain_findbysku(rdp
, reg
->regdomain
);
2242 errx(1, "internal error, regdomain %d not found",
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.
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
,
2266 if (dc
->dc_htcaps
& IEEE80211_HTCAP_CHWIDTH40
) {
2267 regdomain_addchans(ci
, &rd
->bands_11na
, reg
,
2268 IEEE80211_CHAN_A
| IEEE80211_CHAN_HT40U
,
2270 regdomain_addchans(ci
, &rd
->bands_11na
, reg
,
2271 IEEE80211_CHAN_A
| IEEE80211_CHAN_HT40D
,
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
,
2279 if (dc
->dc_htcaps
& IEEE80211_HTCAP_CHWIDTH40
) {
2280 regdomain_addchans(ci
, &rd
->bands_11ng
, reg
,
2281 IEEE80211_CHAN_G
| IEEE80211_CHAN_HT40U
,
2283 regdomain_addchans(ci
, &rd
->bands_11ng
, reg
,
2284 IEEE80211_CHAN_G
| IEEE80211_CHAN_HT40D
,
2288 qsort(ci
->ic_chans
, ci
->ic_nchans
, sizeof(ci
->ic_chans
[0]),
2291 memcpy(ci
, &dc
->dc_chaninfo
,
2292 IEEE80211_CHANINFO_SPACE(&dc
->dc_chaninfo
));
2296 list_countries(void)
2298 struct regdata
*rdp
= getregdata();
2299 const struct country
*cp
;
2300 const struct regdomain
*dp
;
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" : " ");
2311 printf("\nRegulatory domains:\n");
2312 LIST_FOREACH(dp
, &rdp
->domains
, next
) {
2313 printf("%-15.15s%s", dp
->name
, ((i
+1)%4) == 0 ? "\n" : " ");
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
);
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];
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
);
2344 long sku
= strtol(val
, &eptr
, 0);
2347 rd
= lib80211_regdomain_findbysku(rdp
, sku
);
2348 if (eptr
== val
|| rd
== NULL
)
2349 errx(1, "unknown regdomain %s", val
);
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.
2360 callback_register(setregdomain_cb
, ®domain
);
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
);
2373 long code
= strtol(val
, &eptr
, 0);
2376 cc
= lib80211_country_findbycc(rdp
, code
);
2377 if (eptr
== val
|| cc
== NULL
)
2378 errx(1, "unknown ISO country code %s", val
);
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
, ®domain
);
2389 set80211location(const char *val __unused
, int d
, int s
,
2390 const struct afswtch
*rafp __unused
)
2393 regdomain
.location
= d
;
2394 callback_register(setregdomain_cb
, ®domain
);
2398 set80211ecm(const char *val __unused
, int d
, int s
,
2399 const struct afswtch
*rafp __unused
)
2403 callback_register(setregdomain_cb
, ®domain
);
2419 if (spacer
!= '\t') {
2423 col
= 8; /* 8-col tab */
2427 LINE_CHECK(const char *fmt
, ...)
2434 n
= vsnprintf(buf
+1, sizeof(buf
)-1, fmt
, ap
);
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
;
2460 getcaps(int capinfo
)
2462 static char capstring
[32];
2463 char *cp
= capstring
;
2465 if (capinfo
& IEEE80211_CAPINFO_ESS
)
2467 if (capinfo
& IEEE80211_CAPINFO_IBSS
)
2469 if (capinfo
& IEEE80211_CAPINFO_CF_POLLABLE
)
2471 if (capinfo
& IEEE80211_CAPINFO_CF_POLLREQ
)
2473 if (capinfo
& IEEE80211_CAPINFO_PRIVACY
)
2475 if (capinfo
& IEEE80211_CAPINFO_SHORT_PREAMBLE
)
2477 if (capinfo
& IEEE80211_CAPINFO_PBCC
)
2479 if (capinfo
& IEEE80211_CAPINFO_CHNL_AGILITY
)
2481 if (capinfo
& IEEE80211_CAPINFO_SHORT_SLOTTIME
)
2483 if (capinfo
& IEEE80211_CAPINFO_RSN
)
2485 if (capinfo
& IEEE80211_CAPINFO_DSSSOFDM
)
2494 static char flagstring
[32];
2495 char *cp
= flagstring
;
2497 if (flags
& IEEE80211_NODE_AUTH
)
2499 if (flags
& IEEE80211_NODE_QOS
)
2501 if (flags
& IEEE80211_NODE_ERP
)
2503 if (flags
& IEEE80211_NODE_PWR_MGT
)
2505 if (flags
& IEEE80211_NODE_HT
) {
2507 if (flags
& IEEE80211_NODE_HTCOMPAT
)
2510 if (flags
& IEEE80211_NODE_WPS
)
2512 if (flags
& IEEE80211_NODE_TSN
)
2514 if (flags
& IEEE80211_NODE_AMPDU_TX
)
2516 if (flags
& IEEE80211_NODE_AMPDU_RX
)
2518 if (flags
& IEEE80211_NODE_MIMO_PS
) {
2520 if (flags
& IEEE80211_NODE_MIMO_RTS
)
2523 if (flags
& IEEE80211_NODE_RIFS
)
2525 if (flags
& IEEE80211_NODE_SGI40
) {
2527 if (flags
& IEEE80211_NODE_SGI20
)
2529 } else if (flags
& IEEE80211_NODE_SGI20
)
2531 if (flags
& IEEE80211_NODE_AMSDU_TX
)
2533 if (flags
& IEEE80211_NODE_AMSDU_RX
)
2540 printie(const char* tag
, const uint8_t *ie
, size_t ielen
, int maxlen
)
2544 maxlen
-= strlen(tag
)+2;
2545 if (2*ielen
> (size_t)maxlen
)
2548 for (; ielen
> 0; ie
++, ielen
--) {
2551 printf("%02x", *ie
);
2559 #define LE_READ_2(p) \
2561 ((((const u_int8_t *)(p))[0] ) | \
2562 (((const u_int8_t *)(p))[1] << 8)))
2563 #define LE_READ_4(p) \
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
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
;
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]"
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
)
2609 printwmeinfo(const char *tag
, const u_int8_t
*ie
, size_t ielen __unused
,
2610 int maxlen __unused
)
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
);
2622 printhtcap(const char *tag
, const u_int8_t
*ie
, size_t ielen __unused
,
2623 int maxlen __unused
)
2627 const struct ieee80211_ie_htcap
*htcap
=
2628 (const struct ieee80211_ie_htcap
*) ie
;
2632 printf("<cap 0x%x param 0x%x",
2633 LE_READ_2(&htcap
->hc_cap
), htcap
->hc_param
);
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
))
2643 printf("%s%u", sep
, i
);
2645 printf("%s%u-%u", sep
, i
, j
);
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
),
2657 printhtinfo(const char *tag
, const u_int8_t
*ie
, size_t ielen __unused
,
2658 int maxlen __unused
)
2662 const struct ieee80211_ie_htinfo
*htinfo
=
2663 (const struct ieee80211_ie_htinfo
*) ie
;
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[");
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
))
2679 printf("%s%u", sep
, i
);
2681 printf("%s%u-%u", sep
, i
, j
);
2690 printathie(const char *tag
, const u_int8_t
*ie
, size_t ielen __unused
,
2691 int maxlen __unused
)
2695 const struct ieee80211_ath_ie
*ath
=
2696 (const struct ieee80211_ath_ie
*)ie
;
2699 if (ath
->ath_capability
& ATHEROS_CAP_TURBO_PRIME
)
2701 if (ath
->ath_capability
& ATHEROS_CAP_COMPRESSION
)
2703 if (ath
->ath_capability
& ATHEROS_CAP_FAST_FRAME
)
2705 if (ath
->ath_capability
& ATHEROS_CAP_XR
)
2707 if (ath
->ath_capability
& ATHEROS_CAP_AR
)
2709 if (ath
->ath_capability
& ATHEROS_CAP_BURST
)
2711 if (ath
->ath_capability
& ATHEROS_CAP_WME
)
2713 if (ath
->ath_capability
& ATHEROS_CAP_BOOST
)
2715 printf("0x%x>", LE_READ_2(ath
->ath_defkeyix
));
2721 printmeshconf(const char *tag
, const uint8_t *ie
, size_t ielen __unused
,
2722 int maxlen __unused
)
2724 #define MATCHOUI(field, oui, string) \
2726 if (memcmp(field, oui, 4) == 0) \
2727 printf("%s", string); \
2732 const struct ieee80211_meshconf_ie
*mconf
=
2733 (const struct ieee80211_meshconf_ie
*)ie
;
2735 if (mconf
->conf_pselid
== IEEE80211_MESHCONF_PATH_HWMP
)
2740 if (mconf
->conf_pmetid
== IEEE80211_MESHCONF_METRIC_AIRTIME
)
2744 printf(" CONGESTION:");
2745 if (mconf
->conf_ccid
== IEEE80211_MESHCONF_CC_DISABLED
)
2750 if (mconf
->conf_syncid
== IEEE80211_MESHCONF_SYNC_NEIGHOFF
)
2755 if (mconf
->conf_authid
== IEEE80211_MESHCONF_AUTH_DISABLED
)
2759 printf(" FORM:0x%x CAPS:0x%x>", mconf
->conf_form
,
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
);
2772 case WPA_SEL(WPA_CSE_NULL
):
2774 case WPA_SEL(WPA_CSE_WEP40
):
2776 case WPA_SEL(WPA_CSE_WEP104
):
2778 case WPA_SEL(WPA_CSE_TKIP
):
2780 case WPA_SEL(WPA_CSE_CCMP
):
2783 return "?"; /* NB: so 1<< is discarded */
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
);
2794 case WPA_SEL(WPA_ASE_8021X_UNSPEC
):
2795 return "8021X-UNSPEC";
2796 case WPA_SEL(WPA_ASE_8021X_PSK
):
2798 case WPA_SEL(WPA_ASE_NONE
):
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];
2816 ie
+= 6, len
-= 4; /* NB: len is payload only */
2818 printf("<v%u", LE_READ_2(ie
));
2821 printf(" mc:%s", wpa_cipher(ie
));
2824 /* unicast ciphers */
2828 for (; n
> 0; n
--) {
2829 printf("%s%s", sep
, wpa_cipher(ie
));
2834 /* key management algorithms */
2838 for (; n
> 0; n
--) {
2839 printf("%s%s", sep
, wpa_keymgmt(ie
));
2844 if (len
> 2) /* optional capabilities */
2845 printf(", caps 0x%x", LE_READ_2(ie
));
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
);
2857 case RSN_SEL(RSN_CSE_NULL
):
2859 case RSN_SEL(RSN_CSE_WEP40
):
2861 case RSN_SEL(RSN_CSE_WEP104
):
2863 case RSN_SEL(RSN_CSE_TKIP
):
2865 case RSN_SEL(RSN_CSE_CCMP
):
2867 case RSN_SEL(RSN_CSE_WRAP
):
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
);
2881 case RSN_SEL(RSN_ASE_8021X_UNSPEC
):
2882 return "8021X-UNSPEC";
2883 case RSN_SEL(RSN_ASE_8021X_PSK
):
2885 case RSN_SEL(RSN_ASE_NONE
):
2893 printrsnie(const char *tag
, const u_int8_t
*ie
, size_t ielen
,
2894 int maxlen __unused
)
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 */
2911 ie
+= 2, ielen
-= 2;
2913 for (; n
> 0; n
--) {
2914 printf("%s%s", sep
, rsn_cipher(ie
));
2915 ie
+= 4, ielen
-= 4;
2919 /* key management algorithms */
2921 ie
+= 2, ielen
-= 2;
2923 for (; n
> 0; n
--) {
2924 printf("%s%s", sep
, rsn_keymgmt(ie
));
2925 ie
+= 4, ielen
-= 4;
2929 if (ielen
> 2) /* optional capabilities */
2930 printf(", caps 0x%x", LE_READ_2(ie
));
2936 #define BE_READ_2(p) \
2938 ((((const u_int8_t *)(p))[1] ) | \
2939 (((const u_int8_t *)(p))[0] << 8)))
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];
2954 static const char *dev_pass_id
[] = {
2955 "D", /* Default (PIN) */
2956 "U", /* User-specified */
2957 "M", /* Machine-specified */
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 */
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
,
2982 case IEEE80211_WPS_ATTR_VERSION
:
2983 printf("v:%d.%d", *ie
>> 4, *ie
& 0xf);
2985 case IEEE80211_WPS_ATTR_AP_SETUP_LOCKED
:
2986 printf(" ap_setup:%s", *ie
? "locked" :
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:");
2994 printf(" cfg_mthd:" );
2995 cfg_mthd
= BE_READ_2(ie
);
2997 for (n
= 15; n
>= 0; n
--) {
3002 switch (cfg_mthd
& (1 << n
)) {
3005 case IEEE80211_WPS_CONFIG_USBA
:
3009 case IEEE80211_WPS_CONFIG_ETHERNET
:
3013 case IEEE80211_WPS_CONFIG_LABEL
:
3017 case IEEE80211_WPS_CONFIG_DISPLAY
:
3019 (IEEE80211_WPS_CONFIG_VIRT_DISPLAY
|
3020 IEEE80211_WPS_CONFIG_PHY_DISPLAY
)))
3026 case IEEE80211_WPS_CONFIG_EXT_NFC_TOKEN
:
3027 printf("ext_nfc_tokenk");
3030 case IEEE80211_WPS_CONFIG_INT_NFC_TOKEN
:
3031 printf("int_nfc_token");
3034 case IEEE80211_WPS_CONFIG_NFC_INTERFACE
:
3035 printf("nfc_interface");
3038 case IEEE80211_WPS_CONFIG_PUSHBUTTON
:
3040 (IEEE80211_WPS_CONFIG_VIRT_PUSHBUTTON
|
3041 IEEE80211_WPS_CONFIG_PHY_PUSHBUTTON
))) {
3042 printf("push_button");
3046 case IEEE80211_WPS_CONFIG_KEYPAD
:
3050 case IEEE80211_WPS_CONFIG_VIRT_PUSHBUTTON
:
3051 printf("virtual_push_button");
3054 case IEEE80211_WPS_CONFIG_PHY_PUSHBUTTON
:
3055 printf("physical_push_button");
3058 case IEEE80211_WPS_CONFIG_P2PS
:
3062 case IEEE80211_WPS_CONFIG_VIRT_DISPLAY
:
3063 printf("virtual_display");
3066 case IEEE80211_WPS_CONFIG_PHY_DISPLAY
:
3067 printf("physical_display");
3071 printf("unknown_wps_config<%04x>",
3072 cfg_mthd
& (1 << n
));
3078 case IEEE80211_WPS_ATTR_DEV_NAME
:
3079 printf(" device_name:<%.*s>", tlv_len
, ie
);
3081 case IEEE80211_WPS_ATTR_DEV_PASSWORD_ID
:
3083 if (n
< (int)nitems(dev_pass_id
))
3084 printf(" dpi:%s", dev_pass_id
[n
]);
3086 case IEEE80211_WPS_ATTR_MANUFACTURER
:
3087 printf(" manufacturer:<%.*s>", tlv_len
, ie
);
3089 case IEEE80211_WPS_ATTR_MODEL_NAME
:
3090 printf(" model_name:<%.*s>", tlv_len
, ie
);
3092 case IEEE80211_WPS_ATTR_MODEL_NUMBER
:
3093 printf(" model_number:<%.*s>", tlv_len
, ie
);
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
]);
3100 case IEEE80211_WPS_ATTR_RF_BANDS
:
3103 for (n
= 7; n
>= 0; n
--) {
3108 switch (*ie
& (1 << n
)) {
3111 case IEEE80211_WPS_RF_BAND_24GHZ
:
3115 case IEEE80211_WPS_RF_BAND_50GHZ
:
3119 case IEEE80211_WPS_RF_BAND_600GHZ
:
3124 printf("unknown<%02x>",
3131 case IEEE80211_WPS_ATTR_RESPONSE_TYPE
:
3132 printf(" resp_type:0x%02x", *ie
);
3134 case IEEE80211_WPS_ATTR_SELECTED_REGISTRAR
:
3135 printf(" sel:%s", *ie
? "T" : "F");
3137 case IEEE80211_WPS_ATTR_SERIAL_NUMBER
:
3138 printf(" serial_number:<%.*s>", tlv_len
, ie
);
3140 case IEEE80211_WPS_ATTR_UUID_E
:
3142 for (n
= 0; n
< (tlv_len
- 1); n
++)
3143 printf("%02x-", ie
[n
]);
3144 printf("%02x", ie
[n
]);
3146 case IEEE80211_WPS_ATTR_VENDOR_EXT
:
3148 for (n
= 0; n
< tlv_len
; n
++)
3149 printf("%02x", ie
[n
]);
3151 case IEEE80211_WPS_ATTR_WPS_STATE
:
3153 case IEEE80211_WPS_STATE_NOT_CONFIGURED
:
3156 case IEEE80211_WPS_STATE_CONFIGURED
:
3160 printf(" state:B<%02x>", *ie
);
3165 printf(" unknown_wps_attr:0x%x", tlv_type
);
3168 ie
+= tlv_len
, len
-= tlv_len
;
3175 printtdmaie(const char *tag
, const u_int8_t
*ie
, size_t ielen
,
3176 int maxlen __unused
)
3179 if (verbose
&& ielen
>= sizeof(struct ieee80211_tdma_param
)) {
3180 const struct ieee80211_tdma_param
*tdma
=
3181 (const struct ieee80211_tdma_param
*) ie
;
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 "...".
3198 copy_essid(char buf
[], size_t bufsize
, const u_int8_t
*essid
, size_t essid_len
)
3204 if (essid_len
> bufsize
)
3208 /* determine printable or not */
3209 for (i
= 0, p
= essid
; i
< maxlen
; i
++, p
++) {
3210 if (*p
< ' ' || *p
> 0x7e)
3213 if (i
!= maxlen
) { /* not printable, print as hex */
3216 strlcpy(buf
, "0x", bufsize
);
3219 for (i
= 0; i
< maxlen
&& bufsize
>= 2; i
++) {
3220 sprintf(&buf
[2+2*i
], "%02x", p
[i
]);
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);
3234 printssid(const char *tag
, const u_int8_t
*ie
, size_t ielen __unused
,
3237 char ssid
[2*IEEE80211_NWID_LEN
+1];
3239 printf("%s<%.*s>", tag
, copy_essid(ssid
, maxlen
, ie
+2, ie
[1]), ssid
);
3243 printrates(const char *tag
, const u_int8_t
*ie
, size_t ielen
,
3244 int maxlen __unused
)
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
);
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
;
3274 printf(" %zu-%zu,%u", schan
, schan
+ nchan
-1,
3275 cie
->band
[i
].maxtxpwr
);
3277 printf(" %zu,%u", schan
, cie
->band
[i
].maxtxpwr
);
3282 /* unaligned little endian access */
3283 #define LE_READ_4(p) \
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)))
3291 iswpaoui(const u_int8_t
*frm
)
3293 return frm
[1] > 3 && LE_READ_4(frm
+2) == ((WPA_OUI_TYPE
<<24)|WPA_OUI
);
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
;
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
;
3311 isatherosoui(const u_int8_t
*frm
)
3313 return frm
[1] > 3 && LE_READ_4(frm
+2) == ((ATH_OUI_TYPE
<<24)|ATH_OUI
);
3317 istdmaoui(const uint8_t *frm
)
3319 return frm
[1] > 3 && LE_READ_4(frm
+2) == ((TDMA_OUI_TYPE
<<24)|TDMA_OUI
);
3323 iswpsoui(const uint8_t *frm
)
3325 return frm
[1] > 3 && LE_READ_4(frm
+2) == ((WPS_OUI_TYPE
<<24)|WPA_OUI
);
3331 static char iename_buf
[64];
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",
3362 return (const char *) iename_buf
;
3366 printies(const u_int8_t
*vp
, int ielen
, int maxcols
)
3370 case IEEE80211_ELEMID_SSID
:
3372 printssid(" SSID", vp
, 2+vp
[1], maxcols
);
3374 case IEEE80211_ELEMID_RATES
:
3375 case IEEE80211_ELEMID_XRATES
:
3377 printrates(vp
[0] == IEEE80211_ELEMID_RATES
?
3378 " RATES" : " XRATES", vp
, 2+vp
[1], maxcols
);
3380 case IEEE80211_ELEMID_DSPARMS
:
3382 printf(" DSPARMS<%u>", vp
[2]);
3384 case IEEE80211_ELEMID_COUNTRY
:
3386 printcountry(" COUNTRY", vp
, 2+vp
[1], maxcols
);
3388 case IEEE80211_ELEMID_ERP
:
3390 printf(" ERP<0x%x>", vp
[2]);
3392 case IEEE80211_ELEMID_VENDOR
:
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
);
3406 printie(" VEN", vp
, 2+vp
[1], maxcols
);
3408 case IEEE80211_ELEMID_RSN
:
3409 printrsnie(" RSN", vp
, 2+vp
[1], maxcols
);
3411 case IEEE80211_ELEMID_HTCAP
:
3412 printhtcap(" HTCAP", vp
, 2+vp
[1], maxcols
);
3414 case IEEE80211_ELEMID_HTINFO
:
3416 printhtinfo(" HTINFO", vp
, 2+vp
[1], maxcols
);
3418 case IEEE80211_ELEMID_MESHID
:
3420 printssid(" MESHID", vp
, 2+vp
[1], maxcols
);
3422 case IEEE80211_ELEMID_MESHCONF
:
3423 printmeshconf(" MESHCONF", vp
, 2+vp
[1], maxcols
);
3427 printie(iename(vp
[0]), vp
, 2+vp
[1], maxcols
);
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]);
3448 list_scan(int s
, int long_ssids
)
3450 uint8_t buf
[24*1024];
3451 char ssid
[IEEE80211_NWID_LEN
+1];
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
))
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"
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
;
3484 idlen
= sr
->isr_ssid_len
;
3486 printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
3488 , copy_essid(ssid
, ssidmax
, idp
, idlen
)
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
3495 , getcaps(sr
->isr_capinfo
)
3497 printies(vp
+ sr
->isr_ssid_len
+ sr
->isr_meshid_len
,
3498 sr
->isr_ie_len
, 24);
3500 cp
+= sr
->isr_len
, len
-= sr
->isr_len
;
3501 } while (len
>= sizeof(struct ieee80211req_scan_result
));
3505 scan_and_wait(int s
)
3507 struct ieee80211_scan_req sr
;
3508 struct ieee80211req ireq
;
3511 sroute
= socket(PF_ROUTE
, SOCK_RAW
, 0);
3513 perror("socket(PF_ROUTE,SOCK_RAW)");
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
;
3528 ireq
.i_len
= sizeof(sr
);
3529 /* NB: only root can trigger a scan so ignore errors */
3530 if (ioctl(s
, SIOCS80211
, &ireq
) >= 0) {
3532 struct if_announcemsghdr
*ifan
;
3533 struct rt_msghdr
*rtm
;
3536 if (read(sroute
, buf
, sizeof(buf
)) < 0) {
3537 perror("read(PF_ROUTE)");
3540 rtm
= (struct rt_msghdr
*) buf
;
3541 if (rtm
->rtm_version
!= RTM_VERSION
)
3543 ifan
= (struct if_announcemsghdr
*) rtm
;
3544 } while (rtm
->rtm_type
!= RTM_IEEE80211
||
3545 ifan
->ifan_what
!= RTM_IEEE80211_SCAN
);
3551 set80211scan(const char *val __unused
, int d __unused
, int s
,
3552 const struct afswtch
*afp __unused
)
3558 static enum ieee80211_opmode
get80211opmode(int s
);
3561 gettxseq(const struct ieee80211req_sta_info
*si
)
3565 if ((si
->isi_state
& IEEE80211_NODE_QOS
) == 0)
3566 return si
->isi_txseqs
[0];
3567 /* XXX not right but usually what folks want */
3569 for (i
= 0; i
< IEEE80211_TID_SIZE
; i
++)
3570 if (si
->isi_txseqs
[i
] > txseq
)
3571 txseq
= si
->isi_txseqs
[i
];
3576 getrxseq(const struct ieee80211req_sta_info
*si
)
3580 if ((si
->isi_state
& IEEE80211_NODE_QOS
) == 0)
3581 return si
->isi_rxseqs
[0];
3582 /* XXX not right but usually what folks want */
3584 for (i
= 0; i
< IEEE80211_TID_SIZE
; i
++)
3585 if (si
->isi_rxseqs
[i
] > rxseq
)
3586 rxseq
= si
->isi_rxseqs
[i
];
3591 list_stations(int s
)
3594 struct ieee80211req_sta_req req
;
3595 uint8_t buf
[24*1024];
3597 enum ieee80211_opmode opmode
= get80211opmode(s
);
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
))
3617 if (opmode
== IEEE80211_M_MBSS
) {
3618 printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
3631 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
3644 cp
= (const uint8_t *) u
.req
.info
;
3646 const struct ieee80211req_sta_info
*si
;
3648 si
= (const struct ieee80211req_sta_info
*) cp
;
3649 if (si
->isi_len
< sizeof(*si
))
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
*)
3655 , ieee80211_mhz2ieee(si
->isi_freq
,
3659 , mesh_linkstate_string(si
->isi_peerstate
)
3667 printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
3668 , ether_ntoa((const struct ether_addr
*)
3670 , IEEE80211_AID(si
->isi_associd
)
3671 , ieee80211_mhz2ieee(si
->isi_freq
,
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
);
3685 cp
+= si
->isi_len
, len
-= si
->isi_len
;
3686 } while (len
>= sizeof(struct ieee80211req_sta_info
));
3690 mesh_linkstate_string(uint8_t state
)
3692 static const char *state_names
[] = {
3701 if (state
>= nitems(state_names
)) {
3702 static char buf
[10];
3703 snprintf(buf
, sizeof(buf
), "#%u", state
);
3706 return state_names
[state
];
3711 get_chaninfo(const struct ieee80211_channel
*c
, int precise
,
3712 char buf
[], size_t bsize
)
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
);
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
);
3737 if (IEEE80211_IS_CHAN_HT(c
))
3738 strlcat(buf
, " ht", bsize
);
3744 print_chaninfo(const struct ieee80211_channel
*c
, int verb
)
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
)));
3755 chanpref(const struct ieee80211_channel
*c
)
3757 if (IEEE80211_IS_CHAN_HT40(c
))
3759 if (IEEE80211_IS_CHAN_HT20(c
))
3761 if (IEEE80211_IS_CHAN_HALF(c
))
3763 if (IEEE80211_IS_CHAN_QUARTER(c
))
3765 if (IEEE80211_IS_CHAN_TURBO(c
))
3767 if (IEEE80211_IS_CHAN_A(c
))
3769 if (IEEE80211_IS_CHAN_G(c
))
3771 if (IEEE80211_IS_CHAN_B(c
))
3773 if (IEEE80211_IS_CHAN_PUREG(c
))
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
;
3787 achans
= malloc(IEEE80211_CHANINFO_SPACE(chans
));
3789 errx(1, "no space for active channel list");
3790 achans
->ic_nchans
= 0;
3791 memset(reported
, 0, sizeof(reported
));
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
))
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
;
3811 achans
->ic_chans
[achans
->ic_nchans
++] = *c
;
3812 setbit(reported
, c
->ic_ieee
);
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
))
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)
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
);
3840 if (achans
->ic_nchans
% 2) {
3841 print_chaninfo(&achans
->ic_chans
[i
], verb
);
3848 list_channels(int s
, bool allchans
)
3851 print_channels(s
, chaninfo
, allchans
, verbose
);
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
);
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
)
3876 struct ieee80211req_chaninfo
*achans
;
3877 uint8_t reported
[IEEE80211_CHAN_BYTES
];
3878 struct ieee80211_channel
*c
, *prev
;
3882 achans
= malloc(IEEE80211_CHANINFO_SPACE(chaninfo
));
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
)
3897 achans
->ic_chans
[achans
->ic_nchans
++] = *c
;
3898 setbit(reported
, c
->ic_ieee
);
3902 half
= achans
->ic_nchans
/ 2;
3903 if (achans
->ic_nchans
% 2)
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
]);
3911 if (achans
->ic_nchans
% 2) {
3912 print_txpow(&achans
->ic_chans
[i
]);
3916 for (i
= 0; i
< achans
->ic_nchans
; i
++) {
3917 print_txpow_verbose(&achans
->ic_chans
[i
]);
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" \
3936 list_capabilities(int s
)
3938 struct ieee80211_devcaps_req
*dc
;
3941 dc
= malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN
));
3943 dc
= malloc(IEEE80211_DEVCAPS_SIZE(1));
3945 errx(1, "no space for device capabilities");
3946 dc
->dc_chaninfo
.ic_nchans
= verbose
? MAXCHAN
: 1;
3948 printb("drivercaps", dc
->dc_drivercaps
, IEEE80211_C_BITS
);
3949 if (dc
->dc_cryptocaps
!= 0 || verbose
) {
3951 printb("cryptocaps", dc
->dc_cryptocaps
, IEEE80211_CRYPTO_BITS
);
3953 if (dc
->dc_htcaps
!= 0 || verbose
) {
3955 printb("htcaps", dc
->dc_htcaps
, IEEE80211_HTCAP_BITS
);
3959 chaninfo
= &dc
->dc_chaninfo
; /* XXX */
3960 print_channels(s
, &dc
->dc_chaninfo
, 1/*allchans*/, verbose
);
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
;
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)" : "");
3985 list_wme_aci(int s
, const char *tag
, int ac
)
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) {
4007 if ((ac
& IEEE80211_WMEPARAM_BSS
) == 0) {
4008 if (get80211wme(s
, IEEE80211_IOC_WME_ACKPOLICY
, ac
, &val
) != -1) {
4021 static const char *acnames
[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
4025 /* display both BSS and local settings */
4026 for (ac
= WME_AC_BE
; ac
<= WME_AC_VO
; ac
++) {
4028 if (ac
& IEEE80211_WMEPARAM_BSS
)
4029 list_wme_aci(s
, " ", ac
);
4031 list_wme_aci(s
, acnames
[ac
], ac
);
4032 if ((ac
& IEEE80211_WMEPARAM_BSS
) == 0) {
4033 ac
|= IEEE80211_WMEPARAM_BSS
;
4036 ac
&= ~IEEE80211_WMEPARAM_BSS
;
4039 /* display only channel settings */
4040 for (ac
= WME_AC_BE
; ac
<= WME_AC_VO
; ac
++)
4041 list_wme_aci(s
, acnames
[ac
], ac
);
4048 const struct ieee80211_roamparam
*rp
;
4052 for (mode
= IEEE80211_MODE_11A
; mode
< IEEE80211_MODE_MAX
; mode
++) {
4053 rp
= &roamparams
.params
[mode
];
4054 if (rp
->rssi
== 0 && rp
->rate
== 0)
4056 if (mode
== IEEE80211_MODE_11NA
|| mode
== IEEE80211_MODE_11NG
) {
4058 LINE_CHECK("roam:%-7.7s rssi %2u.5dBm MCS %2u ",
4059 modename
[mode
], rp
->rssi
/2,
4060 rp
->rate
&~ IEEE80211_RATE_MCS
);
4062 LINE_CHECK("roam:%-7.7s rssi %4udBm MCS %2u ",
4063 modename
[mode
], rp
->rssi
/2,
4064 rp
->rate
&~ IEEE80211_RATE_MCS
);
4067 LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s",
4068 modename
[mode
], rp
->rssi
/2, rp
->rate
/2);
4070 LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s",
4071 modename
[mode
], rp
->rssi
/2, rp
->rate
/2);
4077 list_txparams(int s
)
4079 const struct ieee80211_txparam
*tp
;
4083 for (mode
= IEEE80211_MODE_11A
; mode
< IEEE80211_MODE_MAX
; mode
++) {
4084 tp
= &txparams
.params
[mode
];
4085 if (tp
->mgmtrate
== 0 && tp
->mcastrate
== 0)
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",
4092 tp
->mgmtrate
&~ IEEE80211_RATE_MCS
,
4093 tp
->mcastrate
&~ IEEE80211_RATE_MCS
,
4096 LINE_CHECK("%-7.7s ucast %2u MCS mgmt %2u MCS "
4097 "mcast %2u MCS maxretry %u",
4099 tp
->ucastrate
&~ IEEE80211_RATE_MCS
,
4100 tp
->mgmtrate
&~ IEEE80211_RATE_MCS
,
4101 tp
->mcastrate
&~ IEEE80211_RATE_MCS
,
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",
4109 tp
->mcastrate
/2, tp
->maxretry
);
4111 LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s "
4112 "mcast %2u Mb/s maxretry %u",
4114 tp
->ucastrate
/2, tp
->mgmtrate
/2,
4115 tp
->mcastrate
/2, tp
->maxretry
);
4121 printpolicy(int policy
)
4124 case IEEE80211_MACCMD_POLICY_OPEN
:
4125 printf("policy: open\n");
4127 case IEEE80211_MACCMD_POLICY_ALLOW
:
4128 printf("policy: allow\n");
4130 case IEEE80211_MACCMD_POLICY_DENY
:
4131 printf("policy: deny\n");
4133 case IEEE80211_MACCMD_POLICY_RADIUS
:
4134 printf("policy: radius\n");
4137 printf("policy: unknown (%u)\n", policy
);
4145 struct ieee80211req ireq
;
4146 struct ieee80211req_maclist
*acllist
;
4147 int i
, nacls
, policy
, len
;
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");
4160 err(1, "unable to get mac policy");
4162 policy
= ireq
.i_val
;
4163 if (policy
== IEEE80211_MACCMD_POLICY_OPEN
) {
4165 } else if (policy
== IEEE80211_MACCMD_POLICY_ALLOW
) {
4167 } else if (policy
== IEEE80211_MACCMD_POLICY_DENY
) {
4169 } else if (policy
== IEEE80211_MACCMD_POLICY_RADIUS
) {
4170 c
= 'r'; /* NB: should never have entries */
4172 printf("policy: unknown (%u)\n", policy
);
4175 if (verbose
|| c
== '?')
4176 printpolicy(policy
);
4178 ireq
.i_val
= IEEE80211_MACCMD_LIST
;
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
);
4191 err(1, "out of memory for acl list");
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
));
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
);
4212 LINE_CHECK("regdomain %d", reg
->regdomain
);
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
);
4220 LINE_CHECK("country %d", reg
->country
);
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");
4229 LINE_CHECK("anywhere");
4237 list_regdomain(int s
, int channelsalso
)
4243 print_regdomain(®domain
, 1);
4245 print_channels(s
, chaninfo
, true /* allchans */,
4246 true /* verbose */);
4248 print_regdomain(®domain
, verbose
);
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"
4276 for (rt
= &routes
[0];
4277 rt
- &routes
[0] < (int)(ireq
.i_len
/ sizeof(*rt
));
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
,
4285 (rt
->imr_flags
& IEEE80211_MESHRT_FLAGS_VALID
) ?
4287 (rt
->imr_flags
& IEEE80211_MESHRT_FLAGS_PROXY
) ?
4293 set80211list(const char *arg
, int d __unused
, int s
,
4294 const struct afswtch
*afp __unused
)
4298 if (iseq(arg
, "sta"))
4300 else if (iseq(arg
, "scan") || iseq(arg
, "ap"))
4302 else if (iseq(arg
, "lscan"))
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"))
4310 else if (iseq(arg
, "caps"))
4311 list_capabilities(s
);
4312 else if (iseq(arg
, "wme") || iseq(arg
, "wmm"))
4314 else if (iseq(arg
, "mac"))
4316 else if (iseq(arg
, "txpow"))
4318 else if (iseq(arg
, "roam"))
4320 else if (iseq(arg
, "txparam") || iseq(arg
, "txparm"))
4322 else if (iseq(arg
, "regdomain"))
4323 list_regdomain(s
, 1);
4324 else if (iseq(arg
, "countries"))
4326 else if (iseq(arg
, "mesh"))
4329 errx(1, "Don't know how to list %s for %s", arg
, IfName
);
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
;
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
;
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)
4367 ireq
->i_len
<= 5 ? "40" :
4368 ireq
->i_len
<= 13 ? "104" : "128");
4372 case IEEE80211_CIPHER_TKIP
:
4375 case IEEE80211_CIPHER_AES_OCB
:
4378 case IEEE80211_CIPHER_AES_CCM
:
4381 case IEEE80211_CIPHER_CKIP
:
4384 case IEEE80211_CIPHER_NONE
:
4388 printf("UNKNOWN (0x%x)", ireq
->i_val
);
4395 printkey(const struct ieee80211req_key
*ik
)
4397 static const uint8_t zerodata
[IEEE80211_KEYBUF_SIZE
];
4398 int keylen
= ik
->ik_keylen
;
4401 printcontents
= printkeys
&&
4402 (memcmp(ik
->ik_keydata
, zerodata
, keylen
) != 0 || verbose
);
4405 switch (ik
->ik_type
) {
4406 case IEEE80211_CIPHER_WEP
:
4408 LINE_CHECK("wepkey %u:%s", ik
->ik_keyix
+1,
4409 keylen
<= 5 ? "40-bit" :
4410 keylen
<= 13 ? "104-bit" : "128-bit");
4412 case IEEE80211_CIPHER_TKIP
:
4414 keylen
-= 128/8; /* ignore MIC for now */
4415 LINE_CHECK("TKIP %u:%u-bit", ik
->ik_keyix
+1, 8*keylen
);
4417 case IEEE80211_CIPHER_AES_OCB
:
4418 LINE_CHECK("AES-OCB %u:%u-bit", ik
->ik_keyix
+1, 8*keylen
);
4420 case IEEE80211_CIPHER_AES_CCM
:
4421 LINE_CHECK("AES-CCM %u:%u-bit", ik
->ik_keyix
+1, 8*keylen
);
4423 case IEEE80211_CIPHER_CKIP
:
4424 LINE_CHECK("CKIP %u:%u-bit", ik
->ik_keyix
+1, 8*keylen
);
4426 case IEEE80211_CIPHER_NONE
:
4427 LINE_CHECK("NULL %u:%u-bit", ik
->ik_keyix
+1, 8*keylen
);
4430 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
4431 ik
->ik_type
, ik
->ik_keyix
+1, 8*keylen
);
4434 if (printcontents
) {
4438 for (i
= 0; i
< keylen
; i
++)
4439 printf("%02x", ik
->ik_keydata
[i
]);
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
= "+";
4462 printrate(const char *tag
, int v
, int defrate
, int defmcs
)
4464 if ((v
& IEEE80211_RATE_MCS
) == 0) {
4467 LINE_CHECK("%s %d.5", tag
, v
/2);
4469 LINE_CHECK("%s %d", tag
, v
/2);
4473 LINE_CHECK("%s %d", tag
, v
&~ 0x80);
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
;
4488 if (ioctl(s
, SIOCG80211
, &ireq
) < 0)
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
;
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. */
4512 * Invalidate cached state so printing status for multiple
4513 * if's doesn't reuse the first interfaces' cached state.
4522 if (opmode
== IEEE80211_M_MBSS
) {
4524 getid(s
, 0, data
, sizeof(data
), &len
, 1);
4525 print_string(data
, len
);
4527 if (get80211val(s
, IEEE80211_IOC_NUMSSIDS
, &num
) < 0)
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
);
4538 print_string(data
, len
);
4541 if (c
->ic_freq
!= IEEE80211_CHAN_ANY
) {
4543 printf(" channel %d (%u MHz%s)", c
->ic_ieee
, c
->ic_freq
,
4544 get_chaninfo(c
, 1, buf
, sizeof(buf
)));
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 */
4560 list_regdomain(s
, 0);
4563 if (get80211val(s
, IEEE80211_IOC_AUTHMODE
, &val
) != -1) {
4565 case IEEE80211_AUTH_NONE
:
4566 LINE_CHECK("authmode NONE");
4568 case IEEE80211_AUTH_OPEN
:
4569 LINE_CHECK("authmode OPEN");
4571 case IEEE80211_AUTH_SHARED
:
4572 LINE_CHECK("authmode SHARED");
4574 case IEEE80211_AUTH_8021X
:
4575 LINE_CHECK("authmode 802.1x");
4577 case IEEE80211_AUTH_WPA
:
4578 if (get80211val(s
, IEEE80211_IOC_WPA
, &wpa
) < 0)
4579 wpa
= 1; /* default to WPA1 */
4582 LINE_CHECK("authmode WPA2/802.11i");
4585 LINE_CHECK("authmode WPA1+WPA2/802.11i");
4588 LINE_CHECK("authmode WPA");
4592 case IEEE80211_AUTH_AUTO
:
4593 LINE_CHECK("authmode AUTO");
4596 LINE_CHECK("authmode UNKNOWN (0x%x)", val
);
4601 if (wpa
|| verbose
) {
4602 if (get80211val(s
, IEEE80211_IOC_WPS
, &val
) != -1) {
4608 if (get80211val(s
, IEEE80211_IOC_TSN
, &val
) != -1) {
4614 if (ioctl(s
, IEEE80211_IOC_COUNTERMEASURES
, &val
) != -1) {
4616 LINE_CHECK("countermeasures");
4618 LINE_CHECK("-countermeasures");
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
);
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
);
4640 ireq
.i_type
= IEEE80211_IOC_RSNCAPS
;
4641 if (ioctl(s
, SIOCG80211
, &ireq
) != -1) {
4642 LINE_CHECK("RSN caps 0x%x", ireq
.i_val
);
4647 ireq
.i_type
= IEEE80211_IOC_UCASTCIPHERS
;
4648 if (ioctl(s
, SIOCG80211
, &ireq
) != -1) {
4653 if (get80211val(s
, IEEE80211_IOC_WEP
, &wepmode
) != -1 &&
4654 wepmode
!= IEEE80211_WEP_NOSUP
) {
4656 case IEEE80211_WEP_OFF
:
4657 LINE_CHECK("privacy OFF");
4659 case IEEE80211_WEP_ON
:
4660 LINE_CHECK("privacy ON");
4662 case IEEE80211_WEP_MIXED
:
4663 LINE_CHECK("privacy MIXED");
4666 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode
);
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!");
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!");
4689 for (i
= 0; i
< num
; i
++) {
4690 struct ieee80211req_key ik
;
4692 memset(&ik
, 0, sizeof(ik
));
4694 if (get80211(s
, IEEE80211_IOC_WPAKEY
, &ik
, sizeof(ik
)) < 0) {
4695 warn("WEP support, but can get keys!");
4698 if (ik
.ik_keylen
!= 0) {
4708 if (get80211val(s
, IEEE80211_IOC_POWERSAVE
, &val
) != -1 &&
4709 val
!= IEEE80211_POWERSAVE_NOSUP
) {
4710 if (val
!= IEEE80211_POWERSAVE_OFF
|| verbose
) {
4712 case IEEE80211_POWERSAVE_OFF
:
4713 LINE_CHECK("powersavemode OFF");
4715 case IEEE80211_POWERSAVE_CAM
:
4716 LINE_CHECK("powersavemode CAM");
4718 case IEEE80211_POWERSAVE_PSP
:
4719 LINE_CHECK("powersavemode PSP");
4721 case IEEE80211_POWERSAVE_PSP_CAM
:
4722 LINE_CHECK("powersavemode PSP-CAM");
4725 if (get80211val(s
, IEEE80211_IOC_POWERSAVESLEEP
, &val
) != -1)
4726 LINE_CHECK("powersavesleep %d", val
);
4730 if (get80211val(s
, IEEE80211_IOC_TXPOWER
, &val
) != -1) {
4732 LINE_CHECK("txpower %d.5", val
/2);
4734 LINE_CHECK("txpower %d", val
/2);
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) {
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
);
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
);
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
);
4789 if (get80211val(s
, IEEE80211_IOC_BGSCAN
, &bgscan
) != -1) {
4791 LINE_CHECK("bgscan");
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
);
4802 rp
= &roamparams
.params
[chan2mode(c
)];
4804 LINE_CHECK("roam:rssi %u.5", rp
->rssi
/2);
4806 LINE_CHECK("roam:rssi %u", rp
->rssi
/2);
4807 LINE_CHECK("roam:rate %u", rp
->rate
/2);
4814 if (IEEE80211_IS_CHAN_ANYG(c
) || verbose
) {
4815 if (get80211val(s
, IEEE80211_IOC_PUREG
, &val
) != -1) {
4817 LINE_CHECK("pureg");
4819 LINE_CHECK("-pureg");
4821 if (get80211val(s
, IEEE80211_IOC_PROTMODE
, &val
) != -1) {
4823 case IEEE80211_PROTMODE_OFF
:
4824 LINE_CHECK("protmode OFF");
4826 case IEEE80211_PROTMODE_CTS
:
4827 LINE_CHECK("protmode CTS");
4829 case IEEE80211_PROTMODE_RTSCTS
:
4830 LINE_CHECK("protmode RTSCTS");
4833 LINE_CHECK("protmode UNKNOWN (0x%x)", val
);
4839 if (IEEE80211_IS_CHAN_HT(c
) || verbose
) {
4841 switch (htconf
& 3) {
4854 if (get80211val(s
, IEEE80211_IOC_HTCOMPAT
, &val
) != -1) {
4856 LINE_CHECK("-htcompat");
4858 LINE_CHECK("htcompat");
4860 if (get80211val(s
, IEEE80211_IOC_AMPDU
, &val
) != -1) {
4863 LINE_CHECK("-ampdu");
4866 LINE_CHECK("ampdutx -ampdurx");
4869 LINE_CHECK("-ampdutx ampdurx");
4873 LINE_CHECK("ampdu");
4877 if (get80211val(s
, IEEE80211_IOC_AMPDU_LIMIT
, &val
) != -1) {
4879 case IEEE80211_HTCAP_MAXRXAMPDU_8K
:
4880 LINE_CHECK("ampdulimit 8k");
4882 case IEEE80211_HTCAP_MAXRXAMPDU_16K
:
4883 LINE_CHECK("ampdulimit 16k");
4885 case IEEE80211_HTCAP_MAXRXAMPDU_32K
:
4886 LINE_CHECK("ampdulimit 32k");
4888 case IEEE80211_HTCAP_MAXRXAMPDU_64K
:
4889 LINE_CHECK("ampdulimit 64k");
4893 if (get80211val(s
, IEEE80211_IOC_AMPDU_DENSITY
, &val
) != -1) {
4895 case IEEE80211_HTCAP_MPDUDENSITY_NA
:
4897 LINE_CHECK("ampdudensity NA");
4899 case IEEE80211_HTCAP_MPDUDENSITY_025
:
4900 LINE_CHECK("ampdudensity .25");
4902 case IEEE80211_HTCAP_MPDUDENSITY_05
:
4903 LINE_CHECK("ampdudensity .5");
4905 case IEEE80211_HTCAP_MPDUDENSITY_1
:
4906 LINE_CHECK("ampdudensity 1");
4908 case IEEE80211_HTCAP_MPDUDENSITY_2
:
4909 LINE_CHECK("ampdudensity 2");
4911 case IEEE80211_HTCAP_MPDUDENSITY_4
:
4912 LINE_CHECK("ampdudensity 4");
4914 case IEEE80211_HTCAP_MPDUDENSITY_8
:
4915 LINE_CHECK("ampdudensity 8");
4917 case IEEE80211_HTCAP_MPDUDENSITY_16
:
4918 LINE_CHECK("ampdudensity 16");
4922 if (get80211val(s
, IEEE80211_IOC_AMSDU
, &val
) != -1) {
4925 LINE_CHECK("-amsdu");
4928 LINE_CHECK("amsdutx -amsdurx");
4931 LINE_CHECK("-amsdutx amsdurx");
4935 LINE_CHECK("amsdu");
4939 /* XXX amsdu limit */
4940 if (get80211val(s
, IEEE80211_IOC_SHORTGI
, &val
) != -1) {
4942 LINE_CHECK("shortgi");
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
);
4952 LINE_CHECK("htprotmode RTSCTS");
4954 if (get80211val(s
, IEEE80211_IOC_PUREN
, &val
) != -1) {
4956 LINE_CHECK("puren");
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
)
4966 LINE_CHECK("-smps");
4968 if (get80211val(s
, IEEE80211_IOC_RIFS
, &val
) != -1) {
4972 LINE_CHECK("-rifs");
4976 if (get80211val(s
, IEEE80211_IOC_WME
, &wme
) != -1) {
4984 if (get80211val(s
, IEEE80211_IOC_BURST
, &val
) != -1) {
4986 LINE_CHECK("burst");
4988 LINE_CHECK("-burst");
4991 if (get80211val(s
, IEEE80211_IOC_FF
, &val
) != -1) {
4997 if (get80211val(s
, IEEE80211_IOC_TURBOP
, &val
) != -1) {
4999 LINE_CHECK("dturbo");
5001 LINE_CHECK("-dturbo");
5003 if (get80211val(s
, IEEE80211_IOC_DWDS
, &val
) != -1) {
5007 LINE_CHECK("-dwds");
5010 if (opmode
== IEEE80211_M_HOSTAP
) {
5011 if (get80211val(s
, IEEE80211_IOC_HIDESSID
, &val
) != -1) {
5013 LINE_CHECK("hidessid");
5015 LINE_CHECK("-hidessid");
5017 if (get80211val(s
, IEEE80211_IOC_APBRIDGE
, &val
) != -1) {
5019 LINE_CHECK("-apbridge");
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) {
5028 LINE_CHECK("-doth");
5032 if (get80211val(s
, IEEE80211_IOC_DFS
, &val
) != -1) {
5038 if (get80211val(s
, IEEE80211_IOC_INACTIVITY
, &val
) != -1) {
5040 LINE_CHECK("-inact");
5042 LINE_CHECK("inact");
5045 if (get80211val(s
, IEEE80211_IOC_ROAMING
, &val
) != -1) {
5046 if (val
!= IEEE80211_ROAMING_AUTO
|| verbose
) {
5048 case IEEE80211_ROAMING_DEVICE
:
5049 LINE_CHECK("roaming DEVICE");
5051 case IEEE80211_ROAMING_AUTO
:
5052 LINE_CHECK("roaming AUTO");
5054 case IEEE80211_ROAMING_MANUAL
:
5055 LINE_CHECK("roaming MANUAL");
5058 LINE_CHECK("roaming UNKNOWN (0x%x)",
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
) {
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) {
5092 LINE_CHECK("meshpeering");
5094 LINE_CHECK("-meshpeering");
5096 if (get80211val(s
, IEEE80211_IOC_MESH_FWRD
, &val
) != -1) {
5098 LINE_CHECK("meshforward");
5100 LINE_CHECK("-meshforward");
5102 if (get80211len(s
, IEEE80211_IOC_MESH_PR_METRIC
, data
, 12,
5105 LINE_CHECK("meshmetric %s", data
);
5107 if (get80211len(s
, IEEE80211_IOC_MESH_PR_PATH
, data
, 12,
5110 LINE_CHECK("meshpath %s", data
);
5112 if (get80211val(s
, IEEE80211_IOC_HWMP_ROOTMODE
, &val
) != -1) {
5114 case IEEE80211_HWMP_ROOTMODE_DISABLED
:
5115 LINE_CHECK("hwmprootmode DISABLED");
5117 case IEEE80211_HWMP_ROOTMODE_NORMAL
:
5118 LINE_CHECK("hwmprootmode NORMAL");
5120 case IEEE80211_HWMP_ROOTMODE_PROACTIVE
:
5121 LINE_CHECK("hwmprootmode PROACTIVE");
5123 case IEEE80211_HWMP_ROOTMODE_RANN
:
5124 LINE_CHECK("hwmprootmode RANN");
5127 LINE_CHECK("hwmprootmode UNKNOWN(%d)", val
);
5131 if (get80211val(s
, IEEE80211_IOC_HWMP_MAXHOPS
, &val
) != -1) {
5132 LINE_CHECK("hwmpmaxhops %u", val
);
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
));
5149 return ioctl(s
, SIOCG80211
, &ireq
);
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
));
5161 assert(ireq
.i_len
== len
); /* NB: check for 16-bit truncation */
5163 if (ioctl(s
, SIOCG80211
, &ireq
) < 0)
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
));
5177 if (ioctl(s
, SIOCG80211
, &ireq
) < 0)
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
));
5193 assert(ireq
.i_len
== len
); /* NB: check for 16-bit truncation */
5195 if (ioctl(s
, SIOCS80211
, &ireq
) < 0)
5196 err(1, "SIOCS80211");
5200 get_string(const char *val
, const char *sep
, u_int8_t
*buf
, int *lenp
)
5208 hexstr
= (val
[0] == '0' && tolower((u_char
)val
[1]) == 'x');
5214 if (sep
!= NULL
&& strchr(sep
, *val
) != NULL
) {
5219 if (!isxdigit((u_char
)val
[0])) {
5220 warnx("bad hexadecimal digits");
5223 if (!isxdigit((u_char
)val
[1])) {
5224 warnx("odd count hexadecimal digits");
5228 if (p
>= buf
+ len
) {
5230 warnx("hexadecimal digits too long");
5232 warnx("string too long");
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]);
5245 /* The string "-" is treated as the empty string. */
5246 if (!hexstr
&& len
== 1 && buf
[0] == '-') {
5248 memset(buf
, 0, *lenp
);
5249 } else if (len
< *lenp
)
5250 memset(p
, 0, *lenp
- len
);
5256 print_string(const u_int8_t
*buf
, int len
)
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
)
5271 if (isspace(buf
[i
]))
5274 if (i
== len
|| utf8
) {
5275 if (hasspc
|| len
== 0 || buf
[0] == '\0')
5276 printf("\"%.*s\"", len
, buf
);
5278 printf("%.*s", len
, buf
);
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 */
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 "
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
= ¶ms
;
5305 if (ioctl(s
, SIOCIFCREATE2
, ifr
) < 0)
5306 err(1, "SIOCIFCREATE2");
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
);
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
);
5324 errx(1, "%s: cannot parse bssid", arg
);
5325 memcpy(params
.icp_bssid
, ea
->octet
, IEEE80211_ADDR_LEN
);
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
);
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
;
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
;
5363 errx(1, "Don't know to create %s for %s", arg
, IfName
);
5367 set80211clone_beacons(const char *val __unused
, int d
, int s __unused
,
5368 const struct afswtch
*rafp __unused
)
5370 /* NB: inverted sense */
5372 params
.icp_flags
&= ~IEEE80211_CLONE_NOBEACONS
;
5374 params
.icp_flags
|= IEEE80211_CLONE_NOBEACONS
;
5378 set80211clone_bssid(const char *val __unused
, int d
, int s __unused
,
5379 const struct afswtch
*rafp __unused
)
5382 params
.icp_flags
|= IEEE80211_CLONE_BSSID
;
5384 params
.icp_flags
&= ~IEEE80211_CLONE_BSSID
;
5388 set80211clone_wdslegacy(const char *val __unused
, int d
, int s __unused
,
5389 const struct afswtch
*rafp __unused
)
5392 params
.icp_flags
|= IEEE80211_CLONE_WDSLEGACY
;
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",
5570 .af_other_status
= ieee80211_status
,
5575 ieee80211_ctor(void)
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
);