Deleted Added
full compact
ifieee80211.c (170588) ifieee80211.c (173275)
1/*
2 * Copyright 2001 The Aerospace Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of The Aerospace Corporation may not be used to endorse or
13 * promote products derived from this software.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
1/*
2 * Copyright 2001 The Aerospace Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of The Aerospace Corporation may not be used to endorse or
13 * promote products derived from this software.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 170588 2007-06-12 00:52:40Z thompsa $
27 * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 173275 2007-11-02 05:24:57Z sam $
28 */
29
30/*-
31 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32 * All rights reserved.
33 *
34 * This code is derived from software contributed to The NetBSD Foundation
35 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36 * NASA Ames Research Center.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the NetBSD
49 * Foundation, Inc. and its contributors.
50 * 4. Neither the name of The NetBSD Foundation nor the names of its
51 * contributors may be used to endorse or promote products derived
52 * from this software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64 * POSSIBILITY OF SUCH DAMAGE.
65 */
66
67#include <sys/param.h>
68#include <sys/ioctl.h>
69#include <sys/socket.h>
70#include <sys/sysctl.h>
71#include <sys/time.h>
72
73#include <net/ethernet.h>
74#include <net/if.h>
75#include <net/if_dl.h>
76#include <net/if_types.h>
77#include <net/if_media.h>
78#include <net/route.h>
79
80#include <net80211/ieee80211.h>
81#include <net80211/ieee80211_crypto.h>
82#include <net80211/ieee80211_ioctl.h>
83
84#include <ctype.h>
85#include <err.h>
86#include <errno.h>
87#include <fcntl.h>
88#include <inttypes.h>
89#include <stdio.h>
90#include <stdlib.h>
91#include <string.h>
92#include <unistd.h>
93#include <stdarg.h>
28 */
29
30/*-
31 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32 * All rights reserved.
33 *
34 * This code is derived from software contributed to The NetBSD Foundation
35 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36 * NASA Ames Research Center.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the NetBSD
49 * Foundation, Inc. and its contributors.
50 * 4. Neither the name of The NetBSD Foundation nor the names of its
51 * contributors may be used to endorse or promote products derived
52 * from this software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64 * POSSIBILITY OF SUCH DAMAGE.
65 */
66
67#include <sys/param.h>
68#include <sys/ioctl.h>
69#include <sys/socket.h>
70#include <sys/sysctl.h>
71#include <sys/time.h>
72
73#include <net/ethernet.h>
74#include <net/if.h>
75#include <net/if_dl.h>
76#include <net/if_types.h>
77#include <net/if_media.h>
78#include <net/route.h>
79
80#include <net80211/ieee80211.h>
81#include <net80211/ieee80211_crypto.h>
82#include <net80211/ieee80211_ioctl.h>
83
84#include <ctype.h>
85#include <err.h>
86#include <errno.h>
87#include <fcntl.h>
88#include <inttypes.h>
89#include <stdio.h>
90#include <stdlib.h>
91#include <string.h>
92#include <unistd.h>
93#include <stdarg.h>
94#include <stddef.h> /* NB: for offsetof */
94
95#include "ifconfig.h"
96
95
96#include "ifconfig.h"
97
98#define MAXCOL 78
99static int col;
100static char spacer;
101
102static void LINE_INIT(char c);
103static void LINE_BREAK(void);
104static void LINE_CHECK(const char *fmt, ...);
105
106/* XXX need max array size */
107static const int htrates[16] = {
108 13, /* IFM_IEEE80211_MCS0 */
109 26, /* IFM_IEEE80211_MCS1 */
110 39, /* IFM_IEEE80211_MCS2 */
111 52, /* IFM_IEEE80211_MCS3 */
112 78, /* IFM_IEEE80211_MCS4 */
113 104, /* IFM_IEEE80211_MCS5 */
114 117, /* IFM_IEEE80211_MCS6 */
115 130, /* IFM_IEEE80211_MCS7 */
116 26, /* IFM_IEEE80211_MCS8 */
117 52, /* IFM_IEEE80211_MCS9 */
118 78, /* IFM_IEEE80211_MCS10 */
119 104, /* IFM_IEEE80211_MCS11 */
120 156, /* IFM_IEEE80211_MCS12 */
121 208, /* IFM_IEEE80211_MCS13 */
122 234, /* IFM_IEEE80211_MCS14 */
123 260, /* IFM_IEEE80211_MCS15 */
124};
125
126static int get80211(int s, int type, void *data, int len);
127static int get80211len(int s, int type, void *data, int len, int *plen);
128static int get80211val(int s, int type, int *val);
97static void set80211(int s, int type, int val, int len, void *data);
98static const char *get_string(const char *val, const char *sep,
99 u_int8_t *buf, int *lenp);
100static void print_string(const u_int8_t *buf, int len);
101
102static struct ieee80211req_chaninfo chaninfo;
103static struct ifmediareq *ifmr;
129static void set80211(int s, int type, int val, int len, void *data);
130static const char *get_string(const char *val, const char *sep,
131 u_int8_t *buf, int *lenp);
132static void print_string(const u_int8_t *buf, int len);
133
134static struct ieee80211req_chaninfo chaninfo;
135static struct ifmediareq *ifmr;
136static struct ieee80211_channel curchan;
137static int gotcurchan = 0;
138static int htconf = 0;
139static int gothtconf = 0;
104
140
141static void
142gethtconf(int s)
143{
144 if (gothtconf)
145 return;
146 if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0)
147 warn("unable to get HT configuration information");
148 gothtconf = 1;
149}
150
105/*
106 * Collect channel info from the kernel. We use this (mostly)
107 * to handle mapping between frequency and IEEE channel number.
108 */
109static void
110getchaninfo(int s)
111{
151/*
152 * Collect channel info from the kernel. We use this (mostly)
153 * to handle mapping between frequency and IEEE channel number.
154 */
155static void
156getchaninfo(int s)
157{
112 struct ieee80211req ireq;
113
114 if (chaninfo.ic_nchans != 0)
115 return;
158 if (chaninfo.ic_nchans != 0)
159 return;
116 (void) memset(&ireq, 0, sizeof(ireq));
117 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
118 ireq.i_type = IEEE80211_IOC_CHANINFO;
119 ireq.i_data = &chaninfo;
120 ireq.i_len = sizeof(chaninfo);
121 if (ioctl(s, SIOCG80211, &ireq) < 0)
160 if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0)
122 errx(1, "unable to get channel information");
123
124 ifmr = ifmedia_getstate(s);
161 errx(1, "unable to get channel information");
162
163 ifmr = ifmedia_getstate(s);
164 gethtconf(s);
125}
126
127/*
128 * Given the channel at index i with attributes from,
129 * check if there is a channel with attributes to in
130 * the channel table. With suitable attributes this
131 * allows the caller to look for promotion; e.g. from
132 * 11b > 11g.
133 */
134static int
135canpromote(int i, int from, int to)
136{
137 const struct ieee80211_channel *fc = &chaninfo.ic_chans[i];
138 int j;
139
140 if ((fc->ic_flags & from) != from)
141 return i;
142 /* NB: quick check exploiting ordering of chans w/ same frequency */
143 if (i+1 < chaninfo.ic_nchans &&
144 chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq &&
145 (chaninfo.ic_chans[i+1].ic_flags & to) == to)
146 return i+1;
147 /* brute force search in case channel list is not ordered */
148 for (j = 0; j < chaninfo.ic_nchans; j++) {
149 const struct ieee80211_channel *tc = &chaninfo.ic_chans[j];
150 if (j != i &&
151 tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
152 return j;
153 }
154 return i;
155}
156
157/*
158 * Handle channel promotion. When a channel is specified with
159 * only a frequency we want to promote it to the ``best'' channel
160 * available. The channel list has separate entries for 11b, 11g,
161 * 11a, and 11n[ga] channels so specifying a frequency w/o any
162 * attributes requires we upgrade, e.g. from 11b -> 11g. This
163 * gets complicated when the channel is specified on the same
164 * command line with a media request that constrains the available
165 * channe list (e.g. mode 11a); we want to honor that to avoid
166 * confusing behaviour.
167 */
168static int
169promote(int i)
170{
171 /*
172 * Query the current mode of the interface in case it's
173 * constrained (e.g. to 11a). We must do this carefully
174 * as there may be a pending ifmedia request in which case
175 * asking the kernel will give us the wrong answer. This
176 * is an unfortunate side-effect of the way ifconfig is
177 * structure for modularity (yech).
178 *
179 * NB: ifmr is actually setup in getchaninfo (above); we
180 * assume it's called coincident with to this call so
181 * we have a ``current setting''; otherwise we must pass
182 * the socket descriptor down to here so we can make
183 * the ifmedia_getstate call ourselves.
184 */
185 int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
186
187 /* when ambiguous promote to ``best'' */
188 /* NB: we abitrarily pick HT40+ over HT40- */
189 if (chanmode != IFM_IEEE80211_11B)
190 i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
165}
166
167/*
168 * Given the channel at index i with attributes from,
169 * check if there is a channel with attributes to in
170 * the channel table. With suitable attributes this
171 * allows the caller to look for promotion; e.g. from
172 * 11b > 11g.
173 */
174static int
175canpromote(int i, int from, int to)
176{
177 const struct ieee80211_channel *fc = &chaninfo.ic_chans[i];
178 int j;
179
180 if ((fc->ic_flags & from) != from)
181 return i;
182 /* NB: quick check exploiting ordering of chans w/ same frequency */
183 if (i+1 < chaninfo.ic_nchans &&
184 chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq &&
185 (chaninfo.ic_chans[i+1].ic_flags & to) == to)
186 return i+1;
187 /* brute force search in case channel list is not ordered */
188 for (j = 0; j < chaninfo.ic_nchans; j++) {
189 const struct ieee80211_channel *tc = &chaninfo.ic_chans[j];
190 if (j != i &&
191 tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
192 return j;
193 }
194 return i;
195}
196
197/*
198 * Handle channel promotion. When a channel is specified with
199 * only a frequency we want to promote it to the ``best'' channel
200 * available. The channel list has separate entries for 11b, 11g,
201 * 11a, and 11n[ga] channels so specifying a frequency w/o any
202 * attributes requires we upgrade, e.g. from 11b -> 11g. This
203 * gets complicated when the channel is specified on the same
204 * command line with a media request that constrains the available
205 * channe list (e.g. mode 11a); we want to honor that to avoid
206 * confusing behaviour.
207 */
208static int
209promote(int i)
210{
211 /*
212 * Query the current mode of the interface in case it's
213 * constrained (e.g. to 11a). We must do this carefully
214 * as there may be a pending ifmedia request in which case
215 * asking the kernel will give us the wrong answer. This
216 * is an unfortunate side-effect of the way ifconfig is
217 * structure for modularity (yech).
218 *
219 * NB: ifmr is actually setup in getchaninfo (above); we
220 * assume it's called coincident with to this call so
221 * we have a ``current setting''; otherwise we must pass
222 * the socket descriptor down to here so we can make
223 * the ifmedia_getstate call ourselves.
224 */
225 int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
226
227 /* when ambiguous promote to ``best'' */
228 /* NB: we abitrarily pick HT40+ over HT40- */
229 if (chanmode != IFM_IEEE80211_11B)
230 i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
191 if (chanmode != IFM_IEEE80211_11G) {
231 if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
192 i = canpromote(i, IEEE80211_CHAN_G,
193 IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
232 i = canpromote(i, IEEE80211_CHAN_G,
233 IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
194 i = canpromote(i, IEEE80211_CHAN_G,
195 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
196 i = canpromote(i, IEEE80211_CHAN_G,
197 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
234 if (htconf & 2) {
235 i = canpromote(i, IEEE80211_CHAN_G,
236 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
237 i = canpromote(i, IEEE80211_CHAN_G,
238 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
239 }
198 }
240 }
199 if (chanmode != IFM_IEEE80211_11A) {
241 if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
200 i = canpromote(i, IEEE80211_CHAN_A,
201 IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
242 i = canpromote(i, IEEE80211_CHAN_A,
243 IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
202 i = canpromote(i, IEEE80211_CHAN_A,
203 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
204 i = canpromote(i, IEEE80211_CHAN_A,
205 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
244 if (htconf & 2) {
245 i = canpromote(i, IEEE80211_CHAN_A,
246 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
247 i = canpromote(i, IEEE80211_CHAN_A,
248 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
249 }
206 }
207 return i;
208}
209
210static void
211mapfreq(struct ieee80211_channel *chan, int freq, int flags)
212{
213 int i;
214
215 for (i = 0; i < chaninfo.ic_nchans; i++) {
216 const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
217
218 if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
219 if (flags == 0) {
220 /* when ambiguous promote to ``best'' */
221 c = &chaninfo.ic_chans[promote(i)];
222 }
223 *chan = *c;
224 return;
225 }
226 }
227 errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
228}
229
230static void
231mapchan(struct ieee80211_channel *chan, int ieee, int flags)
232{
233 int i;
234
235 for (i = 0; i < chaninfo.ic_nchans; i++) {
236 const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
237
238 if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
239 if (flags == 0) {
240 /* when ambiguous promote to ``best'' */
241 c = &chaninfo.ic_chans[promote(i)];
242 }
243 *chan = *c;
244 return;
245 }
246 }
250 }
251 return i;
252}
253
254static void
255mapfreq(struct ieee80211_channel *chan, int freq, int flags)
256{
257 int i;
258
259 for (i = 0; i < chaninfo.ic_nchans; i++) {
260 const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
261
262 if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
263 if (flags == 0) {
264 /* when ambiguous promote to ``best'' */
265 c = &chaninfo.ic_chans[promote(i)];
266 }
267 *chan = *c;
268 return;
269 }
270 }
271 errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
272}
273
274static void
275mapchan(struct ieee80211_channel *chan, int ieee, int flags)
276{
277 int i;
278
279 for (i = 0; i < chaninfo.ic_nchans; i++) {
280 const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
281
282 if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
283 if (flags == 0) {
284 /* when ambiguous promote to ``best'' */
285 c = &chaninfo.ic_chans[promote(i)];
286 }
287 *chan = *c;
288 return;
289 }
290 }
247 errx(1, "unknown/undefined channel number %d", ieee);
291 errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
248}
249
292}
293
294static const struct ieee80211_channel *
295getcurchan(int s)
296{
297 if (gotcurchan)
298 return &curchan;
299 if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
300 int val;
301 /* fall back to legacy ioctl */
302 if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
303 errx(-1, "cannot figure out current channel");
304 getchaninfo(s);
305 mapchan(&curchan, val, 0);
306 }
307 gotcurchan = 1;
308 return &curchan;
309}
310
250static int
251ieee80211_mhz2ieee(int freq, int flags)
252{
253 struct ieee80211_channel chan;
254 mapfreq(&chan, freq, flags);
255 return chan.ic_ieee;
256}
257
258static int
259isanyarg(const char *arg)
260{
311static int
312ieee80211_mhz2ieee(int freq, int flags)
313{
314 struct ieee80211_channel chan;
315 mapfreq(&chan, freq, flags);
316 return chan.ic_ieee;
317}
318
319static int
320isanyarg(const char *arg)
321{
261 return (strcmp(arg, "-") == 0 ||
262 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
322 return (strncmp(arg, "-", 1) == 0 ||
323 strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0);
263}
264
265static void
266set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
267{
268 int ssid;
269 int len;
270 u_int8_t data[IEEE80211_NWID_LEN];
271
272 ssid = 0;
273 len = strlen(val);
274 if (len > 2 && isdigit(val[0]) && val[1] == ':') {
275 ssid = atoi(val)-1;
276 val += 2;
277 }
278
279 bzero(data, sizeof(data));
280 len = sizeof(data);
281 if (get_string(val, NULL, data, &len) == NULL)
282 exit(1);
283
284 set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
285}
286
287static void
288set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
289{
290 int len;
291 u_int8_t data[33];
292
293 bzero(data, sizeof(data));
294 len = sizeof(data);
295 get_string(val, NULL, data, &len);
296
297 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
298}
299
300/*
301 * Parse a channel specification for attributes/flags.
302 * The syntax is:
303 * freq/xx channel width (5,10,20,40,40+,40-)
304 * freq:mode channel mode (a,b,g,h,n,t,s,d)
305 *
306 * These can be combined in either order; e.g. 2437:ng/40.
307 * Modes are case insensitive.
308 *
309 * The result is not validated here; it's assumed to be
310 * checked against the channel table fetched from the kernel.
311 */
312static int
324}
325
326static void
327set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
328{
329 int ssid;
330 int len;
331 u_int8_t data[IEEE80211_NWID_LEN];
332
333 ssid = 0;
334 len = strlen(val);
335 if (len > 2 && isdigit(val[0]) && val[1] == ':') {
336 ssid = atoi(val)-1;
337 val += 2;
338 }
339
340 bzero(data, sizeof(data));
341 len = sizeof(data);
342 if (get_string(val, NULL, data, &len) == NULL)
343 exit(1);
344
345 set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
346}
347
348static void
349set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
350{
351 int len;
352 u_int8_t data[33];
353
354 bzero(data, sizeof(data));
355 len = sizeof(data);
356 get_string(val, NULL, data, &len);
357
358 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
359}
360
361/*
362 * Parse a channel specification for attributes/flags.
363 * The syntax is:
364 * freq/xx channel width (5,10,20,40,40+,40-)
365 * freq:mode channel mode (a,b,g,h,n,t,s,d)
366 *
367 * These can be combined in either order; e.g. 2437:ng/40.
368 * Modes are case insensitive.
369 *
370 * The result is not validated here; it's assumed to be
371 * checked against the channel table fetched from the kernel.
372 */
373static int
313getchannelflags(const char *val)
374getchannelflags(const char *val, int freq)
314{
375{
315#define CHAN_HT_DEFAULT IEEE80211_CHAN_HT40U
316#define _CHAN_HT 0x80000000
317 const char *cp;
318 int flags;
319
320 flags = 0;
321
322 cp = strchr(val, ':');
323 if (cp != NULL) {
324 for (cp++; isalpha((int) *cp); cp++) {
325 /* accept mixed case */
326 int c = *cp;
327 if (isupper(c))
328 c = tolower(c);
329 switch (c) {
330 case 'a': /* 802.11a */
331 flags |= IEEE80211_CHAN_A;
332 break;
333 case 'b': /* 802.11b */
334 flags |= IEEE80211_CHAN_B;
335 break;
336 case 'g': /* 802.11g */
337 flags |= IEEE80211_CHAN_G;
338 break;
339 case 'h': /* ht = 802.11n */
340 case 'n': /* 802.11n */
341 flags |= _CHAN_HT; /* NB: private */
342 break;
343 case 'd': /* dt = Atheros Dynamic Turbo */
344 flags |= IEEE80211_CHAN_TURBO;
345 break;
346 case 't': /* ht, dt, st, t */
347 /* dt and unadorned t specify Dynamic Turbo */
348 if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
349 flags |= IEEE80211_CHAN_TURBO;
350 break;
351 case 's': /* st = Atheros Static Turbo */
352 flags |= IEEE80211_CHAN_STURBO;
353 break;
354 default:
376#define _CHAN_HT 0x80000000
377 const char *cp;
378 int flags;
379
380 flags = 0;
381
382 cp = strchr(val, ':');
383 if (cp != NULL) {
384 for (cp++; isalpha((int) *cp); cp++) {
385 /* accept mixed case */
386 int c = *cp;
387 if (isupper(c))
388 c = tolower(c);
389 switch (c) {
390 case 'a': /* 802.11a */
391 flags |= IEEE80211_CHAN_A;
392 break;
393 case 'b': /* 802.11b */
394 flags |= IEEE80211_CHAN_B;
395 break;
396 case 'g': /* 802.11g */
397 flags |= IEEE80211_CHAN_G;
398 break;
399 case 'h': /* ht = 802.11n */
400 case 'n': /* 802.11n */
401 flags |= _CHAN_HT; /* NB: private */
402 break;
403 case 'd': /* dt = Atheros Dynamic Turbo */
404 flags |= IEEE80211_CHAN_TURBO;
405 break;
406 case 't': /* ht, dt, st, t */
407 /* dt and unadorned t specify Dynamic Turbo */
408 if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
409 flags |= IEEE80211_CHAN_TURBO;
410 break;
411 case 's': /* st = Atheros Static Turbo */
412 flags |= IEEE80211_CHAN_STURBO;
413 break;
414 default:
355 errx(-1, "%s: Invalid channel attribute %c",
415 errx(-1, "%s: Invalid channel attribute %c\n",
356 val, *cp);
357 }
358 }
359 }
360 cp = strchr(val, '/');
361 if (cp != NULL) {
362 char *ep;
363 u_long cw = strtoul(cp+1, &ep, 10);
364
365 switch (cw) {
366 case 5:
367 flags |= IEEE80211_CHAN_QUARTER;
368 break;
369 case 10:
370 flags |= IEEE80211_CHAN_HALF;
371 break;
372 case 20:
373 /* NB: this may be removed below */
374 flags |= IEEE80211_CHAN_HT20;
375 break;
376 case 40:
377 if (ep != NULL && *ep == '+')
378 flags |= IEEE80211_CHAN_HT40U;
379 else if (ep != NULL && *ep == '-')
380 flags |= IEEE80211_CHAN_HT40D;
416 val, *cp);
417 }
418 }
419 }
420 cp = strchr(val, '/');
421 if (cp != NULL) {
422 char *ep;
423 u_long cw = strtoul(cp+1, &ep, 10);
424
425 switch (cw) {
426 case 5:
427 flags |= IEEE80211_CHAN_QUARTER;
428 break;
429 case 10:
430 flags |= IEEE80211_CHAN_HALF;
431 break;
432 case 20:
433 /* NB: this may be removed below */
434 flags |= IEEE80211_CHAN_HT20;
435 break;
436 case 40:
437 if (ep != NULL && *ep == '+')
438 flags |= IEEE80211_CHAN_HT40U;
439 else if (ep != NULL && *ep == '-')
440 flags |= IEEE80211_CHAN_HT40D;
381 else /* NB: pick something */
382 flags |= CHAN_HT_DEFAULT;
383 break;
384 default:
441 break;
442 default:
385 errx(-1, "%s: Invalid channel width", val);
443 errx(-1, "%s: Invalid channel width\n", val);
386 }
387 }
388 /*
389 * Cleanup specifications.
390 */
391 if ((flags & _CHAN_HT) == 0) {
392 /*
393 * If user specified freq/20 or freq/40 quietly remove
394 * HT cw attributes depending on channel use. To give
395 * an explicit 20/40 width for an HT channel you must
396 * indicate it is an HT channel since all HT channels
397 * are also usable for legacy operation; e.g. freq:n/40.
398 */
399 flags &= ~IEEE80211_CHAN_HT;
400 } else {
401 /*
402 * Remove private indicator that this is an HT channel
403 * and if no explicit channel width has been given
404 * provide the default settings.
405 */
406 flags &= ~_CHAN_HT;
444 }
445 }
446 /*
447 * Cleanup specifications.
448 */
449 if ((flags & _CHAN_HT) == 0) {
450 /*
451 * If user specified freq/20 or freq/40 quietly remove
452 * HT cw attributes depending on channel use. To give
453 * an explicit 20/40 width for an HT channel you must
454 * indicate it is an HT channel since all HT channels
455 * are also usable for legacy operation; e.g. freq:n/40.
456 */
457 flags &= ~IEEE80211_CHAN_HT;
458 } else {
459 /*
460 * Remove private indicator that this is an HT channel
461 * and if no explicit channel width has been given
462 * provide the default settings.
463 */
464 flags &= ~_CHAN_HT;
407 if ((flags & IEEE80211_CHAN_HT) == 0)
408 flags |= CHAN_HT_DEFAULT;
465 if ((flags & IEEE80211_CHAN_HT) == 0) {
466 struct ieee80211_channel chan;
467 /*
468 * Consult the channel list to see if we can use
469 * HT40+ or HT40- (if both the map routines choose).
470 */
471 if (freq > 255)
472 mapfreq(&chan, freq, 0);
473 else
474 mapchan(&chan, freq, 0);
475 flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
476 }
409 }
410 return flags;
477 }
478 return flags;
411#undef CHAN_HT_DEFAULT
412#undef _CHAN_HT
413}
414
415static void
416set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
417{
418 struct ieee80211_channel chan;
419
420 memset(&chan, 0, sizeof(chan));
421 if (!isanyarg(val)) {
479#undef _CHAN_HT
480}
481
482static void
483set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
484{
485 struct ieee80211_channel chan;
486
487 memset(&chan, 0, sizeof(chan));
488 if (!isanyarg(val)) {
422 int v = atoi(val);
423 int flags = getchannelflags(val);
489 int v, flags;
424
425 getchaninfo(s);
490
491 getchaninfo(s);
492 v = atoi(val);
493 flags = getchannelflags(val, v);
426 if (v > 255) { /* treat as frequency */
427 mapfreq(&chan, v, flags);
428 } else {
429 mapchan(&chan, v, flags);
430 }
431 } else {
432 chan.ic_freq = IEEE80211_CHAN_ANY;
433 }
434 set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
435}
436
437static void
438set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
439{
440 int mode;
441
442 if (strcasecmp(val, "none") == 0) {
443 mode = IEEE80211_AUTH_NONE;
444 } else if (strcasecmp(val, "open") == 0) {
445 mode = IEEE80211_AUTH_OPEN;
446 } else if (strcasecmp(val, "shared") == 0) {
447 mode = IEEE80211_AUTH_SHARED;
448 } else if (strcasecmp(val, "8021x") == 0) {
449 mode = IEEE80211_AUTH_8021X;
450 } else if (strcasecmp(val, "wpa") == 0) {
451 mode = IEEE80211_AUTH_WPA;
452 } else {
453 errx(1, "unknown authmode");
454 }
455
456 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
457}
458
459static void
460set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
461{
462 int mode;
463
464 if (strcasecmp(val, "off") == 0) {
465 mode = IEEE80211_POWERSAVE_OFF;
466 } else if (strcasecmp(val, "on") == 0) {
467 mode = IEEE80211_POWERSAVE_ON;
468 } else if (strcasecmp(val, "cam") == 0) {
469 mode = IEEE80211_POWERSAVE_CAM;
470 } else if (strcasecmp(val, "psp") == 0) {
471 mode = IEEE80211_POWERSAVE_PSP;
472 } else if (strcasecmp(val, "psp-cam") == 0) {
473 mode = IEEE80211_POWERSAVE_PSP_CAM;
474 } else {
475 errx(1, "unknown powersavemode");
476 }
477
478 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
479}
480
481static void
482set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
483{
484 if (d == 0)
485 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
486 0, NULL);
487 else
488 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
489 0, NULL);
490}
491
492static void
493set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
494{
495 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
496}
497
498static void
499set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
500{
501 int mode;
502
503 if (strcasecmp(val, "off") == 0) {
504 mode = IEEE80211_WEP_OFF;
505 } else if (strcasecmp(val, "on") == 0) {
506 mode = IEEE80211_WEP_ON;
507 } else if (strcasecmp(val, "mixed") == 0) {
508 mode = IEEE80211_WEP_MIXED;
509 } else {
510 errx(1, "unknown wep mode");
511 }
512
513 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
514}
515
516static void
517set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
518{
519 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
520}
521
522static int
523isundefarg(const char *arg)
524{
525 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
526}
527
528static void
529set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
530{
531 if (isundefarg(val))
532 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
533 else
534 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
535}
536
537static void
538set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
539{
540 int key = 0;
541 int len;
542 u_int8_t data[IEEE80211_KEYBUF_SIZE];
543
544 if (isdigit(val[0]) && val[1] == ':') {
545 key = atoi(val)-1;
546 val += 2;
547 }
548
549 bzero(data, sizeof(data));
550 len = sizeof(data);
551 get_string(val, NULL, data, &len);
552
553 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
554}
555
556/*
557 * This function is purely a NetBSD compatability interface. The NetBSD
558 * interface is too inflexible, but it's there so we'll support it since
559 * it's not all that hard.
560 */
561static void
562set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
563{
564 int txkey;
565 int i, len;
566 u_int8_t data[IEEE80211_KEYBUF_SIZE];
567
568 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
569
570 if (isdigit(val[0]) && val[1] == ':') {
571 txkey = val[0]-'0'-1;
572 val += 2;
573
574 for (i = 0; i < 4; i++) {
575 bzero(data, sizeof(data));
576 len = sizeof(data);
577 val = get_string(val, ",", data, &len);
578 if (val == NULL)
579 exit(1);
580
581 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
582 }
583 } else {
584 bzero(data, sizeof(data));
585 len = sizeof(data);
586 get_string(val, NULL, data, &len);
587 txkey = 0;
588
589 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
590
591 bzero(data, sizeof(data));
592 for (i = 1; i < 4; i++)
593 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
594 }
595
596 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
597}
598
599static void
600set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
601{
602 set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
603 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
604}
605
606static void
607set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
608{
609 int mode;
610
611 if (strcasecmp(val, "off") == 0) {
612 mode = IEEE80211_PROTMODE_OFF;
613 } else if (strcasecmp(val, "cts") == 0) {
614 mode = IEEE80211_PROTMODE_CTS;
494 if (v > 255) { /* treat as frequency */
495 mapfreq(&chan, v, flags);
496 } else {
497 mapchan(&chan, v, flags);
498 }
499 } else {
500 chan.ic_freq = IEEE80211_CHAN_ANY;
501 }
502 set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
503}
504
505static void
506set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
507{
508 int mode;
509
510 if (strcasecmp(val, "none") == 0) {
511 mode = IEEE80211_AUTH_NONE;
512 } else if (strcasecmp(val, "open") == 0) {
513 mode = IEEE80211_AUTH_OPEN;
514 } else if (strcasecmp(val, "shared") == 0) {
515 mode = IEEE80211_AUTH_SHARED;
516 } else if (strcasecmp(val, "8021x") == 0) {
517 mode = IEEE80211_AUTH_8021X;
518 } else if (strcasecmp(val, "wpa") == 0) {
519 mode = IEEE80211_AUTH_WPA;
520 } else {
521 errx(1, "unknown authmode");
522 }
523
524 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
525}
526
527static void
528set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
529{
530 int mode;
531
532 if (strcasecmp(val, "off") == 0) {
533 mode = IEEE80211_POWERSAVE_OFF;
534 } else if (strcasecmp(val, "on") == 0) {
535 mode = IEEE80211_POWERSAVE_ON;
536 } else if (strcasecmp(val, "cam") == 0) {
537 mode = IEEE80211_POWERSAVE_CAM;
538 } else if (strcasecmp(val, "psp") == 0) {
539 mode = IEEE80211_POWERSAVE_PSP;
540 } else if (strcasecmp(val, "psp-cam") == 0) {
541 mode = IEEE80211_POWERSAVE_PSP_CAM;
542 } else {
543 errx(1, "unknown powersavemode");
544 }
545
546 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
547}
548
549static void
550set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
551{
552 if (d == 0)
553 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
554 0, NULL);
555 else
556 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
557 0, NULL);
558}
559
560static void
561set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
562{
563 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
564}
565
566static void
567set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
568{
569 int mode;
570
571 if (strcasecmp(val, "off") == 0) {
572 mode = IEEE80211_WEP_OFF;
573 } else if (strcasecmp(val, "on") == 0) {
574 mode = IEEE80211_WEP_ON;
575 } else if (strcasecmp(val, "mixed") == 0) {
576 mode = IEEE80211_WEP_MIXED;
577 } else {
578 errx(1, "unknown wep mode");
579 }
580
581 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
582}
583
584static void
585set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
586{
587 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
588}
589
590static int
591isundefarg(const char *arg)
592{
593 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
594}
595
596static void
597set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
598{
599 if (isundefarg(val))
600 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
601 else
602 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
603}
604
605static void
606set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
607{
608 int key = 0;
609 int len;
610 u_int8_t data[IEEE80211_KEYBUF_SIZE];
611
612 if (isdigit(val[0]) && val[1] == ':') {
613 key = atoi(val)-1;
614 val += 2;
615 }
616
617 bzero(data, sizeof(data));
618 len = sizeof(data);
619 get_string(val, NULL, data, &len);
620
621 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
622}
623
624/*
625 * This function is purely a NetBSD compatability interface. The NetBSD
626 * interface is too inflexible, but it's there so we'll support it since
627 * it's not all that hard.
628 */
629static void
630set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
631{
632 int txkey;
633 int i, len;
634 u_int8_t data[IEEE80211_KEYBUF_SIZE];
635
636 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
637
638 if (isdigit(val[0]) && val[1] == ':') {
639 txkey = val[0]-'0'-1;
640 val += 2;
641
642 for (i = 0; i < 4; i++) {
643 bzero(data, sizeof(data));
644 len = sizeof(data);
645 val = get_string(val, ",", data, &len);
646 if (val == NULL)
647 exit(1);
648
649 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
650 }
651 } else {
652 bzero(data, sizeof(data));
653 len = sizeof(data);
654 get_string(val, NULL, data, &len);
655 txkey = 0;
656
657 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
658
659 bzero(data, sizeof(data));
660 for (i = 1; i < 4; i++)
661 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
662 }
663
664 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
665}
666
667static void
668set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
669{
670 set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
671 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
672}
673
674static void
675set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
676{
677 int mode;
678
679 if (strcasecmp(val, "off") == 0) {
680 mode = IEEE80211_PROTMODE_OFF;
681 } else if (strcasecmp(val, "cts") == 0) {
682 mode = IEEE80211_PROTMODE_CTS;
615 } else if (strcasecmp(val, "rtscts") == 0) {
683 } else if (strncasecmp(val, "rtscts", 3) == 0) {
616 mode = IEEE80211_PROTMODE_RTSCTS;
617 } else {
618 errx(1, "unknown protection mode");
619 }
620
621 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
622}
623
624static void
684 mode = IEEE80211_PROTMODE_RTSCTS;
685 } else {
686 errx(1, "unknown protection mode");
687 }
688
689 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
690}
691
692static void
693set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp)
694{
695 int mode;
696
697 if (strcasecmp(val, "off") == 0) {
698 mode = IEEE80211_PROTMODE_OFF;
699 } else if (strncasecmp(val, "rts", 3) == 0) {
700 mode = IEEE80211_PROTMODE_RTSCTS;
701 } else {
702 errx(1, "unknown protection mode");
703 }
704
705 set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
706}
707
708static void
625set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
626{
709set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
710{
627 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
711 double v = atof(val);
712 int txpow;
713
714 txpow = (int) (2*v);
715 if (txpow != 2*v)
716 errx(-1, "invalid tx power (must be .5 dBm units)");
717 set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
628}
629
630#define IEEE80211_ROAMING_DEVICE 0
631#define IEEE80211_ROAMING_AUTO 1
632#define IEEE80211_ROAMING_MANUAL 2
633
634static void
635set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
636{
637 int mode;
638
639 if (strcasecmp(val, "device") == 0) {
640 mode = IEEE80211_ROAMING_DEVICE;
641 } else if (strcasecmp(val, "auto") == 0) {
642 mode = IEEE80211_ROAMING_AUTO;
643 } else if (strcasecmp(val, "manual") == 0) {
644 mode = IEEE80211_ROAMING_MANUAL;
645 } else {
646 errx(1, "unknown roaming mode");
647 }
648 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
649}
650
651static void
652set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
653{
654 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
655}
656
657static void
658set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
659{
660 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
661}
662
663static void
664set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
665{
666 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
667}
668
669static void
670set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
671{
672 set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
673}
674
675static void
676set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
677{
678 set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
679}
680
681static void
682set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
683{
684 struct ieee80211req_chanlist chanlist;
685#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
686 char *temp, *cp, *tp;
687
688 temp = malloc(strlen(val) + 1);
689 if (temp == NULL)
690 errx(1, "malloc failed");
691 strcpy(temp, val);
692 memset(&chanlist, 0, sizeof(chanlist));
693 cp = temp;
694 for (;;) {
718}
719
720#define IEEE80211_ROAMING_DEVICE 0
721#define IEEE80211_ROAMING_AUTO 1
722#define IEEE80211_ROAMING_MANUAL 2
723
724static void
725set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
726{
727 int mode;
728
729 if (strcasecmp(val, "device") == 0) {
730 mode = IEEE80211_ROAMING_DEVICE;
731 } else if (strcasecmp(val, "auto") == 0) {
732 mode = IEEE80211_ROAMING_AUTO;
733 } else if (strcasecmp(val, "manual") == 0) {
734 mode = IEEE80211_ROAMING_MANUAL;
735 } else {
736 errx(1, "unknown roaming mode");
737 }
738 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
739}
740
741static void
742set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
743{
744 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
745}
746
747static void
748set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
749{
750 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
751}
752
753static void
754set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
755{
756 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
757}
758
759static void
760set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
761{
762 set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
763}
764
765static void
766set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
767{
768 set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
769}
770
771static void
772set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
773{
774 struct ieee80211req_chanlist chanlist;
775#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
776 char *temp, *cp, *tp;
777
778 temp = malloc(strlen(val) + 1);
779 if (temp == NULL)
780 errx(1, "malloc failed");
781 strcpy(temp, val);
782 memset(&chanlist, 0, sizeof(chanlist));
783 cp = temp;
784 for (;;) {
695 int first, last, f;
785 int first, last, f, c;
696
697 tp = strchr(cp, ',');
698 if (tp != NULL)
699 *tp++ = '\0';
700 switch (sscanf(cp, "%u-%u", &first, &last)) {
701 case 1:
702 if (first > MAXCHAN)
703 errx(-1, "channel %u out of range, max %zu",
704 first, MAXCHAN);
705 setbit(chanlist.ic_channels, first);
706 break;
707 case 2:
708 if (first > MAXCHAN)
709 errx(-1, "channel %u out of range, max %zu",
710 first, MAXCHAN);
711 if (last > MAXCHAN)
712 errx(-1, "channel %u out of range, max %zu",
713 last, MAXCHAN);
714 if (first > last)
715 errx(-1, "void channel range, %u > %u",
716 first, last);
717 for (f = first; f <= last; f++)
718 setbit(chanlist.ic_channels, f);
719 break;
720 }
721 if (tp == NULL)
722 break;
786
787 tp = strchr(cp, ',');
788 if (tp != NULL)
789 *tp++ = '\0';
790 switch (sscanf(cp, "%u-%u", &first, &last)) {
791 case 1:
792 if (first > MAXCHAN)
793 errx(-1, "channel %u out of range, max %zu",
794 first, MAXCHAN);
795 setbit(chanlist.ic_channels, first);
796 break;
797 case 2:
798 if (first > MAXCHAN)
799 errx(-1, "channel %u out of range, max %zu",
800 first, MAXCHAN);
801 if (last > MAXCHAN)
802 errx(-1, "channel %u out of range, max %zu",
803 last, MAXCHAN);
804 if (first > last)
805 errx(-1, "void channel range, %u > %u",
806 first, last);
807 for (f = first; f <= last; f++)
808 setbit(chanlist.ic_channels, f);
809 break;
810 }
811 if (tp == NULL)
812 break;
723 while (isspace(*tp))
813 c = *tp;
814 while (isspace(c))
724 tp++;
815 tp++;
725 if (!isdigit(*tp))
816 if (!isdigit(c))
726 break;
727 cp = tp;
728 }
729 set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
730#undef MAXCHAN
731}
732
733static void
734set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
735{
736
737 if (!isanyarg(val)) {
738 char *temp;
739 struct sockaddr_dl sdl;
740
741 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
742 if (temp == NULL)
743 errx(1, "malloc failed");
744 temp[0] = ':';
745 strcpy(temp + 1, val);
746 sdl.sdl_len = sizeof(sdl);
747 link_addr(temp, &sdl);
748 free(temp);
749 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
750 errx(1, "malformed link-level address");
751 set80211(s, IEEE80211_IOC_BSSID, 0,
752 IEEE80211_ADDR_LEN, LLADDR(&sdl));
753 } else {
754 uint8_t zerobssid[IEEE80211_ADDR_LEN];
755 memset(zerobssid, 0, sizeof(zerobssid));
756 set80211(s, IEEE80211_IOC_BSSID, 0,
757 IEEE80211_ADDR_LEN, zerobssid);
758 }
759}
760
761static int
762getac(const char *ac)
763{
764 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
765 return WME_AC_BE;
766 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
767 return WME_AC_BK;
768 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
769 return WME_AC_VI;
770 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
771 return WME_AC_VO;
772 errx(1, "unknown wme access class %s", ac);
773}
774
775static
776DECL_CMD_FUNC2(set80211cwmin, ac, val)
777{
778 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
779}
780
781static
782DECL_CMD_FUNC2(set80211cwmax, ac, val)
783{
784 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
785}
786
787static
788DECL_CMD_FUNC2(set80211aifs, ac, val)
789{
790 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
791}
792
793static
794DECL_CMD_FUNC2(set80211txoplimit, ac, val)
795{
796 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
797}
798
799static
800DECL_CMD_FUNC(set80211acm, ac, d)
801{
802 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
803}
804static
805DECL_CMD_FUNC(set80211noacm, ac, d)
806{
807 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
808}
809
810static
811DECL_CMD_FUNC(set80211ackpolicy, ac, d)
812{
813 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
814}
815static
816DECL_CMD_FUNC(set80211noackpolicy, ac, d)
817{
818 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
819}
820
821static
822DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
823{
824 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
825 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
826}
827
828static
829DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
830{
831 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
832 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
833}
834
835static
836DECL_CMD_FUNC2(set80211bssaifs, ac, val)
837{
838 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
839 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
840}
841
842static
843DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
844{
845 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
846 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
847}
848
849static
850DECL_CMD_FUNC(set80211dtimperiod, val, d)
851{
852 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
853}
854
855static
856DECL_CMD_FUNC(set80211bintval, val, d)
857{
858 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
859}
860
861static void
862set80211macmac(int s, int op, const char *val)
863{
864 char *temp;
865 struct sockaddr_dl sdl;
866
867 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
868 if (temp == NULL)
869 errx(1, "malloc failed");
870 temp[0] = ':';
871 strcpy(temp + 1, val);
872 sdl.sdl_len = sizeof(sdl);
873 link_addr(temp, &sdl);
874 free(temp);
875 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
876 errx(1, "malformed link-level address");
877 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
878}
879
880static
881DECL_CMD_FUNC(set80211addmac, val, d)
882{
883 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
884}
885
886static
887DECL_CMD_FUNC(set80211delmac, val, d)
888{
889 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
890}
891
892static
893DECL_CMD_FUNC(set80211kickmac, val, d)
894{
895 char *temp;
896 struct sockaddr_dl sdl;
897 struct ieee80211req_mlme mlme;
898
899 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
900 if (temp == NULL)
901 errx(1, "malloc failed");
902 temp[0] = ':';
903 strcpy(temp + 1, val);
904 sdl.sdl_len = sizeof(sdl);
905 link_addr(temp, &sdl);
906 free(temp);
907 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
908 errx(1, "malformed link-level address");
909 memset(&mlme, 0, sizeof(mlme));
910 mlme.im_op = IEEE80211_MLME_DEAUTH;
911 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
912 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
913 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
914}
915
916static
917DECL_CMD_FUNC(set80211maccmd, val, d)
918{
919 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
920}
921
922static void
923set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
924{
925 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
926}
927
928static void
929set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
930{
931 set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
932}
933
934static
935DECL_CMD_FUNC(set80211bgscanidle, val, d)
936{
937 set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
938}
939
940static
941DECL_CMD_FUNC(set80211bgscanintvl, val, d)
942{
943 set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
944}
945
946static
947DECL_CMD_FUNC(set80211scanvalid, val, d)
948{
949 set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
950}
951
952static
953DECL_CMD_FUNC(set80211roamrssi11a, val, d)
954{
955 set80211(s, IEEE80211_IOC_ROAM_RSSI_11A, atoi(val), 0, NULL);
956}
957
958static
959DECL_CMD_FUNC(set80211roamrssi11b, val, d)
960{
961 set80211(s, IEEE80211_IOC_ROAM_RSSI_11B, atoi(val), 0, NULL);
962}
963
964static
965DECL_CMD_FUNC(set80211roamrssi11g, val, d)
966{
967 set80211(s, IEEE80211_IOC_ROAM_RSSI_11G, atoi(val), 0, NULL);
968}
969
970static
971DECL_CMD_FUNC(set80211roamrate11a, val, d)
972{
973 set80211(s, IEEE80211_IOC_ROAM_RATE_11A, 2*atoi(val), 0, NULL);
974}
975
976static
977DECL_CMD_FUNC(set80211roamrate11b, val, d)
978{
979 set80211(s, IEEE80211_IOC_ROAM_RATE_11B, 2*atoi(val), 0, NULL);
980}
981
982static
983DECL_CMD_FUNC(set80211roamrate11g, val, d)
984{
985 set80211(s, IEEE80211_IOC_ROAM_RATE_11G, 2*atoi(val), 0, NULL);
986}
987
988static
989DECL_CMD_FUNC(set80211mcastrate, val, d)
990{
991 set80211(s, IEEE80211_IOC_MCAST_RATE, 2*atoi(val), 0, NULL);
992}
993
994static
995DECL_CMD_FUNC(set80211fragthreshold, val, d)
996{
997 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
998 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
999}
1000
1001static
1002DECL_CMD_FUNC(set80211bmissthreshold, val, d)
1003{
1004 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
1005 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
1006}
1007
1008static void
1009set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
1010{
1011 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
1012}
1013
1014static void
1015set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
1016{
1017 set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
1018}
1019
817 break;
818 cp = tp;
819 }
820 set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
821#undef MAXCHAN
822}
823
824static void
825set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
826{
827
828 if (!isanyarg(val)) {
829 char *temp;
830 struct sockaddr_dl sdl;
831
832 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
833 if (temp == NULL)
834 errx(1, "malloc failed");
835 temp[0] = ':';
836 strcpy(temp + 1, val);
837 sdl.sdl_len = sizeof(sdl);
838 link_addr(temp, &sdl);
839 free(temp);
840 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
841 errx(1, "malformed link-level address");
842 set80211(s, IEEE80211_IOC_BSSID, 0,
843 IEEE80211_ADDR_LEN, LLADDR(&sdl));
844 } else {
845 uint8_t zerobssid[IEEE80211_ADDR_LEN];
846 memset(zerobssid, 0, sizeof(zerobssid));
847 set80211(s, IEEE80211_IOC_BSSID, 0,
848 IEEE80211_ADDR_LEN, zerobssid);
849 }
850}
851
852static int
853getac(const char *ac)
854{
855 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
856 return WME_AC_BE;
857 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
858 return WME_AC_BK;
859 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
860 return WME_AC_VI;
861 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
862 return WME_AC_VO;
863 errx(1, "unknown wme access class %s", ac);
864}
865
866static
867DECL_CMD_FUNC2(set80211cwmin, ac, val)
868{
869 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
870}
871
872static
873DECL_CMD_FUNC2(set80211cwmax, ac, val)
874{
875 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
876}
877
878static
879DECL_CMD_FUNC2(set80211aifs, ac, val)
880{
881 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
882}
883
884static
885DECL_CMD_FUNC2(set80211txoplimit, ac, val)
886{
887 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
888}
889
890static
891DECL_CMD_FUNC(set80211acm, ac, d)
892{
893 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
894}
895static
896DECL_CMD_FUNC(set80211noacm, ac, d)
897{
898 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
899}
900
901static
902DECL_CMD_FUNC(set80211ackpolicy, ac, d)
903{
904 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
905}
906static
907DECL_CMD_FUNC(set80211noackpolicy, ac, d)
908{
909 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
910}
911
912static
913DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
914{
915 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
916 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
917}
918
919static
920DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
921{
922 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
923 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
924}
925
926static
927DECL_CMD_FUNC2(set80211bssaifs, ac, val)
928{
929 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
930 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
931}
932
933static
934DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
935{
936 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
937 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
938}
939
940static
941DECL_CMD_FUNC(set80211dtimperiod, val, d)
942{
943 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
944}
945
946static
947DECL_CMD_FUNC(set80211bintval, val, d)
948{
949 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
950}
951
952static void
953set80211macmac(int s, int op, const char *val)
954{
955 char *temp;
956 struct sockaddr_dl sdl;
957
958 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
959 if (temp == NULL)
960 errx(1, "malloc failed");
961 temp[0] = ':';
962 strcpy(temp + 1, val);
963 sdl.sdl_len = sizeof(sdl);
964 link_addr(temp, &sdl);
965 free(temp);
966 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
967 errx(1, "malformed link-level address");
968 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
969}
970
971static
972DECL_CMD_FUNC(set80211addmac, val, d)
973{
974 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
975}
976
977static
978DECL_CMD_FUNC(set80211delmac, val, d)
979{
980 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
981}
982
983static
984DECL_CMD_FUNC(set80211kickmac, val, d)
985{
986 char *temp;
987 struct sockaddr_dl sdl;
988 struct ieee80211req_mlme mlme;
989
990 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
991 if (temp == NULL)
992 errx(1, "malloc failed");
993 temp[0] = ':';
994 strcpy(temp + 1, val);
995 sdl.sdl_len = sizeof(sdl);
996 link_addr(temp, &sdl);
997 free(temp);
998 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
999 errx(1, "malformed link-level address");
1000 memset(&mlme, 0, sizeof(mlme));
1001 mlme.im_op = IEEE80211_MLME_DEAUTH;
1002 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
1003 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
1004 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
1005}
1006
1007static
1008DECL_CMD_FUNC(set80211maccmd, val, d)
1009{
1010 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
1011}
1012
1013static void
1014set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
1015{
1016 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
1017}
1018
1019static void
1020set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
1021{
1022 set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
1023}
1024
1025static
1026DECL_CMD_FUNC(set80211bgscanidle, val, d)
1027{
1028 set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
1029}
1030
1031static
1032DECL_CMD_FUNC(set80211bgscanintvl, val, d)
1033{
1034 set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
1035}
1036
1037static
1038DECL_CMD_FUNC(set80211scanvalid, val, d)
1039{
1040 set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
1041}
1042
1043static
1044DECL_CMD_FUNC(set80211roamrssi11a, val, d)
1045{
1046 set80211(s, IEEE80211_IOC_ROAM_RSSI_11A, atoi(val), 0, NULL);
1047}
1048
1049static
1050DECL_CMD_FUNC(set80211roamrssi11b, val, d)
1051{
1052 set80211(s, IEEE80211_IOC_ROAM_RSSI_11B, atoi(val), 0, NULL);
1053}
1054
1055static
1056DECL_CMD_FUNC(set80211roamrssi11g, val, d)
1057{
1058 set80211(s, IEEE80211_IOC_ROAM_RSSI_11G, atoi(val), 0, NULL);
1059}
1060
1061static
1062DECL_CMD_FUNC(set80211roamrate11a, val, d)
1063{
1064 set80211(s, IEEE80211_IOC_ROAM_RATE_11A, 2*atoi(val), 0, NULL);
1065}
1066
1067static
1068DECL_CMD_FUNC(set80211roamrate11b, val, d)
1069{
1070 set80211(s, IEEE80211_IOC_ROAM_RATE_11B, 2*atoi(val), 0, NULL);
1071}
1072
1073static
1074DECL_CMD_FUNC(set80211roamrate11g, val, d)
1075{
1076 set80211(s, IEEE80211_IOC_ROAM_RATE_11G, 2*atoi(val), 0, NULL);
1077}
1078
1079static
1080DECL_CMD_FUNC(set80211mcastrate, val, d)
1081{
1082 set80211(s, IEEE80211_IOC_MCAST_RATE, 2*atoi(val), 0, NULL);
1083}
1084
1085static
1086DECL_CMD_FUNC(set80211fragthreshold, val, d)
1087{
1088 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
1089 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
1090}
1091
1092static
1093DECL_CMD_FUNC(set80211bmissthreshold, val, d)
1094{
1095 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
1096 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
1097}
1098
1099static void
1100set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
1101{
1102 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
1103}
1104
1105static void
1106set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
1107{
1108 set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
1109}
1110
1111static void
1112set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp)
1113{
1114 set80211(s, IEEE80211_IOC_SHORTGI,
1115 d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
1116 0, NULL);
1117}
1118
1119static void
1120set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp)
1121{
1122 int ampdu;
1123
1124 if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
1125 errx(-1, "cannot get AMPDU setting");
1126 if (d < 0) {
1127 d = -d;
1128 ampdu &= ~d;
1129 } else
1130 ampdu |= d;
1131 set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
1132}
1133
1134static
1135DECL_CMD_FUNC(set80211ampdulimit, val, d)
1136{
1137 int v;
1138
1139 switch (atoi(val)) {
1140 case 8:
1141 case 8*1024:
1142 v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
1143 break;
1144 case 16:
1145 case 16*1024:
1146 v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
1147 break;
1148 case 32:
1149 case 32*1024:
1150 v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
1151 break;
1152 case 64:
1153 case 64*1024:
1154 v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
1155 break;
1156 default:
1157 errx(-1, "invalid A-MPDU limit %s", val);
1158 }
1159 set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
1160}
1161
1162static
1163DECL_CMD_FUNC(set80211ampdudensity, val, d)
1164{
1165 int v;
1166
1167 if (isanyarg(val))
1168 v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1169 else switch ((int)(atof(val)*4)) {
1170 case 0:
1171 v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1172 break;
1173 case 1:
1174 v = IEEE80211_HTCAP_MPDUDENSITY_025;
1175 break;
1176 case 2:
1177 v = IEEE80211_HTCAP_MPDUDENSITY_05;
1178 break;
1179 case 4:
1180 v = IEEE80211_HTCAP_MPDUDENSITY_1;
1181 break;
1182 case 8:
1183 v = IEEE80211_HTCAP_MPDUDENSITY_2;
1184 break;
1185 case 16:
1186 v = IEEE80211_HTCAP_MPDUDENSITY_4;
1187 break;
1188 case 32:
1189 v = IEEE80211_HTCAP_MPDUDENSITY_8;
1190 break;
1191 case 64:
1192 v = IEEE80211_HTCAP_MPDUDENSITY_16;
1193 break;
1194 default:
1195 errx(-1, "invalid A-MPDU density %s", val);
1196 }
1197 set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
1198}
1199
1200static void
1201set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
1202{
1203 int amsdu;
1204
1205 if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
1206 errx(-1, "cannot get AMSDU setting");
1207 if (d < 0) {
1208 d = -d;
1209 amsdu &= ~d;
1210 } else
1211 amsdu |= d;
1212 set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
1213}
1214
1215static
1216DECL_CMD_FUNC(set80211amsdulimit, val, d)
1217{
1218 set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
1219}
1220
1221static void
1222set80211puren(const char *val, int d, int s, const struct afswtch *rafp)
1223{
1224 set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
1225}
1226
1227static void
1228set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp)
1229{
1230 set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
1231}
1232
1233static void
1234set80211htconf(const char *val, int d, int s, const struct afswtch *rafp)
1235{
1236 set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
1237 htconf = d;
1238}
1239
1240static void
1241set80211inact(const char *val, int d, int s, const struct afswtch *rafp)
1242{
1243 set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
1244}
1245
1246static void
1247LINE_INIT(char c)
1248{
1249 spacer = c;
1250 if (c == '\t')
1251 col = 8;
1252 else
1253 col = 1;
1254}
1255
1256static void
1257LINE_BREAK(void)
1258{
1259 if (spacer != '\t') {
1260 printf("\n");
1261 spacer = '\t';
1262 }
1263 col = 8; /* 8-col tab */
1264}
1265
1266static void
1267LINE_CHECK(const char *fmt, ...)
1268{
1269 char buf[80];
1270 va_list ap;
1271 int n;
1272
1273 va_start(ap, fmt);
1274 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1275 va_end(ap);
1276 col += 1+n;
1277 if (col > MAXCOL) {
1278 LINE_BREAK();
1279 col += n;
1280 }
1281 buf[0] = spacer;
1282 printf("%s", buf);
1283 spacer = ' ';
1284}
1285
1020static int
1021getmaxrate(const uint8_t rates[15], uint8_t nrates)
1022{
1023 int i, maxrate = -1;
1024
1025 for (i = 0; i < nrates; i++) {
1026 int rate = rates[i] & IEEE80211_RATE_VAL;
1027 if (rate > maxrate)
1028 maxrate = rate;
1029 }
1030 return maxrate / 2;
1031}
1032
1033static const char *
1034getcaps(int capinfo)
1035{
1036 static char capstring[32];
1037 char *cp = capstring;
1038
1039 if (capinfo & IEEE80211_CAPINFO_ESS)
1040 *cp++ = 'E';
1041 if (capinfo & IEEE80211_CAPINFO_IBSS)
1042 *cp++ = 'I';
1043 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
1044 *cp++ = 'c';
1045 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
1046 *cp++ = 'C';
1047 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
1048 *cp++ = 'P';
1049 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
1050 *cp++ = 'S';
1051 if (capinfo & IEEE80211_CAPINFO_PBCC)
1052 *cp++ = 'B';
1053 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
1054 *cp++ = 'A';
1055 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
1056 *cp++ = 's';
1057 if (capinfo & IEEE80211_CAPINFO_RSN)
1058 *cp++ = 'R';
1059 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
1060 *cp++ = 'D';
1061 *cp = '\0';
1062 return capstring;
1063}
1064
1065static const char *
1066getflags(int flags)
1067{
1068/* XXX need these publicly defined or similar */
1069#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */
1070#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
1071#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */
1072#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */
1073#define IEEE80211_NODE_HT 0x0040 /* HT enabled */
1286static int
1287getmaxrate(const uint8_t rates[15], uint8_t nrates)
1288{
1289 int i, maxrate = -1;
1290
1291 for (i = 0; i < nrates; i++) {
1292 int rate = rates[i] & IEEE80211_RATE_VAL;
1293 if (rate > maxrate)
1294 maxrate = rate;
1295 }
1296 return maxrate / 2;
1297}
1298
1299static const char *
1300getcaps(int capinfo)
1301{
1302 static char capstring[32];
1303 char *cp = capstring;
1304
1305 if (capinfo & IEEE80211_CAPINFO_ESS)
1306 *cp++ = 'E';
1307 if (capinfo & IEEE80211_CAPINFO_IBSS)
1308 *cp++ = 'I';
1309 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
1310 *cp++ = 'c';
1311 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
1312 *cp++ = 'C';
1313 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
1314 *cp++ = 'P';
1315 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
1316 *cp++ = 'S';
1317 if (capinfo & IEEE80211_CAPINFO_PBCC)
1318 *cp++ = 'B';
1319 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
1320 *cp++ = 'A';
1321 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
1322 *cp++ = 's';
1323 if (capinfo & IEEE80211_CAPINFO_RSN)
1324 *cp++ = 'R';
1325 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
1326 *cp++ = 'D';
1327 *cp = '\0';
1328 return capstring;
1329}
1330
1331static const char *
1332getflags(int flags)
1333{
1334/* XXX need these publicly defined or similar */
1335#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */
1336#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
1337#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */
1338#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */
1339#define IEEE80211_NODE_HT 0x0040 /* HT enabled */
1340#define IEEE80211_NODE_HTCOMPAT 0x0080 /* HT setup w/ vendor OUI's */
1341#define IEEE80211_NODE_WPS 0x0100 /* WPS association */
1342#define IEEE80211_NODE_TSN 0x0200 /* TSN association */
1343
1074 static char flagstring[32];
1075 char *cp = flagstring;
1076
1077 if (flags & IEEE80211_NODE_AUTH)
1078 *cp++ = 'A';
1079 if (flags & IEEE80211_NODE_QOS)
1080 *cp++ = 'Q';
1081 if (flags & IEEE80211_NODE_ERP)
1082 *cp++ = 'E';
1083 if (flags & IEEE80211_NODE_PWR_MGT)
1084 *cp++ = 'P';
1344 static char flagstring[32];
1345 char *cp = flagstring;
1346
1347 if (flags & IEEE80211_NODE_AUTH)
1348 *cp++ = 'A';
1349 if (flags & IEEE80211_NODE_QOS)
1350 *cp++ = 'Q';
1351 if (flags & IEEE80211_NODE_ERP)
1352 *cp++ = 'E';
1353 if (flags & IEEE80211_NODE_PWR_MGT)
1354 *cp++ = 'P';
1085 if (flags & IEEE80211_NODE_HT)
1355 if (flags & IEEE80211_NODE_HT) {
1086 *cp++ = 'H';
1356 *cp++ = 'H';
1357 if (flags & IEEE80211_NODE_HTCOMPAT)
1358 *cp++ = '+';
1359 }
1360 if (flags & IEEE80211_NODE_WPS)
1361 *cp++ = 'W';
1362 if (flags & IEEE80211_NODE_TSN)
1363 *cp++ = 'T';
1087 *cp = '\0';
1088 return flagstring;
1364 *cp = '\0';
1365 return flagstring;
1366#undef IEEE80211_NODE_TSN
1367#undef IEEE80211_NODE_WPS
1368#undef IEEE80211_NODE_HTCOMPAT
1089#undef IEEE80211_NODE_HT
1090#undef IEEE80211_NODE_AUTH
1091#undef IEEE80211_NODE_QOS
1092#undef IEEE80211_NODE_ERP
1093#undef IEEE80211_NODE_PWR_MGT
1094}
1095
1096static void
1097printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
1098{
1099 printf("%s", tag);
1100 if (verbose) {
1101 maxlen -= strlen(tag)+2;
1102 if (2*ielen > maxlen)
1103 maxlen--;
1104 printf("<");
1105 for (; ielen > 0; ie++, ielen--) {
1106 if (maxlen-- <= 0)
1107 break;
1108 printf("%02x", *ie);
1109 }
1110 if (ielen != 0)
1111 printf("-");
1112 printf(">");
1113 }
1114}
1115
1116#define LE_READ_2(p) \
1117 ((u_int16_t) \
1118 ((((const u_int8_t *)(p))[0] ) | \
1119 (((const u_int8_t *)(p))[1] << 8)))
1120#define LE_READ_4(p) \
1121 ((u_int32_t) \
1122 ((((const u_int8_t *)(p))[0] ) | \
1123 (((const u_int8_t *)(p))[1] << 8) | \
1124 (((const u_int8_t *)(p))[2] << 16) | \
1125 (((const u_int8_t *)(p))[3] << 24)))
1126
1127/*
1128 * NB: The decoding routines assume a properly formatted ie
1129 * which should be safe as the kernel only retains them
1130 * if they parse ok.
1131 */
1132
1133static void
1369#undef IEEE80211_NODE_HT
1370#undef IEEE80211_NODE_AUTH
1371#undef IEEE80211_NODE_QOS
1372#undef IEEE80211_NODE_ERP
1373#undef IEEE80211_NODE_PWR_MGT
1374}
1375
1376static void
1377printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
1378{
1379 printf("%s", tag);
1380 if (verbose) {
1381 maxlen -= strlen(tag)+2;
1382 if (2*ielen > maxlen)
1383 maxlen--;
1384 printf("<");
1385 for (; ielen > 0; ie++, ielen--) {
1386 if (maxlen-- <= 0)
1387 break;
1388 printf("%02x", *ie);
1389 }
1390 if (ielen != 0)
1391 printf("-");
1392 printf(">");
1393 }
1394}
1395
1396#define LE_READ_2(p) \
1397 ((u_int16_t) \
1398 ((((const u_int8_t *)(p))[0] ) | \
1399 (((const u_int8_t *)(p))[1] << 8)))
1400#define LE_READ_4(p) \
1401 ((u_int32_t) \
1402 ((((const u_int8_t *)(p))[0] ) | \
1403 (((const u_int8_t *)(p))[1] << 8) | \
1404 (((const u_int8_t *)(p))[2] << 16) | \
1405 (((const u_int8_t *)(p))[3] << 24)))
1406
1407/*
1408 * NB: The decoding routines assume a properly formatted ie
1409 * which should be safe as the kernel only retains them
1410 * if they parse ok.
1411 */
1412
1413static void
1134printwmeie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1414printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1135{
1136#define MS(_v, _f) (((_v) & _f) >> _f##_S)
1137 static const char *acnames[] = { "BE", "BK", "VO", "VI" };
1415{
1416#define MS(_v, _f) (((_v) & _f) >> _f##_S)
1417 static const char *acnames[] = { "BE", "BK", "VO", "VI" };
1418 const struct ieee80211_wme_param *wme =
1419 (const struct ieee80211_wme_param *) ie;
1138 int i;
1139
1140 printf("%s", tag);
1420 int i;
1421
1422 printf("%s", tag);
1141 if (verbose) {
1142 printf("<qosinfo 0x%x", ie[
1143 __offsetof(struct ieee80211_wme_param, param_qosInfo)]);
1144 ie += __offsetof(struct ieee80211_wme_param, params_acParams);
1145 for (i = 0; i < WME_NUM_AC; i++) {
1146 printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
1147 , acnames[i]
1148 , MS(ie[0], WME_PARAM_ACM) ? "acm " : ""
1149 , MS(ie[0], WME_PARAM_AIFSN)
1150 , MS(ie[1], WME_PARAM_LOGCWMIN)
1151 , MS(ie[1], WME_PARAM_LOGCWMAX)
1152 , LE_READ_2(ie+2)
1153 );
1154 ie += 4;
1155 }
1156 printf(">");
1423 if (!verbose)
1424 return;
1425 printf("<qosinfo 0x%x", wme->param_qosInfo);
1426 ie += offsetof(struct ieee80211_wme_param, params_acParams);
1427 for (i = 0; i < WME_NUM_AC; i++) {
1428 const struct ieee80211_wme_acparams *ac =
1429 &wme->params_acParams[i];
1430
1431 printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
1432 , acnames[i]
1433 , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
1434 , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
1435 , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
1436 , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
1437 , LE_READ_2(&ac->acp_txop)
1438 );
1157 }
1439 }
1440 printf(">");
1158#undef MS
1159}
1160
1161static void
1441#undef MS
1442}
1443
1444static void
1445printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1446{
1447 printf("%s", tag);
1448 if (verbose) {
1449 const struct ieee80211_wme_info *wme =
1450 (const struct ieee80211_wme_info *) ie;
1451 printf("<version 0x%x info 0x%x>",
1452 wme->wme_version, wme->wme_info);
1453 }
1454}
1455
1456static void
1457printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1458{
1459 printf("%s", tag);
1460 if (verbose) {
1461 const struct ieee80211_ie_htcap *htcap =
1462 (const struct ieee80211_ie_htcap *) ie;
1463 const char *sep;
1464 int i, j;
1465
1466 printf("<cap 0x%x param 0x%x",
1467 LE_READ_2(&htcap->hc_cap), htcap->hc_param);
1468 printf(" mcsset[");
1469 sep = "";
1470 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
1471 if (isset(htcap->hc_mcsset, i)) {
1472 for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
1473 if (isclr(htcap->hc_mcsset, j))
1474 break;
1475 j--;
1476 if (i == j)
1477 printf("%s%u", sep, i);
1478 else
1479 printf("%s%u-%u", sep, i, j);
1480 i += j-i;
1481 sep = ",";
1482 }
1483 printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
1484 LE_READ_2(&htcap->hc_extcap),
1485 LE_READ_4(&htcap->hc_txbf),
1486 htcap->hc_antenna);
1487 }
1488}
1489
1490static void
1491printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1492{
1493 printf("%s", tag);
1494 if (verbose) {
1495 const struct ieee80211_ie_htinfo *htinfo =
1496 (const struct ieee80211_ie_htinfo *) ie;
1497 const char *sep;
1498 int i, j;
1499
1500 printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
1501 htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
1502 LE_READ_2(&htinfo->hi_byte45));
1503 printf(" basicmcs[");
1504 sep = "";
1505 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
1506 if (isset(htinfo->hi_basicmcsset, i)) {
1507 for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
1508 if (isclr(htinfo->hi_basicmcsset, j))
1509 break;
1510 j--;
1511 if (i == j)
1512 printf("%s%u", sep, i);
1513 else
1514 printf("%s%u-%u", sep, i, j);
1515 i += j-i;
1516 sep = ",";
1517 }
1518 printf("]>");
1519 }
1520}
1521
1522static void
1162printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1163{
1164
1165 printf("%s", tag);
1166 if (verbose) {
1167 const struct ieee80211_ath_ie *ath =
1168 (const struct ieee80211_ath_ie *)ie;
1169
1170 printf("<");
1171 if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
1172 printf("DTURBO,");
1173 if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
1174 printf("COMP,");
1175 if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
1176 printf("FF,");
1177 if (ath->ath_capability & ATHEROS_CAP_XR)
1178 printf("XR,");
1179 if (ath->ath_capability & ATHEROS_CAP_AR)
1180 printf("AR,");
1181 if (ath->ath_capability & ATHEROS_CAP_BURST)
1182 printf("BURST,");
1183 if (ath->ath_capability & ATHEROS_CAP_WME)
1184 printf("WME,");
1185 if (ath->ath_capability & ATHEROS_CAP_BOOST)
1186 printf("BOOST,");
1187 printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
1188 }
1189}
1190
1191static const char *
1192wpa_cipher(const u_int8_t *sel)
1193{
1194#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
1195 u_int32_t w = LE_READ_4(sel);
1196
1197 switch (w) {
1198 case WPA_SEL(WPA_CSE_NULL):
1199 return "NONE";
1200 case WPA_SEL(WPA_CSE_WEP40):
1201 return "WEP40";
1202 case WPA_SEL(WPA_CSE_WEP104):
1203 return "WEP104";
1204 case WPA_SEL(WPA_CSE_TKIP):
1205 return "TKIP";
1206 case WPA_SEL(WPA_CSE_CCMP):
1207 return "AES-CCMP";
1208 }
1209 return "?"; /* NB: so 1<< is discarded */
1210#undef WPA_SEL
1211}
1212
1213static const char *
1214wpa_keymgmt(const u_int8_t *sel)
1215{
1216#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
1217 u_int32_t w = LE_READ_4(sel);
1218
1219 switch (w) {
1220 case WPA_SEL(WPA_ASE_8021X_UNSPEC):
1221 return "8021X-UNSPEC";
1222 case WPA_SEL(WPA_ASE_8021X_PSK):
1223 return "8021X-PSK";
1224 case WPA_SEL(WPA_ASE_NONE):
1225 return "NONE";
1226 }
1227 return "?";
1228#undef WPA_SEL
1229}
1230
1231static void
1232printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1233{
1234 u_int8_t len = ie[1];
1235
1236 printf("%s", tag);
1237 if (verbose) {
1238 const char *sep;
1239 int n;
1240
1241 ie += 6, len -= 4; /* NB: len is payload only */
1242
1243 printf("<v%u", LE_READ_2(ie));
1244 ie += 2, len -= 2;
1245
1246 printf(" mc:%s", wpa_cipher(ie));
1247 ie += 4, len -= 4;
1248
1249 /* unicast ciphers */
1250 n = LE_READ_2(ie);
1251 ie += 2, len -= 2;
1252 sep = " uc:";
1253 for (; n > 0; n--) {
1254 printf("%s%s", sep, wpa_cipher(ie));
1255 ie += 4, len -= 4;
1256 sep = "+";
1257 }
1258
1259 /* key management algorithms */
1260 n = LE_READ_2(ie);
1261 ie += 2, len -= 2;
1262 sep = " km:";
1263 for (; n > 0; n--) {
1264 printf("%s%s", sep, wpa_keymgmt(ie));
1265 ie += 4, len -= 4;
1266 sep = "+";
1267 }
1268
1269 if (len > 2) /* optional capabilities */
1270 printf(", caps 0x%x", LE_READ_2(ie));
1271 printf(">");
1272 }
1273}
1274
1275static const char *
1276rsn_cipher(const u_int8_t *sel)
1277{
1278#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
1279 u_int32_t w = LE_READ_4(sel);
1280
1281 switch (w) {
1282 case RSN_SEL(RSN_CSE_NULL):
1283 return "NONE";
1284 case RSN_SEL(RSN_CSE_WEP40):
1285 return "WEP40";
1286 case RSN_SEL(RSN_CSE_WEP104):
1287 return "WEP104";
1288 case RSN_SEL(RSN_CSE_TKIP):
1289 return "TKIP";
1290 case RSN_SEL(RSN_CSE_CCMP):
1291 return "AES-CCMP";
1292 case RSN_SEL(RSN_CSE_WRAP):
1293 return "AES-OCB";
1294 }
1295 return "?";
1296#undef WPA_SEL
1297}
1298
1299static const char *
1300rsn_keymgmt(const u_int8_t *sel)
1301{
1302#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
1303 u_int32_t w = LE_READ_4(sel);
1304
1305 switch (w) {
1306 case RSN_SEL(RSN_ASE_8021X_UNSPEC):
1307 return "8021X-UNSPEC";
1308 case RSN_SEL(RSN_ASE_8021X_PSK):
1309 return "8021X-PSK";
1310 case RSN_SEL(RSN_ASE_NONE):
1311 return "NONE";
1312 }
1313 return "?";
1314#undef RSN_SEL
1315}
1316
1317static void
1318printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1319{
1523printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1524{
1525
1526 printf("%s", tag);
1527 if (verbose) {
1528 const struct ieee80211_ath_ie *ath =
1529 (const struct ieee80211_ath_ie *)ie;
1530
1531 printf("<");
1532 if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
1533 printf("DTURBO,");
1534 if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
1535 printf("COMP,");
1536 if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
1537 printf("FF,");
1538 if (ath->ath_capability & ATHEROS_CAP_XR)
1539 printf("XR,");
1540 if (ath->ath_capability & ATHEROS_CAP_AR)
1541 printf("AR,");
1542 if (ath->ath_capability & ATHEROS_CAP_BURST)
1543 printf("BURST,");
1544 if (ath->ath_capability & ATHEROS_CAP_WME)
1545 printf("WME,");
1546 if (ath->ath_capability & ATHEROS_CAP_BOOST)
1547 printf("BOOST,");
1548 printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
1549 }
1550}
1551
1552static const char *
1553wpa_cipher(const u_int8_t *sel)
1554{
1555#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
1556 u_int32_t w = LE_READ_4(sel);
1557
1558 switch (w) {
1559 case WPA_SEL(WPA_CSE_NULL):
1560 return "NONE";
1561 case WPA_SEL(WPA_CSE_WEP40):
1562 return "WEP40";
1563 case WPA_SEL(WPA_CSE_WEP104):
1564 return "WEP104";
1565 case WPA_SEL(WPA_CSE_TKIP):
1566 return "TKIP";
1567 case WPA_SEL(WPA_CSE_CCMP):
1568 return "AES-CCMP";
1569 }
1570 return "?"; /* NB: so 1<< is discarded */
1571#undef WPA_SEL
1572}
1573
1574static const char *
1575wpa_keymgmt(const u_int8_t *sel)
1576{
1577#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
1578 u_int32_t w = LE_READ_4(sel);
1579
1580 switch (w) {
1581 case WPA_SEL(WPA_ASE_8021X_UNSPEC):
1582 return "8021X-UNSPEC";
1583 case WPA_SEL(WPA_ASE_8021X_PSK):
1584 return "8021X-PSK";
1585 case WPA_SEL(WPA_ASE_NONE):
1586 return "NONE";
1587 }
1588 return "?";
1589#undef WPA_SEL
1590}
1591
1592static void
1593printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1594{
1595 u_int8_t len = ie[1];
1596
1597 printf("%s", tag);
1598 if (verbose) {
1599 const char *sep;
1600 int n;
1601
1602 ie += 6, len -= 4; /* NB: len is payload only */
1603
1604 printf("<v%u", LE_READ_2(ie));
1605 ie += 2, len -= 2;
1606
1607 printf(" mc:%s", wpa_cipher(ie));
1608 ie += 4, len -= 4;
1609
1610 /* unicast ciphers */
1611 n = LE_READ_2(ie);
1612 ie += 2, len -= 2;
1613 sep = " uc:";
1614 for (; n > 0; n--) {
1615 printf("%s%s", sep, wpa_cipher(ie));
1616 ie += 4, len -= 4;
1617 sep = "+";
1618 }
1619
1620 /* key management algorithms */
1621 n = LE_READ_2(ie);
1622 ie += 2, len -= 2;
1623 sep = " km:";
1624 for (; n > 0; n--) {
1625 printf("%s%s", sep, wpa_keymgmt(ie));
1626 ie += 4, len -= 4;
1627 sep = "+";
1628 }
1629
1630 if (len > 2) /* optional capabilities */
1631 printf(", caps 0x%x", LE_READ_2(ie));
1632 printf(">");
1633 }
1634}
1635
1636static const char *
1637rsn_cipher(const u_int8_t *sel)
1638{
1639#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
1640 u_int32_t w = LE_READ_4(sel);
1641
1642 switch (w) {
1643 case RSN_SEL(RSN_CSE_NULL):
1644 return "NONE";
1645 case RSN_SEL(RSN_CSE_WEP40):
1646 return "WEP40";
1647 case RSN_SEL(RSN_CSE_WEP104):
1648 return "WEP104";
1649 case RSN_SEL(RSN_CSE_TKIP):
1650 return "TKIP";
1651 case RSN_SEL(RSN_CSE_CCMP):
1652 return "AES-CCMP";
1653 case RSN_SEL(RSN_CSE_WRAP):
1654 return "AES-OCB";
1655 }
1656 return "?";
1657#undef WPA_SEL
1658}
1659
1660static const char *
1661rsn_keymgmt(const u_int8_t *sel)
1662{
1663#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
1664 u_int32_t w = LE_READ_4(sel);
1665
1666 switch (w) {
1667 case RSN_SEL(RSN_ASE_8021X_UNSPEC):
1668 return "8021X-UNSPEC";
1669 case RSN_SEL(RSN_ASE_8021X_PSK):
1670 return "8021X-PSK";
1671 case RSN_SEL(RSN_ASE_NONE):
1672 return "NONE";
1673 }
1674 return "?";
1675#undef RSN_SEL
1676}
1677
1678static void
1679printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1680{
1320 u_int8_t len = ie[1];
1321
1322 printf("%s", tag);
1323 if (verbose) {
1324 const char *sep;
1325 int n;
1326
1681 printf("%s", tag);
1682 if (verbose) {
1683 const char *sep;
1684 int n;
1685
1327 ie += 6, len -= 4; /* NB: len is payload only */
1686 ie += 2, ielen -= 2;
1328
1329 printf("<v%u", LE_READ_2(ie));
1687
1688 printf("<v%u", LE_READ_2(ie));
1330 ie += 2, len -= 2;
1689 ie += 2, ielen -= 2;
1331
1332 printf(" mc:%s", rsn_cipher(ie));
1690
1691 printf(" mc:%s", rsn_cipher(ie));
1333 ie += 4, len -= 4;
1692 ie += 4, ielen -= 4;
1334
1335 /* unicast ciphers */
1336 n = LE_READ_2(ie);
1693
1694 /* unicast ciphers */
1695 n = LE_READ_2(ie);
1337 ie += 2, len -= 2;
1696 ie += 2, ielen -= 2;
1338 sep = " uc:";
1339 for (; n > 0; n--) {
1340 printf("%s%s", sep, rsn_cipher(ie));
1697 sep = " uc:";
1698 for (; n > 0; n--) {
1699 printf("%s%s", sep, rsn_cipher(ie));
1341 ie += 4, len -= 4;
1700 ie += 4, ielen -= 4;
1342 sep = "+";
1343 }
1344
1345 /* key management algorithms */
1346 n = LE_READ_2(ie);
1701 sep = "+";
1702 }
1703
1704 /* key management algorithms */
1705 n = LE_READ_2(ie);
1347 ie += 2, len -= 2;
1706 ie += 2, ielen -= 2;
1348 sep = " km:";
1349 for (; n > 0; n--) {
1350 printf("%s%s", sep, rsn_keymgmt(ie));
1707 sep = " km:";
1708 for (; n > 0; n--) {
1709 printf("%s%s", sep, rsn_keymgmt(ie));
1351 ie += 4, len -= 4;
1710 ie += 4, ielen -= 4;
1352 sep = "+";
1353 }
1354
1711 sep = "+";
1712 }
1713
1355 if (len > 2) /* optional capabilities */
1714 if (ielen > 2) /* optional capabilities */
1356 printf(", caps 0x%x", LE_READ_2(ie));
1357 /* XXXPMKID */
1358 printf(">");
1359 }
1360}
1361
1362/*
1363 * Copy the ssid string contents into buf, truncating to fit. If the
1364 * ssid is entirely printable then just copy intact. Otherwise convert
1365 * to hexadecimal. If the result is truncated then replace the last
1366 * three characters with "...".
1367 */
1368static int
1369copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
1370{
1371 const u_int8_t *p;
1372 size_t maxlen;
1373 int i;
1374
1375 if (essid_len > bufsize)
1376 maxlen = bufsize;
1377 else
1378 maxlen = essid_len;
1379 /* determine printable or not */
1380 for (i = 0, p = essid; i < maxlen; i++, p++) {
1381 if (*p < ' ' || *p > 0x7e)
1382 break;
1383 }
1384 if (i != maxlen) { /* not printable, print as hex */
1385 if (bufsize < 3)
1386 return 0;
1387 strlcpy(buf, "0x", bufsize);
1388 bufsize -= 2;
1389 p = essid;
1390 for (i = 0; i < maxlen && bufsize >= 2; i++) {
1391 sprintf(&buf[2+2*i], "%02x", p[i]);
1392 bufsize -= 2;
1393 }
1394 if (i != essid_len)
1395 memcpy(&buf[2+2*i-3], "...", 3);
1396 } else { /* printable, truncate as needed */
1397 memcpy(buf, essid, maxlen);
1398 if (maxlen != essid_len)
1399 memcpy(&buf[maxlen-3], "...", 3);
1400 }
1401 return maxlen;
1402}
1403
1715 printf(", caps 0x%x", LE_READ_2(ie));
1716 /* XXXPMKID */
1717 printf(">");
1718 }
1719}
1720
1721/*
1722 * Copy the ssid string contents into buf, truncating to fit. If the
1723 * ssid is entirely printable then just copy intact. Otherwise convert
1724 * to hexadecimal. If the result is truncated then replace the last
1725 * three characters with "...".
1726 */
1727static int
1728copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
1729{
1730 const u_int8_t *p;
1731 size_t maxlen;
1732 int i;
1733
1734 if (essid_len > bufsize)
1735 maxlen = bufsize;
1736 else
1737 maxlen = essid_len;
1738 /* determine printable or not */
1739 for (i = 0, p = essid; i < maxlen; i++, p++) {
1740 if (*p < ' ' || *p > 0x7e)
1741 break;
1742 }
1743 if (i != maxlen) { /* not printable, print as hex */
1744 if (bufsize < 3)
1745 return 0;
1746 strlcpy(buf, "0x", bufsize);
1747 bufsize -= 2;
1748 p = essid;
1749 for (i = 0; i < maxlen && bufsize >= 2; i++) {
1750 sprintf(&buf[2+2*i], "%02x", p[i]);
1751 bufsize -= 2;
1752 }
1753 if (i != essid_len)
1754 memcpy(&buf[2+2*i-3], "...", 3);
1755 } else { /* printable, truncate as needed */
1756 memcpy(buf, essid, maxlen);
1757 if (maxlen != essid_len)
1758 memcpy(&buf[maxlen-3], "...", 3);
1759 }
1760 return maxlen;
1761}
1762
1763static void
1764printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1765{
1766 char ssid[2*IEEE80211_NWID_LEN+1];
1767
1768 printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
1769}
1770
1771static void
1772printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1773{
1774 const char *sep;
1775 int i;
1776
1777 printf("%s", tag);
1778 sep = "<";
1779 for (i = 2; i < ielen; i++) {
1780 printf("%s%s%d", sep,
1781 ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
1782 ie[i] & IEEE80211_RATE_VAL);
1783 sep = ",";
1784 }
1785 printf(">");
1786}
1787
1788static void
1789printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
1790{
1791 const struct ieee80211_country_ie *cie =
1792 (const struct ieee80211_country_ie *) ie;
1793 int i, nbands, schan, nchan;
1794
1795 printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
1796 nbands = (cie->len - 3) / sizeof(cie->band[0]);
1797 for (i = 0; i < nbands; i++) {
1798 schan = cie->band[i].schan;
1799 nchan = cie->band[i].nchan;
1800 if (nchan != 1)
1801 printf(" %u-%u,%u", schan, schan + nchan-1,
1802 cie->band[i].maxtxpwr);
1803 else
1804 printf(" %u,%u", schan, cie->band[i].maxtxpwr);
1805 }
1806 printf(">");
1807}
1808
1404/* unaligned little endian access */
1405#define LE_READ_4(p) \
1406 ((u_int32_t) \
1407 ((((const u_int8_t *)(p))[0] ) | \
1408 (((const u_int8_t *)(p))[1] << 8) | \
1409 (((const u_int8_t *)(p))[2] << 16) | \
1410 (((const u_int8_t *)(p))[3] << 24)))
1411
1412static int __inline
1413iswpaoui(const u_int8_t *frm)
1414{
1415 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1416}
1417
1418static int __inline
1809/* unaligned little endian access */
1810#define LE_READ_4(p) \
1811 ((u_int32_t) \
1812 ((((const u_int8_t *)(p))[0] ) | \
1813 (((const u_int8_t *)(p))[1] << 8) | \
1814 (((const u_int8_t *)(p))[2] << 16) | \
1815 (((const u_int8_t *)(p))[3] << 24)))
1816
1817static int __inline
1818iswpaoui(const u_int8_t *frm)
1819{
1820 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1821}
1822
1823static int __inline
1419iswmeoui(const u_int8_t *frm)
1824iswmeinfo(const u_int8_t *frm)
1420{
1825{
1421 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
1826 return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
1827 frm[6] == WME_INFO_OUI_SUBTYPE;
1422}
1423
1424static int __inline
1828}
1829
1830static int __inline
1831iswmeparam(const u_int8_t *frm)
1832{
1833 return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
1834 frm[6] == WME_PARAM_OUI_SUBTYPE;
1835}
1836
1837static int __inline
1425isatherosoui(const u_int8_t *frm)
1426{
1427 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
1428}
1429
1838isatherosoui(const u_int8_t *frm)
1839{
1840 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
1841}
1842
1843static const char *
1844iename(int elemid)
1845{
1846 switch (elemid) {
1847 case IEEE80211_ELEMID_FHPARMS: return " FHPARMS";
1848 case IEEE80211_ELEMID_CFPARMS: return " CFPARMS";
1849 case IEEE80211_ELEMID_TIM: return " TIM";
1850 case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
1851 case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
1852 case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR";
1853 case IEEE80211_ELEMID_PWRCAP: return " PWRCAP";
1854 case IEEE80211_ELEMID_TPCREQ: return " TPCREQ";
1855 case IEEE80211_ELEMID_TPCREP: return " TPCREP";
1856 case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN";
1857 case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA";
1858 case IEEE80211_ELEMID_MEASREQ: return " MEASREQ";
1859 case IEEE80211_ELEMID_MEASREP: return " MEASREP";
1860 case IEEE80211_ELEMID_QUIET: return " QUIET";
1861 case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS";
1862 case IEEE80211_ELEMID_TPC: return " TPC";
1863 case IEEE80211_ELEMID_CCKM: return " CCKM";
1864 }
1865 return " ???";
1866}
1867
1430static void
1431printies(const u_int8_t *vp, int ielen, int maxcols)
1432{
1433 while (ielen > 0) {
1434 switch (vp[0]) {
1868static void
1869printies(const u_int8_t *vp, int ielen, int maxcols)
1870{
1871 while (ielen > 0) {
1872 switch (vp[0]) {
1873 case IEEE80211_ELEMID_SSID:
1874 if (verbose)
1875 printssid(" SSID", vp, 2+vp[1], maxcols);
1876 break;
1877 case IEEE80211_ELEMID_RATES:
1878 case IEEE80211_ELEMID_XRATES:
1879 if (verbose)
1880 printrates(vp[0] == IEEE80211_ELEMID_RATES ?
1881 " RATES" : " XRATES", vp, 2+vp[1], maxcols);
1882 break;
1883 case IEEE80211_ELEMID_DSPARMS:
1884 if (verbose)
1885 printf(" DSPARMS<%u>", vp[2]);
1886 break;
1887 case IEEE80211_ELEMID_COUNTRY:
1888 if (verbose)
1889 printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
1890 break;
1891 case IEEE80211_ELEMID_ERP:
1892 if (verbose)
1893 printf(" ERP<0x%x>", vp[2]);
1894 break;
1435 case IEEE80211_ELEMID_VENDOR:
1436 if (iswpaoui(vp))
1437 printwpaie(" WPA", vp, 2+vp[1], maxcols);
1895 case IEEE80211_ELEMID_VENDOR:
1896 if (iswpaoui(vp))
1897 printwpaie(" WPA", vp, 2+vp[1], maxcols);
1438 else if (iswmeoui(vp))
1439 printwmeie(" WME", vp, 2+vp[1], maxcols);
1898 else if (iswmeinfo(vp))
1899 printwmeinfo(" WME", vp, 2+vp[1], maxcols);
1900 else if (iswmeparam(vp))
1901 printwmeparam(" WME", vp, 2+vp[1], maxcols);
1440 else if (isatherosoui(vp))
1441 printathie(" ATH", vp, 2+vp[1], maxcols);
1902 else if (isatherosoui(vp))
1903 printathie(" ATH", vp, 2+vp[1], maxcols);
1442 else
1904 else if (verbose)
1443 printie(" VEN", vp, 2+vp[1], maxcols);
1444 break;
1445 case IEEE80211_ELEMID_RSN:
1446 printrsnie(" RSN", vp, 2+vp[1], maxcols);
1447 break;
1905 printie(" VEN", vp, 2+vp[1], maxcols);
1906 break;
1907 case IEEE80211_ELEMID_RSN:
1908 printrsnie(" RSN", vp, 2+vp[1], maxcols);
1909 break;
1910 case IEEE80211_ELEMID_HTCAP:
1911 printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
1912 break;
1913 case IEEE80211_ELEMID_HTINFO:
1914 if (verbose)
1915 printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
1916 break;
1448 default:
1917 default:
1449 printie(" ???", vp, 2+vp[1], maxcols);
1918 if (verbose)
1919 printie(iename(vp[0]), vp, 2+vp[1], maxcols);
1450 break;
1451 }
1452 ielen -= 2+vp[1];
1453 vp += 2+vp[1];
1454 }
1455}
1456
1457static void
1458list_scan(int s)
1459{
1460 uint8_t buf[24*1024];
1920 break;
1921 }
1922 ielen -= 2+vp[1];
1923 vp += 2+vp[1];
1924 }
1925}
1926
1927static void
1928list_scan(int s)
1929{
1930 uint8_t buf[24*1024];
1461 struct ieee80211req ireq;
1462 char ssid[IEEE80211_NWID_LEN+1];
1931 char ssid[IEEE80211_NWID_LEN+1];
1463 uint8_t *cp;
1932 const uint8_t *cp;
1464 int len, ssidmax;
1465
1933 int len, ssidmax;
1934
1466 (void) memset(&ireq, 0, sizeof(ireq));
1467 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1468 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
1469 ireq.i_data = buf;
1470 ireq.i_len = sizeof(buf);
1471 if (ioctl(s, SIOCG80211, &ireq) < 0)
1935 if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
1472 errx(1, "unable to get scan results");
1936 errx(1, "unable to get scan results");
1473 len = ireq.i_len;
1474 if (len < sizeof(struct ieee80211req_scan_result))
1475 return;
1476
1477 getchaninfo(s);
1478
1479 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
1480 printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
1481 , ssidmax, ssidmax, "SSID"
1482 , "BSSID"
1483 , "CHAN"
1484 , "RATE"
1485 , " S:N"
1486 , "INT"
1487 , "CAPS"
1488 );
1489 cp = buf;
1490 do {
1491 const struct ieee80211req_scan_result *sr;
1492 const uint8_t *vp;
1493
1494 sr = (const struct ieee80211req_scan_result *) cp;
1937 if (len < sizeof(struct ieee80211req_scan_result))
1938 return;
1939
1940 getchaninfo(s);
1941
1942 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
1943 printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
1944 , ssidmax, ssidmax, "SSID"
1945 , "BSSID"
1946 , "CHAN"
1947 , "RATE"
1948 , " S:N"
1949 , "INT"
1950 , "CAPS"
1951 );
1952 cp = buf;
1953 do {
1954 const struct ieee80211req_scan_result *sr;
1955 const uint8_t *vp;
1956
1957 sr = (const struct ieee80211req_scan_result *) cp;
1495 vp = ((const u_int8_t *)sr) + sr->isr_ie_off;
1958 vp = cp + sr->isr_ie_off;
1496 printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
1497 , ssidmax
1498 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
1499 , ssid
1500 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
1501 , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
1502 , getmaxrate(sr->isr_rates, sr->isr_nrates)
1503 , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
1504 , sr->isr_intval
1505 , getcaps(sr->isr_capinfo)
1506 );
1507 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
1508 printf("\n");
1509 cp += sr->isr_len, len -= sr->isr_len;
1510 } while (len >= sizeof(struct ieee80211req_scan_result));
1511}
1512
1513#include <net80211/ieee80211_freebsd.h>
1514
1515static void
1516scan_and_wait(int s)
1517{
1518 struct ieee80211req ireq;
1519 int sroute;
1520
1521 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
1522 if (sroute < 0) {
1523 perror("socket(PF_ROUTE,SOCK_RAW)");
1524 return;
1525 }
1526 (void) memset(&ireq, 0, sizeof(ireq));
1527 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1528 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
1529 /* NB: only root can trigger a scan so ignore errors */
1530 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
1531 char buf[2048];
1532 struct if_announcemsghdr *ifan;
1533 struct rt_msghdr *rtm;
1534
1535 do {
1536 if (read(sroute, buf, sizeof(buf)) < 0) {
1537 perror("read(PF_ROUTE)");
1538 break;
1539 }
1540 rtm = (struct rt_msghdr *) buf;
1541 if (rtm->rtm_version != RTM_VERSION)
1542 break;
1543 ifan = (struct if_announcemsghdr *) rtm;
1544 } while (rtm->rtm_type != RTM_IEEE80211 ||
1545 ifan->ifan_what != RTM_IEEE80211_SCAN);
1546 }
1547 close(sroute);
1548}
1549
1550static
1551DECL_CMD_FUNC(set80211scan, val, d)
1552{
1553 scan_and_wait(s);
1554 list_scan(s);
1555}
1556
1557static enum ieee80211_opmode get80211opmode(int s);
1558
1959 printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
1960 , ssidmax
1961 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
1962 , ssid
1963 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
1964 , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
1965 , getmaxrate(sr->isr_rates, sr->isr_nrates)
1966 , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
1967 , sr->isr_intval
1968 , getcaps(sr->isr_capinfo)
1969 );
1970 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
1971 printf("\n");
1972 cp += sr->isr_len, len -= sr->isr_len;
1973 } while (len >= sizeof(struct ieee80211req_scan_result));
1974}
1975
1976#include <net80211/ieee80211_freebsd.h>
1977
1978static void
1979scan_and_wait(int s)
1980{
1981 struct ieee80211req ireq;
1982 int sroute;
1983
1984 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
1985 if (sroute < 0) {
1986 perror("socket(PF_ROUTE,SOCK_RAW)");
1987 return;
1988 }
1989 (void) memset(&ireq, 0, sizeof(ireq));
1990 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1991 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
1992 /* NB: only root can trigger a scan so ignore errors */
1993 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
1994 char buf[2048];
1995 struct if_announcemsghdr *ifan;
1996 struct rt_msghdr *rtm;
1997
1998 do {
1999 if (read(sroute, buf, sizeof(buf)) < 0) {
2000 perror("read(PF_ROUTE)");
2001 break;
2002 }
2003 rtm = (struct rt_msghdr *) buf;
2004 if (rtm->rtm_version != RTM_VERSION)
2005 break;
2006 ifan = (struct if_announcemsghdr *) rtm;
2007 } while (rtm->rtm_type != RTM_IEEE80211 ||
2008 ifan->ifan_what != RTM_IEEE80211_SCAN);
2009 }
2010 close(sroute);
2011}
2012
2013static
2014DECL_CMD_FUNC(set80211scan, val, d)
2015{
2016 scan_and_wait(s);
2017 list_scan(s);
2018}
2019
2020static enum ieee80211_opmode get80211opmode(int s);
2021
2022static int
2023gettxseq(const struct ieee80211req_sta_info *si)
2024{
2025#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
2026
2027 int i, txseq;
2028
2029 if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
2030 return si->isi_txseqs[0];
2031 /* XXX not right but usually what folks want */
2032 txseq = 0;
2033 for (i = 0; i < IEEE80211_TID_SIZE; i++)
2034 if (si->isi_txseqs[i] > txseq)
2035 txseq = si->isi_txseqs[i];
2036 return txseq;
2037#undef IEEE80211_NODE_QOS
2038}
2039
2040static int
2041getrxseq(const struct ieee80211req_sta_info *si)
2042{
2043#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
2044
2045 int i, rxseq;
2046
2047 if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
2048 return si->isi_rxseqs[0];
2049 /* XXX not right but usually what folks want */
2050 rxseq = 0;
2051 for (i = 0; i < IEEE80211_TID_SIZE; i++)
2052 if (si->isi_rxseqs[i] > rxseq)
2053 rxseq = si->isi_rxseqs[i];
2054 return rxseq;
2055#undef IEEE80211_NODE_QOS
2056}
2057
2058static int
2059gettxrate(int txrate, int chanflags)
2060{
2061 if (txrate & 0x80) {
2062 txrate = htrates[txrate & 0xf];
2063 /* NB: could bump this more based on short gi */
2064 return chanflags & IEEE80211_CHAN_HT40 ? txrate : txrate / 2;
2065 } else
2066 return (txrate & IEEE80211_RATE_VAL) / 2;
2067}
2068
1559static void
1560list_stations(int s)
1561{
1562 union {
1563 struct ieee80211req_sta_req req;
1564 uint8_t buf[24*1024];
1565 } u;
1566 enum ieee80211_opmode opmode = get80211opmode(s);
2069static void
2070list_stations(int s)
2071{
2072 union {
2073 struct ieee80211req_sta_req req;
2074 uint8_t buf[24*1024];
2075 } u;
2076 enum ieee80211_opmode opmode = get80211opmode(s);
1567 struct ieee80211req ireq;
1568 const uint8_t *cp;
1569 int len;
1570
2077 const uint8_t *cp;
2078 int len;
2079
1571 (void) memset(&ireq, 0, sizeof(ireq));
1572 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1573 /* broadcast address =>'s get all stations */
1574 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
1575 if (opmode == IEEE80211_M_STA) {
1576 /*
1577 * Get information about the associated AP.
1578 */
2080 /* broadcast address =>'s get all stations */
2081 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
2082 if (opmode == IEEE80211_M_STA) {
2083 /*
2084 * Get information about the associated AP.
2085 */
1579 ireq.i_type = IEEE80211_IOC_BSSID;
1580 ireq.i_data = u.req.is_u.macaddr;
1581 ireq.i_len = IEEE80211_ADDR_LEN;
1582 (void) ioctl(s, SIOCG80211, &ireq);
2086 (void) get80211(s, IEEE80211_IOC_BSSID,
2087 u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
1583 }
2088 }
1584 ireq.i_type = IEEE80211_IOC_STA_INFO;
1585 ireq.i_data = &u;
1586 ireq.i_len = sizeof(u);
1587 if (ioctl(s, SIOCG80211, &ireq) < 0)
2089 if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
1588 errx(1, "unable to get station information");
2090 errx(1, "unable to get station information");
1589 len = ireq.i_len;
1590 if (len < sizeof(struct ieee80211req_sta_info))
1591 return;
1592
1593 getchaninfo(s);
1594
1595 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
1596 , "ADDR"
1597 , "AID"
1598 , "CHAN"
1599 , "RATE"
1600 , "RSSI"
1601 , "IDLE"
1602 , "TXSEQ"
1603 , "RXSEQ"
1604 , "CAPS"
1605 , "FLAG"
1606 );
1607 cp = (const uint8_t *) u.req.info;
1608 do {
1609 const struct ieee80211req_sta_info *si;
1610
1611 si = (const struct ieee80211req_sta_info *) cp;
1612 if (si->isi_len < sizeof(*si))
1613 break;
1614 printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s"
1615 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1616 , IEEE80211_AID(si->isi_associd)
1617 , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags)
2091 if (len < sizeof(struct ieee80211req_sta_info))
2092 return;
2093
2094 getchaninfo(s);
2095
2096 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
2097 , "ADDR"
2098 , "AID"
2099 , "CHAN"
2100 , "RATE"
2101 , "RSSI"
2102 , "IDLE"
2103 , "TXSEQ"
2104 , "RXSEQ"
2105 , "CAPS"
2106 , "FLAG"
2107 );
2108 cp = (const uint8_t *) u.req.info;
2109 do {
2110 const struct ieee80211req_sta_info *si;
2111
2112 si = (const struct ieee80211req_sta_info *) cp;
2113 if (si->isi_len < sizeof(*si))
2114 break;
2115 printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s"
2116 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
2117 , IEEE80211_AID(si->isi_associd)
2118 , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags)
1618 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
2119 , gettxrate(si->isi_txrate, si->isi_flags)
1619 , si->isi_rssi/2.
1620 , si->isi_inact
2120 , si->isi_rssi/2.
2121 , si->isi_inact
1621 , si->isi_txseqs[0]
1622 , si->isi_rxseqs[0]
2122 , gettxseq(si)
2123 , getrxseq(si)
1623 , getcaps(si->isi_capinfo)
1624 , getflags(si->isi_state)
1625 );
1626 printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
1627 printf("\n");
1628 cp += si->isi_len, len -= si->isi_len;
1629 } while (len >= sizeof(struct ieee80211req_sta_info));
1630}
1631
1632static const char *
1633get_chaninfo(const struct ieee80211_channel *c, int precise,
1634 char buf[], size_t bsize)
1635{
1636 buf[0] = '\0';
1637 if (IEEE80211_IS_CHAN_FHSS(c))
1638 strlcat(buf, " FHSS", bsize);
1639 if (IEEE80211_IS_CHAN_A(c)) {
1640 if (IEEE80211_IS_CHAN_HALF(c))
1641 strlcat(buf, " 11a/10Mhz", bsize);
1642 else if (IEEE80211_IS_CHAN_QUARTER(c))
1643 strlcat(buf, " 11a/5Mhz", bsize);
1644 else
1645 strlcat(buf, " 11a", bsize);
1646 }
1647 if (IEEE80211_IS_CHAN_ANYG(c)) {
1648 if (IEEE80211_IS_CHAN_HALF(c))
1649 strlcat(buf, " 11g/10Mhz", bsize);
1650 else if (IEEE80211_IS_CHAN_QUARTER(c))
1651 strlcat(buf, " 11g/5Mhz", bsize);
1652 else
1653 strlcat(buf, " 11g", bsize);
1654 } else if (IEEE80211_IS_CHAN_B(c))
1655 strlcat(buf, " 11b", bsize);
1656 if (IEEE80211_IS_CHAN_TURBO(c))
1657 strlcat(buf, " Turbo", bsize);
1658 if (precise) {
1659 if (IEEE80211_IS_CHAN_HT20(c))
1660 strlcat(buf, " ht/20", bsize);
1661 else if (IEEE80211_IS_CHAN_HT40D(c))
1662 strlcat(buf, " ht/40-", bsize);
1663 else if (IEEE80211_IS_CHAN_HT40U(c))
1664 strlcat(buf, " ht/40+", bsize);
1665 } else {
1666 if (IEEE80211_IS_CHAN_HT(c))
1667 strlcat(buf, " ht", bsize);
1668 }
1669 return buf;
1670}
1671
1672static void
2124 , getcaps(si->isi_capinfo)
2125 , getflags(si->isi_state)
2126 );
2127 printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
2128 printf("\n");
2129 cp += si->isi_len, len -= si->isi_len;
2130 } while (len >= sizeof(struct ieee80211req_sta_info));
2131}
2132
2133static const char *
2134get_chaninfo(const struct ieee80211_channel *c, int precise,
2135 char buf[], size_t bsize)
2136{
2137 buf[0] = '\0';
2138 if (IEEE80211_IS_CHAN_FHSS(c))
2139 strlcat(buf, " FHSS", bsize);
2140 if (IEEE80211_IS_CHAN_A(c)) {
2141 if (IEEE80211_IS_CHAN_HALF(c))
2142 strlcat(buf, " 11a/10Mhz", bsize);
2143 else if (IEEE80211_IS_CHAN_QUARTER(c))
2144 strlcat(buf, " 11a/5Mhz", bsize);
2145 else
2146 strlcat(buf, " 11a", bsize);
2147 }
2148 if (IEEE80211_IS_CHAN_ANYG(c)) {
2149 if (IEEE80211_IS_CHAN_HALF(c))
2150 strlcat(buf, " 11g/10Mhz", bsize);
2151 else if (IEEE80211_IS_CHAN_QUARTER(c))
2152 strlcat(buf, " 11g/5Mhz", bsize);
2153 else
2154 strlcat(buf, " 11g", bsize);
2155 } else if (IEEE80211_IS_CHAN_B(c))
2156 strlcat(buf, " 11b", bsize);
2157 if (IEEE80211_IS_CHAN_TURBO(c))
2158 strlcat(buf, " Turbo", bsize);
2159 if (precise) {
2160 if (IEEE80211_IS_CHAN_HT20(c))
2161 strlcat(buf, " ht/20", bsize);
2162 else if (IEEE80211_IS_CHAN_HT40D(c))
2163 strlcat(buf, " ht/40-", bsize);
2164 else if (IEEE80211_IS_CHAN_HT40U(c))
2165 strlcat(buf, " ht/40+", bsize);
2166 } else {
2167 if (IEEE80211_IS_CHAN_HT(c))
2168 strlcat(buf, " ht", bsize);
2169 }
2170 return buf;
2171}
2172
2173static void
1673print_chaninfo(const struct ieee80211_channel *c)
2174print_chaninfo(const struct ieee80211_channel *c, int verb)
1674{
1675 char buf[14];
1676
1677 printf("Channel %3u : %u%c Mhz%-14.14s",
1678 ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
1679 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
2175{
2176 char buf[14];
2177
2178 printf("Channel %3u : %u%c Mhz%-14.14s",
2179 ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
2180 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
1680 get_chaninfo(c, verbose, buf, sizeof(buf)));
2181 get_chaninfo(c, verb, buf, sizeof(buf)));
1681}
1682
1683static void
2182}
2183
2184static void
1684list_channels(int s, int allchans)
2185print_channels(int s, const struct ieee80211req_chaninfo *chans,
2186 int allchans, int verb)
1685{
1686 struct ieee80211req_chaninfo achans;
1687 uint8_t reported[IEEE80211_CHAN_BYTES];
1688 const struct ieee80211_channel *c;
1689 int i, half;
1690
2187{
2188 struct ieee80211req_chaninfo achans;
2189 uint8_t reported[IEEE80211_CHAN_BYTES];
2190 const struct ieee80211_channel *c;
2191 int i, half;
2192
1691 getchaninfo(s);
1692 memset(&achans, 0, sizeof(achans));
1693 memset(reported, 0, sizeof(reported));
1694 if (!allchans) {
1695 struct ieee80211req_chanlist active;
2193 memset(&achans, 0, sizeof(achans));
2194 memset(reported, 0, sizeof(reported));
2195 if (!allchans) {
2196 struct ieee80211req_chanlist active;
1696 struct ieee80211req ireq;
1697
2197
1698 (void) memset(&ireq, 0, sizeof(ireq));
1699 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1700 ireq.i_type = IEEE80211_IOC_CHANLIST;
1701 ireq.i_data = &active;
1702 ireq.i_len = sizeof(active);
1703 if (ioctl(s, SIOCG80211, &ireq) < 0)
2198 if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
1704 errx(1, "unable to get active channel list");
1705 memset(&achans, 0, sizeof(achans));
2199 errx(1, "unable to get active channel list");
2200 memset(&achans, 0, sizeof(achans));
1706 for (i = 0; i < chaninfo.ic_nchans; i++) {
1707 c = &chaninfo.ic_chans[i];
2201 for (i = 0; i < chans->ic_nchans; i++) {
2202 c = &chans->ic_chans[i];
1708 if (!isset(active.ic_channels, c->ic_ieee))
1709 continue;
1710 /*
1711 * Suppress compatible duplicates unless
1712 * verbose. The kernel gives us it's
1713 * complete channel list which has separate
1714 * entries for 11g/11b and 11a/turbo.
1715 */
2203 if (!isset(active.ic_channels, c->ic_ieee))
2204 continue;
2205 /*
2206 * Suppress compatible duplicates unless
2207 * verbose. The kernel gives us it's
2208 * complete channel list which has separate
2209 * entries for 11g/11b and 11a/turbo.
2210 */
1716 if (isset(reported, c->ic_ieee) && !verbose) {
2211 if (isset(reported, c->ic_ieee) && !verb) {
1717 /* XXX we assume duplicates are adjacent */
1718 achans.ic_chans[achans.ic_nchans-1] = *c;
1719 } else {
1720 achans.ic_chans[achans.ic_nchans++] = *c;
1721 setbit(reported, c->ic_ieee);
1722 }
1723 }
1724 } else {
2212 /* XXX we assume duplicates are adjacent */
2213 achans.ic_chans[achans.ic_nchans-1] = *c;
2214 } else {
2215 achans.ic_chans[achans.ic_nchans++] = *c;
2216 setbit(reported, c->ic_ieee);
2217 }
2218 }
2219 } else {
1725 for (i = 0; i < chaninfo.ic_nchans; i++) {
1726 c = &chaninfo.ic_chans[i];
2220 for (i = 0; i < chans->ic_nchans; i++) {
2221 c = &chans->ic_chans[i];
1727 /* suppress duplicates as above */
2222 /* suppress duplicates as above */
1728 if (isset(reported, c->ic_ieee) && !verbose) {
2223 if (isset(reported, c->ic_ieee) && !verb) {
1729 /* XXX we assume duplicates are adjacent */
1730 achans.ic_chans[achans.ic_nchans-1] = *c;
1731 } else {
1732 achans.ic_chans[achans.ic_nchans++] = *c;
1733 setbit(reported, c->ic_ieee);
1734 }
1735 }
1736 }
1737 half = achans.ic_nchans / 2;
1738 if (achans.ic_nchans % 2)
1739 half++;
1740
1741 for (i = 0; i < achans.ic_nchans / 2; i++) {
2224 /* XXX we assume duplicates are adjacent */
2225 achans.ic_chans[achans.ic_nchans-1] = *c;
2226 } else {
2227 achans.ic_chans[achans.ic_nchans++] = *c;
2228 setbit(reported, c->ic_ieee);
2229 }
2230 }
2231 }
2232 half = achans.ic_nchans / 2;
2233 if (achans.ic_nchans % 2)
2234 half++;
2235
2236 for (i = 0; i < achans.ic_nchans / 2; i++) {
1742 print_chaninfo(&achans.ic_chans[i]);
1743 print_chaninfo(&achans.ic_chans[half+i]);
2237 print_chaninfo(&achans.ic_chans[i], verb);
2238 print_chaninfo(&achans.ic_chans[half+i], verb);
1744 printf("\n");
1745 }
1746 if (achans.ic_nchans % 2) {
2239 printf("\n");
2240 }
2241 if (achans.ic_nchans % 2) {
1747 print_chaninfo(&achans.ic_chans[i]);
2242 print_chaninfo(&achans.ic_chans[i], verb);
1748 printf("\n");
1749 }
1750}
1751
1752static void
2243 printf("\n");
2244 }
2245}
2246
2247static void
2248list_channels(int s, int allchans)
2249{
2250 getchaninfo(s);
2251 print_channels(s, &chaninfo, allchans, verbose);
2252}
2253
2254static void
1753print_txpow(const struct ieee80211_channel *c)
1754{
1755 printf("Channel %3u : %u Mhz %3.1f reg %2d ",
1756 c->ic_ieee, c->ic_freq,
1757 c->ic_maxpower/2., c->ic_maxregpower);
1758}
1759
1760static void
1761print_txpow_verbose(const struct ieee80211_channel *c)
1762{
2255print_txpow(const struct ieee80211_channel *c)
2256{
2257 printf("Channel %3u : %u Mhz %3.1f reg %2d ",
2258 c->ic_ieee, c->ic_freq,
2259 c->ic_maxpower/2., c->ic_maxregpower);
2260}
2261
2262static void
2263print_txpow_verbose(const struct ieee80211_channel *c)
2264{
1763 print_chaninfo(c);
2265 print_chaninfo(c, 1);
1764 printf("min %4.1f dBm max %3.1f dBm reg %2d dBm",
1765 c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
1766 /* indicate where regulatory cap limits power use */
1767 if (c->ic_maxpower > 2*c->ic_maxregpower)
1768 printf(" <");
1769}
1770
1771static void
1772list_txpow(int s)
1773{
1774 struct ieee80211req_chaninfo achans;
1775 uint8_t reported[IEEE80211_CHAN_BYTES];
1776 struct ieee80211_channel *c, *prev;
1777 int i, half;
1778
1779 getchaninfo(s);
1780 memset(&achans, 0, sizeof(achans));
1781 memset(reported, 0, sizeof(reported));
1782 for (i = 0; i < chaninfo.ic_nchans; i++) {
1783 c = &chaninfo.ic_chans[i];
1784 /* suppress duplicates as above */
1785 if (isset(reported, c->ic_ieee) && !verbose) {
1786 /* XXX we assume duplicates are adjacent */
1787 prev = &achans.ic_chans[achans.ic_nchans-1];
1788 /* display highest power on channel */
1789 if (c->ic_maxpower > prev->ic_maxpower)
1790 *prev = *c;
1791 } else {
1792 achans.ic_chans[achans.ic_nchans++] = *c;
1793 setbit(reported, c->ic_ieee);
1794 }
1795 }
1796 if (!verbose) {
1797 half = achans.ic_nchans / 2;
1798 if (achans.ic_nchans % 2)
1799 half++;
1800
1801 for (i = 0; i < achans.ic_nchans / 2; i++) {
1802 print_txpow(&achans.ic_chans[i]);
1803 print_txpow(&achans.ic_chans[half+i]);
1804 printf("\n");
1805 }
1806 if (achans.ic_nchans % 2) {
1807 print_txpow(&achans.ic_chans[i]);
1808 printf("\n");
1809 }
1810 } else {
1811 for (i = 0; i < achans.ic_nchans; i++) {
1812 print_txpow_verbose(&achans.ic_chans[i]);
1813 printf("\n");
1814 }
1815 }
1816}
1817
1818static void
1819list_keys(int s)
1820{
1821}
1822
1823#define IEEE80211_C_BITS \
1824"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\7FF\10TURBOP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1825"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1826"\31WPA2\32BURST\33WME\34WDS\36BGSCAN\37TXFRAG"
1827
1828static void
1829list_capabilities(int s)
1830{
1831 struct ieee80211req ireq;
1832 u_int32_t caps;
1833
1834 (void) memset(&ireq, 0, sizeof(ireq));
1835 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1836 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1837 if (ioctl(s, SIOCG80211, &ireq) < 0)
1838 errx(1, "unable to get driver capabilities");
1839 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1840 printb(name, caps, IEEE80211_C_BITS);
1841 putchar('\n');
1842}
1843
2266 printf("min %4.1f dBm max %3.1f dBm reg %2d dBm",
2267 c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
2268 /* indicate where regulatory cap limits power use */
2269 if (c->ic_maxpower > 2*c->ic_maxregpower)
2270 printf(" <");
2271}
2272
2273static void
2274list_txpow(int s)
2275{
2276 struct ieee80211req_chaninfo achans;
2277 uint8_t reported[IEEE80211_CHAN_BYTES];
2278 struct ieee80211_channel *c, *prev;
2279 int i, half;
2280
2281 getchaninfo(s);
2282 memset(&achans, 0, sizeof(achans));
2283 memset(reported, 0, sizeof(reported));
2284 for (i = 0; i < chaninfo.ic_nchans; i++) {
2285 c = &chaninfo.ic_chans[i];
2286 /* suppress duplicates as above */
2287 if (isset(reported, c->ic_ieee) && !verbose) {
2288 /* XXX we assume duplicates are adjacent */
2289 prev = &achans.ic_chans[achans.ic_nchans-1];
2290 /* display highest power on channel */
2291 if (c->ic_maxpower > prev->ic_maxpower)
2292 *prev = *c;
2293 } else {
2294 achans.ic_chans[achans.ic_nchans++] = *c;
2295 setbit(reported, c->ic_ieee);
2296 }
2297 }
2298 if (!verbose) {
2299 half = achans.ic_nchans / 2;
2300 if (achans.ic_nchans % 2)
2301 half++;
2302
2303 for (i = 0; i < achans.ic_nchans / 2; i++) {
2304 print_txpow(&achans.ic_chans[i]);
2305 print_txpow(&achans.ic_chans[half+i]);
2306 printf("\n");
2307 }
2308 if (achans.ic_nchans % 2) {
2309 print_txpow(&achans.ic_chans[i]);
2310 printf("\n");
2311 }
2312 } else {
2313 for (i = 0; i < achans.ic_nchans; i++) {
2314 print_txpow_verbose(&achans.ic_chans[i]);
2315 printf("\n");
2316 }
2317 }
2318}
2319
2320static void
2321list_keys(int s)
2322{
2323}
2324
2325#define IEEE80211_C_BITS \
2326"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\7FF\10TURBOP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
2327"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
2328"\31WPA2\32BURST\33WME\34WDS\36BGSCAN\37TXFRAG"
2329
2330static void
2331list_capabilities(int s)
2332{
2333 struct ieee80211req ireq;
2334 u_int32_t caps;
2335
2336 (void) memset(&ireq, 0, sizeof(ireq));
2337 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
2338 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
2339 if (ioctl(s, SIOCG80211, &ireq) < 0)
2340 errx(1, "unable to get driver capabilities");
2341 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
2342 printb(name, caps, IEEE80211_C_BITS);
2343 putchar('\n');
2344}
2345
1844static void
1845list_wme(int s)
2346static int
2347get80211wme(int s, int param, int ac, int *val)
1846{
2348{
1847 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1848 struct ieee80211req ireq;
2349 struct ieee80211req ireq;
1849 int ac;
1850
1851 (void) memset(&ireq, 0, sizeof(ireq));
1852 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
2350
2351 (void) memset(&ireq, 0, sizeof(ireq));
2352 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1853 ireq.i_len = 0;
2353 ireq.i_type = param;
2354 ireq.i_len = ac;
2355 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2356 warn("cannot get WME parameter %d, ac %d%s",
2357 param, ac & IEEE80211_WMEPARAM_VAL,
2358 ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
2359 return -1;
2360 }
2361 *val = ireq.i_val;
2362 return 0;
2363}
2364
2365static void
2366list_wme(int s)
2367{
2368 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
2369 int ac, val;
2370
1854 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1855again:
2371 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
2372again:
1856 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
2373 if (ac & IEEE80211_WMEPARAM_BSS)
1857 printf("\t%s", " ");
1858 else
1859 printf("\t%s", acnames[ac]);
1860
2374 printf("\t%s", " ");
2375 else
2376 printf("\t%s", acnames[ac]);
2377
1861 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1862
1863 /* show WME BSS parameters */
2378 /* show WME BSS parameters */
1864 ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1865 if (ioctl(s, SIOCG80211, &ireq) != -1)
1866 printf(" cwmin %2u", ireq.i_val);
1867 ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1868 if (ioctl(s, SIOCG80211, &ireq) != -1)
1869 printf(" cwmax %2u", ireq.i_val);
1870 ireq.i_type = IEEE80211_IOC_WME_AIFS;
1871 if (ioctl(s, SIOCG80211, &ireq) != -1)
1872 printf(" aifs %2u", ireq.i_val);
1873 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1874 if (ioctl(s, SIOCG80211, &ireq) != -1)
1875 printf(" txopLimit %3u", ireq.i_val);
1876 ireq.i_type = IEEE80211_IOC_WME_ACM;
1877 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1878 if (ireq.i_val)
2379 if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
2380 printf(" cwmin %2u", val);
2381 if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
2382 printf(" cwmax %2u", val);
2383 if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
2384 printf(" aifs %2u", val);
2385 if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
2386 printf(" txopLimit %3u", val);
2387 if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
2388 if (val)
1879 printf(" acm");
1880 else if (verbose)
1881 printf(" -acm");
1882 }
1883 /* !BSS only */
2389 printf(" acm");
2390 else if (verbose)
2391 printf(" -acm");
2392 }
2393 /* !BSS only */
1884 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1885 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1886 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1887 if (!ireq.i_val)
2394 if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
2395 if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
2396 if (!val)
1888 printf(" -ack");
1889 else if (verbose)
1890 printf(" ack");
1891 }
1892 }
1893 printf("\n");
2397 printf(" -ack");
2398 else if (verbose)
2399 printf(" ack");
2400 }
2401 }
2402 printf("\n");
1894 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1895 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
2403 if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
2404 ac |= IEEE80211_WMEPARAM_BSS;
1896 goto again;
1897 } else
2405 goto again;
2406 } else
1898 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
2407 ac &= ~IEEE80211_WMEPARAM_BSS;
1899 }
1900}
1901
1902static void
2408 }
2409}
2410
2411static void
2412printpolicy(int policy)
2413{
2414 switch (policy) {
2415 case IEEE80211_MACCMD_POLICY_OPEN:
2416 printf("policy: open\n");
2417 break;
2418 case IEEE80211_MACCMD_POLICY_ALLOW:
2419 printf("policy: allow\n");
2420 break;
2421 case IEEE80211_MACCMD_POLICY_DENY:
2422 printf("policy: deny\n");
2423 break;
2424 default:
2425 printf("policy: unknown (%u)\n", policy);
2426 break;
2427 }
2428}
2429
2430static void
1903list_mac(int s)
1904{
1905 struct ieee80211req ireq;
1906 struct ieee80211req_maclist *acllist;
2431list_mac(int s)
2432{
2433 struct ieee80211req ireq;
2434 struct ieee80211req_maclist *acllist;
1907 int i, nacls, policy;
2435 int i, nacls, policy, len;
2436 uint8_t *data;
1908 char c;
1909
1910 (void) memset(&ireq, 0, sizeof(ireq));
1911 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1912 ireq.i_type = IEEE80211_IOC_MACCMD;
1913 ireq.i_val = IEEE80211_MACCMD_POLICY;
1914 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1915 if (errno == EINVAL) {
1916 printf("No acl policy loaded\n");
1917 return;
1918 }
1919 err(1, "unable to get mac policy");
1920 }
1921 policy = ireq.i_val;
2437 char c;
2438
2439 (void) memset(&ireq, 0, sizeof(ireq));
2440 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
2441 ireq.i_type = IEEE80211_IOC_MACCMD;
2442 ireq.i_val = IEEE80211_MACCMD_POLICY;
2443 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2444 if (errno == EINVAL) {
2445 printf("No acl policy loaded\n");
2446 return;
2447 }
2448 err(1, "unable to get mac policy");
2449 }
2450 policy = ireq.i_val;
1922
1923 ireq.i_val = IEEE80211_MACCMD_LIST;
1924 ireq.i_len = 0;
1925 if (ioctl(s, SIOCG80211, &ireq) < 0)
1926 err(1, "unable to get mac acl list size");
1927 if (ireq.i_len == 0) /* NB: no acls */
1928 return;
1929
1930 ireq.i_data = malloc(ireq.i_len);
1931 if (ireq.i_data == NULL)
1932 err(1, "out of memory for acl list");
1933
1934 if (ioctl(s, SIOCG80211, &ireq) < 0)
1935 err(1, "unable to get mac acl list");
1936 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
2451 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1937 if (verbose)
1938 printf("policy: open\n");
1939 c = '*';
1940 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
2452 c = '*';
2453 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1941 if (verbose)
1942 printf("policy: allow\n");
1943 c = '+';
1944 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
2454 c = '+';
2455 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1945 if (verbose)
1946 printf("policy: deny\n");
1947 c = '-';
1948 } else {
1949 printf("policy: unknown (%u)\n", policy);
1950 c = '?';
1951 }
2456 c = '-';
2457 } else {
2458 printf("policy: unknown (%u)\n", policy);
2459 c = '?';
2460 }
1952 nacls = ireq.i_len / sizeof(*acllist);
1953 acllist = (struct ieee80211req_maclist *) ireq.i_data;
2461 if (verbose || c == '?')
2462 printpolicy(policy);
2463
2464 if (get80211len(s, IEEE80211_MACCMD_LIST, NULL, 0, &len) < 0)
2465 err(1, "unable to get mac acl list size");
2466 if (len == 0) { /* NB: no acls */
2467 if (!(verbose || c == '?'))
2468 printpolicy(policy);
2469 return;
2470 }
2471
2472 data = malloc(len);
2473 if (data == NULL)
2474 err(1, "out of memory for acl list");
2475
2476 if (get80211(s, IEEE80211_MACCMD_LIST, data, len) < 0)
2477 err(1, "unable to get mac acl list");
2478 nacls = len / sizeof(*acllist);
2479 acllist = (struct ieee80211req_maclist *) data;
1954 for (i = 0; i < nacls; i++)
1955 printf("%c%s\n", c, ether_ntoa(
1956 (const struct ether_addr *) acllist[i].ml_macaddr));
2480 for (i = 0; i < nacls; i++)
2481 printf("%c%s\n", c, ether_ntoa(
2482 (const struct ether_addr *) acllist[i].ml_macaddr));
2483 free(data);
1957}
1958
1959static
1960DECL_CMD_FUNC(set80211list, arg, d)
1961{
1962#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1963
2484}
2485
2486static
2487DECL_CMD_FUNC(set80211list, arg, d)
2488{
2489#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
2490
2491 LINE_INIT('\t');
2492
1964 if (iseq(arg, "sta"))
1965 list_stations(s);
1966 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1967 list_scan(s);
1968 else if (iseq(arg, "chan") || iseq(arg, "freq"))
1969 list_channels(s, 1);
1970 else if (iseq(arg, "active"))
1971 list_channels(s, 0);
1972 else if (iseq(arg, "keys"))
1973 list_keys(s);
1974 else if (iseq(arg, "caps"))
1975 list_capabilities(s);
1976 else if (iseq(arg, "wme"))
1977 list_wme(s);
1978 else if (iseq(arg, "mac"))
1979 list_mac(s);
1980 else if (iseq(arg, "txpow"))
1981 list_txpow(s);
1982 else
1983 errx(1, "Don't know how to list %s for %s", arg, name);
1984#undef iseq
1985}
1986
1987static enum ieee80211_opmode
1988get80211opmode(int s)
1989{
1990 struct ifmediareq ifmr;
1991
1992 (void) memset(&ifmr, 0, sizeof(ifmr));
1993 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1994
1995 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1996 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1997 return IEEE80211_M_IBSS; /* XXX ahdemo */
1998 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1999 return IEEE80211_M_HOSTAP;
2000 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
2001 return IEEE80211_M_MONITOR;
2002 }
2003 return IEEE80211_M_STA;
2004}
2005
2006#if 0
2007static void
2008printcipher(int s, struct ieee80211req *ireq, int keylenop)
2009{
2010 switch (ireq->i_val) {
2011 case IEEE80211_CIPHER_WEP:
2012 ireq->i_type = keylenop;
2013 if (ioctl(s, SIOCG80211, ireq) != -1)
2014 printf("WEP-%s",
2015 ireq->i_len <= 5 ? "40" :
2016 ireq->i_len <= 13 ? "104" : "128");
2017 else
2018 printf("WEP");
2019 break;
2020 case IEEE80211_CIPHER_TKIP:
2021 printf("TKIP");
2022 break;
2023 case IEEE80211_CIPHER_AES_OCB:
2024 printf("AES-OCB");
2025 break;
2026 case IEEE80211_CIPHER_AES_CCM:
2027 printf("AES-CCM");
2028 break;
2029 case IEEE80211_CIPHER_CKIP:
2030 printf("CKIP");
2031 break;
2032 case IEEE80211_CIPHER_NONE:
2033 printf("NONE");
2034 break;
2035 default:
2036 printf("UNKNOWN (0x%x)", ireq->i_val);
2037 break;
2038 }
2039}
2040#endif
2041
2493 if (iseq(arg, "sta"))
2494 list_stations(s);
2495 else if (iseq(arg, "scan") || iseq(arg, "ap"))
2496 list_scan(s);
2497 else if (iseq(arg, "chan") || iseq(arg, "freq"))
2498 list_channels(s, 1);
2499 else if (iseq(arg, "active"))
2500 list_channels(s, 0);
2501 else if (iseq(arg, "keys"))
2502 list_keys(s);
2503 else if (iseq(arg, "caps"))
2504 list_capabilities(s);
2505 else if (iseq(arg, "wme"))
2506 list_wme(s);
2507 else if (iseq(arg, "mac"))
2508 list_mac(s);
2509 else if (iseq(arg, "txpow"))
2510 list_txpow(s);
2511 else
2512 errx(1, "Don't know how to list %s for %s", arg, name);
2513#undef iseq
2514}
2515
2516static enum ieee80211_opmode
2517get80211opmode(int s)
2518{
2519 struct ifmediareq ifmr;
2520
2521 (void) memset(&ifmr, 0, sizeof(ifmr));
2522 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
2523
2524 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
2525 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
2526 return IEEE80211_M_IBSS; /* XXX ahdemo */
2527 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
2528 return IEEE80211_M_HOSTAP;
2529 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
2530 return IEEE80211_M_MONITOR;
2531 }
2532 return IEEE80211_M_STA;
2533}
2534
2535#if 0
2536static void
2537printcipher(int s, struct ieee80211req *ireq, int keylenop)
2538{
2539 switch (ireq->i_val) {
2540 case IEEE80211_CIPHER_WEP:
2541 ireq->i_type = keylenop;
2542 if (ioctl(s, SIOCG80211, ireq) != -1)
2543 printf("WEP-%s",
2544 ireq->i_len <= 5 ? "40" :
2545 ireq->i_len <= 13 ? "104" : "128");
2546 else
2547 printf("WEP");
2548 break;
2549 case IEEE80211_CIPHER_TKIP:
2550 printf("TKIP");
2551 break;
2552 case IEEE80211_CIPHER_AES_OCB:
2553 printf("AES-OCB");
2554 break;
2555 case IEEE80211_CIPHER_AES_CCM:
2556 printf("AES-CCM");
2557 break;
2558 case IEEE80211_CIPHER_CKIP:
2559 printf("CKIP");
2560 break;
2561 case IEEE80211_CIPHER_NONE:
2562 printf("NONE");
2563 break;
2564 default:
2565 printf("UNKNOWN (0x%x)", ireq->i_val);
2566 break;
2567 }
2568}
2569#endif
2570
2042#define MAXCOL 78
2043static int col;
2044static char spacer;
2045
2046static void
2571static void
2047LINE_BREAK(void)
2048{
2049 if (spacer != '\t') {
2050 printf("\n");
2051 spacer = '\t';
2052 }
2053 col = 8; /* 8-col tab */
2054}
2055
2056static void
2057LINE_CHECK(const char *fmt, ...)
2058{
2059 char buf[80];
2060 va_list ap;
2061 int n;
2062
2063 va_start(ap, fmt);
2064 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
2065 va_end(ap);
2066 col += 1+n;
2067 if (col > MAXCOL) {
2068 LINE_BREAK();
2069 col += n;
2070 }
2071 buf[0] = spacer;
2072 printf("%s", buf);
2073 spacer = ' ';
2074}
2075
2076static void
2077printkey(const struct ieee80211req_key *ik)
2078{
2079 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
2080 int keylen = ik->ik_keylen;
2081 int printcontents;
2082
2083 printcontents = printkeys &&
2084 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
2085 if (printcontents)
2086 LINE_BREAK();
2087 switch (ik->ik_type) {
2088 case IEEE80211_CIPHER_WEP:
2089 /* compatibility */
2090 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
2091 keylen <= 5 ? "40-bit" :
2092 keylen <= 13 ? "104-bit" : "128-bit");
2093 break;
2094 case IEEE80211_CIPHER_TKIP:
2095 if (keylen > 128/8)
2096 keylen -= 128/8; /* ignore MIC for now */
2097 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2098 break;
2099 case IEEE80211_CIPHER_AES_OCB:
2100 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2101 break;
2102 case IEEE80211_CIPHER_AES_CCM:
2103 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2104 break;
2105 case IEEE80211_CIPHER_CKIP:
2106 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2107 break;
2108 case IEEE80211_CIPHER_NONE:
2109 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2110 break;
2111 default:
2112 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
2113 ik->ik_type, ik->ik_keyix+1, 8*keylen);
2114 break;
2115 }
2116 if (printcontents) {
2117 int i;
2118
2119 printf(" <");
2120 for (i = 0; i < keylen; i++)
2121 printf("%02x", ik->ik_keydata[i]);
2122 printf(">");
2123 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
2124 (ik->ik_keyrsc != 0 || verbose))
2125 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
2126 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
2127 (ik->ik_keytsc != 0 || verbose))
2128 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
2129 if (ik->ik_flags != 0 && verbose) {
2130 const char *sep = " ";
2131
2132 if (ik->ik_flags & IEEE80211_KEY_XMIT)
2133 printf("%stx", sep), sep = "+";
2134 if (ik->ik_flags & IEEE80211_KEY_RECV)
2135 printf("%srx", sep), sep = "+";
2136 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
2137 printf("%sdef", sep), sep = "+";
2138 }
2139 LINE_BREAK();
2140 }
2141}
2142
2143static void
2572printkey(const struct ieee80211req_key *ik)
2573{
2574 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
2575 int keylen = ik->ik_keylen;
2576 int printcontents;
2577
2578 printcontents = printkeys &&
2579 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
2580 if (printcontents)
2581 LINE_BREAK();
2582 switch (ik->ik_type) {
2583 case IEEE80211_CIPHER_WEP:
2584 /* compatibility */
2585 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
2586 keylen <= 5 ? "40-bit" :
2587 keylen <= 13 ? "104-bit" : "128-bit");
2588 break;
2589 case IEEE80211_CIPHER_TKIP:
2590 if (keylen > 128/8)
2591 keylen -= 128/8; /* ignore MIC for now */
2592 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2593 break;
2594 case IEEE80211_CIPHER_AES_OCB:
2595 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2596 break;
2597 case IEEE80211_CIPHER_AES_CCM:
2598 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2599 break;
2600 case IEEE80211_CIPHER_CKIP:
2601 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2602 break;
2603 case IEEE80211_CIPHER_NONE:
2604 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
2605 break;
2606 default:
2607 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
2608 ik->ik_type, ik->ik_keyix+1, 8*keylen);
2609 break;
2610 }
2611 if (printcontents) {
2612 int i;
2613
2614 printf(" <");
2615 for (i = 0; i < keylen; i++)
2616 printf("%02x", ik->ik_keydata[i]);
2617 printf(">");
2618 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
2619 (ik->ik_keyrsc != 0 || verbose))
2620 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
2621 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
2622 (ik->ik_keytsc != 0 || verbose))
2623 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
2624 if (ik->ik_flags != 0 && verbose) {
2625 const char *sep = " ";
2626
2627 if (ik->ik_flags & IEEE80211_KEY_XMIT)
2628 printf("%stx", sep), sep = "+";
2629 if (ik->ik_flags & IEEE80211_KEY_RECV)
2630 printf("%srx", sep), sep = "+";
2631 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
2632 printf("%sdef", sep), sep = "+";
2633 }
2634 LINE_BREAK();
2635 }
2636}
2637
2638static void
2144ieee80211_status(int s)
2639printrate(const char *tag, int v, int defrate, int defmcs)
2145{
2640{
2146 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
2147 enum ieee80211_opmode opmode = get80211opmode(s);
2148 int i, num, wpa, wme, bgscan, bgscaninterval;
2641 if (v == 11)
2642 LINE_CHECK("%s 5.5", tag);
2643 else if (v & 0x80) {
2644 if (v != defmcs)
2645 LINE_CHECK("%s %d", tag, v &~ 0x80);
2646 } else {
2647 if (v != defrate)
2648 LINE_CHECK("%s %d", tag, v/2);
2649 }
2650}
2651
2652static int
2653getssid(int s, int ix, void *data, size_t len, int *plen)
2654{
2149 struct ieee80211req ireq;
2655 struct ieee80211req ireq;
2150 u_int8_t data[32];
2151 struct ieee80211_channel chan;
2152 const struct ieee80211_channel *c;
2153
2154 (void) memset(&ireq, 0, sizeof(ireq));
2155 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
2656
2657 (void) memset(&ireq, 0, sizeof(ireq));
2658 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
2156 ireq.i_data = &data;
2659 ireq.i_type = IEEE80211_IOC_SSID;
2660 ireq.i_val = ix;
2661 ireq.i_data = data;
2662 ireq.i_len = len;
2663 if (ioctl(s, SIOCG80211, &ireq) < 0)
2664 return -1;
2665 *plen = ireq.i_len;
2666 return 0;
2667}
2157
2668
2158 wpa = 0; /* unknown/not set */
2159 bgscan = 0; /* unknown/not set */
2669static void
2670printrssi(const char *tag, int rssi)
2671{
2672 if (rssi & 1)
2673 LINE_CHECK("%s %u.5", tag, rssi/2);
2674 else
2675 LINE_CHECK("%s %u", tag, rssi/2);
2676}
2160
2677
2161 ireq.i_type = IEEE80211_IOC_SSID;
2162 ireq.i_val = -1;
2163 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2678static void
2679ieee80211_status(int s)
2680{
2681 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
2682 enum ieee80211_opmode opmode = get80211opmode(s);
2683 int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode;
2684 uint8_t data[32];
2685 const struct ieee80211_channel *c;
2686
2687 if (getssid(s, -1, data, sizeof(data), &len) < 0) {
2164 /* If we can't get the SSID, this isn't an 802.11 device. */
2165 return;
2166 }
2688 /* If we can't get the SSID, this isn't an 802.11 device. */
2689 return;
2690 }
2167 num = 0;
2168 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
2169 if (ioctl(s, SIOCG80211, &ireq) >= 0)
2170 num = ireq.i_val;
2691
2692 /*
2693 * Invalidate cached state so printing status for multiple
2694 * if's doesn't reuse the first interfaces' cached state.
2695 */
2696 gotcurchan = 0;
2697 gothtconf = 0;
2698
2699 if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0)
2700 num = 0;
2171 printf("\tssid ");
2172 if (num > 1) {
2701 printf("\tssid ");
2702 if (num > 1) {
2173 ireq.i_type = IEEE80211_IOC_SSID;
2174 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
2175 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
2176 printf(" %d:", ireq.i_val + 1);
2177 print_string(data, ireq.i_len);
2703 for (i = 0; i < num; i++) {
2704 if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) {
2705 printf(" %d:", i + 1);
2706 print_string(data, len);
2178 }
2179 }
2180 } else
2707 }
2708 }
2709 } else
2181 print_string(data, ireq.i_len);
2710 print_string(data, len);
2182
2711
2183 ireq.i_data = &chan;
2184 ireq.i_len = sizeof(chan);
2185 ireq.i_type = IEEE80211_IOC_CURCHAN;
2186 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2187 /* fall back to legacy ioctl */
2188 ireq.i_data = NULL;
2189 ireq.i_len = 0;
2190 ireq.i_type = IEEE80211_IOC_CHANNEL;
2191 if (ioctl(s, SIOCG80211, &ireq) < 0)
2192 goto end;
2193 getchaninfo(s);
2194 mapchan(&chan, ireq.i_val, 0);
2195 }
2196 c = &chan;
2712 c = getcurchan(s);
2197 if (c->ic_freq != IEEE80211_CHAN_ANY) {
2198 char buf[14];
2199 printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq,
2200 get_chaninfo(c, 1, buf, sizeof(buf)));
2201 } else if (verbose)
2202 printf(" channel UNDEF");
2713 if (c->ic_freq != IEEE80211_CHAN_ANY) {
2714 char buf[14];
2715 printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq,
2716 get_chaninfo(c, 1, buf, sizeof(buf)));
2717 } else if (verbose)
2718 printf(" channel UNDEF");
2203 ireq.i_data = &data; /* reset data buffer */
2204
2719
2205 ireq.i_type = IEEE80211_IOC_BSSID;
2206 ireq.i_len = IEEE80211_ADDR_LEN;
2207 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
2208 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
2209 printf(" bssid %s", ether_ntoa(ireq.i_data));
2720 if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 &&
2721 (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
2722 printf(" bssid %s", ether_ntoa((struct ether_addr *)data));
2210
2723
2211 ireq.i_type = IEEE80211_IOC_STATIONNAME;
2212 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2724 if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) {
2213 printf("\n\tstationname ");
2725 printf("\n\tstationname ");
2214 print_string(data, ireq.i_len);
2726 print_string(data, len);
2215 }
2216
2217 spacer = ' '; /* force first break */
2218 LINE_BREAK();
2219
2727 }
2728
2729 spacer = ' '; /* force first break */
2730 LINE_BREAK();
2731
2220 ireq.i_type = IEEE80211_IOC_AUTHMODE;
2221 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2222 switch (ireq.i_val) {
2223 case IEEE80211_AUTH_NONE:
2224 LINE_CHECK("authmode NONE");
2732 wpa = 0;
2733 if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) {
2734 switch (val) {
2735 case IEEE80211_AUTH_NONE:
2736 LINE_CHECK("authmode NONE");
2737 break;
2738 case IEEE80211_AUTH_OPEN:
2739 LINE_CHECK("authmode OPEN");
2740 break;
2741 case IEEE80211_AUTH_SHARED:
2742 LINE_CHECK("authmode SHARED");
2743 break;
2744 case IEEE80211_AUTH_8021X:
2745 LINE_CHECK("authmode 802.1x");
2746 break;
2747 case IEEE80211_AUTH_WPA:
2748 if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0)
2749 wpa = 1; /* default to WPA1 */
2750 switch (wpa) {
2751 case 2:
2752 LINE_CHECK("authmode WPA2/802.11i");
2225 break;
2753 break;
2226 case IEEE80211_AUTH_OPEN:
2227 LINE_CHECK("authmode OPEN");
2754 case 3:
2755 LINE_CHECK("authmode WPA1+WPA2/802.11i");
2228 break;
2756 break;
2229 case IEEE80211_AUTH_SHARED:
2230 LINE_CHECK("authmode SHARED");
2231 break;
2232 case IEEE80211_AUTH_8021X:
2233 LINE_CHECK("authmode 802.1x");
2234 break;
2235 case IEEE80211_AUTH_WPA:
2236 ireq.i_type = IEEE80211_IOC_WPA;
2237 if (ioctl(s, SIOCG80211, &ireq) != -1)
2238 wpa = ireq.i_val;
2239 if (!wpa)
2240 wpa = 1; /* default to WPA1 */
2241 switch (wpa) {
2242 case 2:
2243 LINE_CHECK("authmode WPA2/802.11i");
2244 break;
2245 case 3:
2246 LINE_CHECK("authmode WPA1+WPA2/802.11i");
2247 break;
2248 default:
2249 LINE_CHECK("authmode WPA");
2250 break;
2251 }
2252 break;
2253 case IEEE80211_AUTH_AUTO:
2254 LINE_CHECK("authmode AUTO");
2255 break;
2256 default:
2757 default:
2257 LINE_CHECK("authmode UNKNOWN (0x%x)",
2258 ireq.i_val);
2758 LINE_CHECK("authmode WPA");
2259 break;
2759 break;
2760 }
2761 break;
2762 case IEEE80211_AUTH_AUTO:
2763 LINE_CHECK("authmode AUTO");
2764 break;
2765 default:
2766 LINE_CHECK("authmode UNKNOWN (0x%x)", val);
2767 break;
2260 }
2261 }
2262
2768 }
2769 }
2770
2263 ireq.i_type = IEEE80211_IOC_WEP;
2264 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
2265 ireq.i_val != IEEE80211_WEP_NOSUP) {
2266 int firstkey, wepmode;
2771 if (wpa || verbose) {
2772 if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) {
2773 if (val)
2774 LINE_CHECK("countermeasures");
2775 else if (verbose)
2776 LINE_CHECK("-countermeasures");
2777 }
2778 }
2267
2779
2268 wepmode = ireq.i_val;
2780 if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 &&
2781 wepmode != IEEE80211_WEP_NOSUP) {
2782 int firstkey;
2783
2269 switch (wepmode) {
2784 switch (wepmode) {
2270 case IEEE80211_WEP_OFF:
2271 LINE_CHECK("privacy OFF");
2272 break;
2273 case IEEE80211_WEP_ON:
2274 LINE_CHECK("privacy ON");
2275 break;
2276 case IEEE80211_WEP_MIXED:
2277 LINE_CHECK("privacy MIXED");
2278 break;
2279 default:
2280 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
2281 break;
2785 case IEEE80211_WEP_OFF:
2786 LINE_CHECK("privacy OFF");
2787 break;
2788 case IEEE80211_WEP_ON:
2789 LINE_CHECK("privacy ON");
2790 break;
2791 case IEEE80211_WEP_MIXED:
2792 LINE_CHECK("privacy MIXED");
2793 break;
2794 default:
2795 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
2796 break;
2282 }
2283
2284 /*
2285 * If we get here then we've got WEP support so we need
2286 * to print WEP status.
2287 */
2288
2797 }
2798
2799 /*
2800 * If we get here then we've got WEP support so we need
2801 * to print WEP status.
2802 */
2803
2289 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
2290 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2804 if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) {
2291 warn("WEP support, but no tx key!");
2292 goto end;
2293 }
2805 warn("WEP support, but no tx key!");
2806 goto end;
2807 }
2294 if (ireq.i_val != -1)
2295 LINE_CHECK("deftxkey %d", ireq.i_val+1);
2808 if (val != -1)
2809 LINE_CHECK("deftxkey %d", val+1);
2296 else if (wepmode != IEEE80211_WEP_OFF || verbose)
2297 LINE_CHECK("deftxkey UNDEF");
2298
2810 else if (wepmode != IEEE80211_WEP_OFF || verbose)
2811 LINE_CHECK("deftxkey UNDEF");
2812
2299 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
2300 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2813 if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) {
2301 warn("WEP support, but no NUMWEPKEYS support!");
2302 goto end;
2303 }
2814 warn("WEP support, but no NUMWEPKEYS support!");
2815 goto end;
2816 }
2304 num = ireq.i_val;
2305
2306 firstkey = 1;
2307 for (i = 0; i < num; i++) {
2308 struct ieee80211req_key ik;
2309
2310 memset(&ik, 0, sizeof(ik));
2311 ik.ik_keyix = i;
2817
2818 firstkey = 1;
2819 for (i = 0; i < num; i++) {
2820 struct ieee80211req_key ik;
2821
2822 memset(&ik, 0, sizeof(ik));
2823 ik.ik_keyix = i;
2312 ireq.i_type = IEEE80211_IOC_WPAKEY;
2313 ireq.i_data = &ik;
2314 ireq.i_len = sizeof(ik);
2315 if (ioctl(s, SIOCG80211, &ireq) < 0) {
2824 if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) {
2316 warn("WEP support, but can get keys!");
2317 goto end;
2318 }
2319 if (ik.ik_keylen != 0) {
2320 if (verbose)
2321 LINE_BREAK();
2322 printkey(&ik);
2323 firstkey = 0;
2324 }
2325 }
2825 warn("WEP support, but can get keys!");
2826 goto end;
2827 }
2828 if (ik.ik_keylen != 0) {
2829 if (verbose)
2830 LINE_BREAK();
2831 printkey(&ik);
2832 firstkey = 0;
2833 }
2834 }
2326 ireq.i_data = &data; /* reset data buffer */
2835end:
2836 ;
2327 }
2328
2837 }
2838
2329 ireq.i_type = IEEE80211_IOC_POWERSAVE;
2330 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
2331 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
2332 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
2333 switch (ireq.i_val) {
2334 case IEEE80211_POWERSAVE_OFF:
2335 LINE_CHECK("powersavemode OFF");
2336 break;
2337 case IEEE80211_POWERSAVE_CAM:
2338 LINE_CHECK("powersavemode CAM");
2339 break;
2340 case IEEE80211_POWERSAVE_PSP:
2341 LINE_CHECK("powersavemode PSP");
2342 break;
2343 case IEEE80211_POWERSAVE_PSP_CAM:
2344 LINE_CHECK("powersavemode PSP-CAM");
2345 break;
2839 if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 &&
2840 val != IEEE80211_POWERSAVE_NOSUP ) {
2841 if (val != IEEE80211_POWERSAVE_OFF || verbose) {
2842 switch (val) {
2843 case IEEE80211_POWERSAVE_OFF:
2844 LINE_CHECK("powersavemode OFF");
2845 break;
2846 case IEEE80211_POWERSAVE_CAM:
2847 LINE_CHECK("powersavemode CAM");
2848 break;
2849 case IEEE80211_POWERSAVE_PSP:
2850 LINE_CHECK("powersavemode PSP");
2851 break;
2852 case IEEE80211_POWERSAVE_PSP_CAM:
2853 LINE_CHECK("powersavemode PSP-CAM");
2854 break;
2346 }
2855 }
2347 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
2348 if (ioctl(s, SIOCG80211, &ireq) != -1)
2349 LINE_CHECK("powersavesleep %d", ireq.i_val);
2856 if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1)
2857 LINE_CHECK("powersavesleep %d", val);
2350 }
2351 }
2352
2858 }
2859 }
2860
2353 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
2354 if (ioctl(s, SIOCG80211, &ireq) != -1)
2355 LINE_CHECK("txpowmax %d", ireq.i_val);
2356
2861 if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) {
2862 if (val & 1)
2863 LINE_CHECK("txpower %d.5", val/2);
2864 else
2865 LINE_CHECK("txpower %d", val/2);
2866 }
2357 if (verbose) {
2867 if (verbose) {
2358 ireq.i_type = IEEE80211_IOC_TXPOWER;
2359 if (ioctl(s, SIOCG80211, &ireq) != -1)
2360 LINE_CHECK("txpower %d", ireq.i_val);
2868 if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1)
2869 LINE_CHECK("txpowmax %.1f", val/2.);
2361 }
2362
2870 }
2871
2363 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
2364 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2365 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
2366 LINE_CHECK("rtsthreshold %d", ireq.i_val);
2872 if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) {
2873 if (val != IEEE80211_RTS_MAX || verbose)
2874 LINE_CHECK("rtsthreshold %d", val);
2367 }
2368
2875 }
2876
2369 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
2370 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2371 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
2372 LINE_CHECK("fragthreshold %d", ireq.i_val);
2877 if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) {
2878 if (val != IEEE80211_FRAG_MAX || verbose)
2879 LINE_CHECK("fragthreshold %d", val);
2373 }
2880 }
2374 ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
2375 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2376 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
2377 LINE_CHECK("bmiss %d", ireq.i_val);
2378 }
2379
2380 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
2381 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2382 if (ireq.i_val != 2*1 || verbose) {
2383 if (ireq.i_val == 11)
2384 LINE_CHECK("mcastrate 5.5");
2385 else
2386 LINE_CHECK("mcastrate %d", ireq.i_val/2);
2881 if (opmode == IEEE80211_M_STA || verbose) {
2882 if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) {
2883 if (val != IEEE80211_HWBMISS_MAX || verbose)
2884 LINE_CHECK("bmiss %d", val);
2387 }
2388 }
2389
2885 }
2886 }
2887
2390 ireq.i_type = IEEE80211_IOC_BGSCAN_INTERVAL;
2391 if (ioctl(s, SIOCG80211, &ireq) != -1)
2392 bgscaninterval = ireq.i_val;
2393 else
2394 bgscaninterval = -1;
2888 if (get80211val(s, IEEE80211_IOC_MCAST_RATE, &val) != -1)
2889 printrate("mcastrate", val, 2*1, 0/*XXX*/);
2395
2890
2396 ireq.i_type = IEEE80211_IOC_SCANVALID;
2397 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2398 if (ireq.i_val != bgscaninterval || verbose)
2399 LINE_CHECK("scanvalid %u", ireq.i_val);
2891 bgscaninterval = -1;
2892 (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval);
2893
2894 if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) {
2895 if (val != bgscaninterval || verbose)
2896 LINE_CHECK("scanvalid %u", val);
2400 }
2401
2897 }
2898
2402 ireq.i_type = IEEE80211_IOC_BGSCAN;
2403 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2404 bgscan = ireq.i_val;
2405 if (ireq.i_val)
2899 bgscan = 0;
2900 if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) {
2901 if (bgscan)
2406 LINE_CHECK("bgscan");
2407 else if (verbose)
2408 LINE_CHECK("-bgscan");
2409 }
2410 if (bgscan || verbose) {
2411 if (bgscaninterval != -1)
2412 LINE_CHECK("bgscanintvl %u", bgscaninterval);
2902 LINE_CHECK("bgscan");
2903 else if (verbose)
2904 LINE_CHECK("-bgscan");
2905 }
2906 if (bgscan || verbose) {
2907 if (bgscaninterval != -1)
2908 LINE_CHECK("bgscanintvl %u", bgscaninterval);
2413 ireq.i_type = IEEE80211_IOC_BGSCAN_IDLE;
2414 if (ioctl(s, SIOCG80211, &ireq) != -1)
2415 LINE_CHECK("bgscanidle %u", ireq.i_val);
2909 if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1)
2910 LINE_CHECK("bgscanidle %u", val);
2416 if (IEEE80211_IS_CHAN_A(c) || verbose) {
2911 if (IEEE80211_IS_CHAN_A(c) || verbose) {
2417 ireq.i_type = IEEE80211_IOC_ROAM_RSSI_11A;
2418 if (ioctl(s, SIOCG80211, &ireq) != -1)
2419 LINE_CHECK("roam:rssi11a %d", ireq.i_val);
2420 ireq.i_type = IEEE80211_IOC_ROAM_RATE_11A;
2421 if (ioctl(s, SIOCG80211, &ireq) != -1)
2422 LINE_CHECK("roam:rate11a %u", ireq.i_val/2);
2912 if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11A, &val) != -1)
2913 printrssi("roam:rssi11a", val);
2914 if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11A, &val) != -1)
2915 printrate("roam:rate11a", val, -1, -1);
2423 }
2424 if (IEEE80211_IS_CHAN_B(c) || verbose) {
2916 }
2917 if (IEEE80211_IS_CHAN_B(c) || verbose) {
2425 ireq.i_type = IEEE80211_IOC_ROAM_RSSI_11B;
2426 if (ioctl(s, SIOCG80211, &ireq) != -1)
2427 LINE_CHECK("roam:rssi11b %d", ireq.i_val);
2428 ireq.i_type = IEEE80211_IOC_ROAM_RATE_11B;
2429 if (ioctl(s, SIOCG80211, &ireq) != -1)
2430 LINE_CHECK("roam:rate11b %u", ireq.i_val/2);
2918 if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11B, &val) != -1)
2919 printrssi("roam:rssi11b", val);
2920 if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11B, &val) != -1)
2921 printrate("roam:rate11b", val, -1, -1);
2431 }
2432 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
2922 }
2923 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
2433 ireq.i_type = IEEE80211_IOC_ROAM_RSSI_11G;
2434 if (ioctl(s, SIOCG80211, &ireq) != -1)
2435 LINE_CHECK("roam:rssi11g %d", ireq.i_val);
2436 ireq.i_type = IEEE80211_IOC_ROAM_RATE_11G;
2437 if (ioctl(s, SIOCG80211, &ireq) != -1)
2438 LINE_CHECK("roam:rate11g %u", ireq.i_val/2);
2924 if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11G, &val) != -1)
2925 printrssi("roam:rssi11g", val);
2926 if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11G, &val) != -1)
2927 printrate("roam:rate11g", val, -1, -1);
2439 }
2440 }
2441
2442 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
2928 }
2929 }
2930
2931 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
2443 ireq.i_type = IEEE80211_IOC_PUREG;
2444 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2445 if (ireq.i_val)
2932 if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) {
2933 if (val)
2446 LINE_CHECK("pureg");
2447 else if (verbose)
2448 LINE_CHECK("-pureg");
2449 }
2934 LINE_CHECK("pureg");
2935 else if (verbose)
2936 LINE_CHECK("-pureg");
2937 }
2450 ireq.i_type = IEEE80211_IOC_PROTMODE;
2451 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2452 switch (ireq.i_val) {
2453 case IEEE80211_PROTMODE_OFF:
2454 LINE_CHECK("protmode OFF");
2455 break;
2456 case IEEE80211_PROTMODE_CTS:
2457 LINE_CHECK("protmode CTS");
2458 break;
2459 case IEEE80211_PROTMODE_RTSCTS:
2460 LINE_CHECK("protmode RTSCTS");
2461 break;
2462 default:
2463 LINE_CHECK("protmode UNKNOWN (0x%x)",
2464 ireq.i_val);
2465 break;
2938 if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) {
2939 switch (val) {
2940 case IEEE80211_PROTMODE_OFF:
2941 LINE_CHECK("protmode OFF");
2942 break;
2943 case IEEE80211_PROTMODE_CTS:
2944 LINE_CHECK("protmode CTS");
2945 break;
2946 case IEEE80211_PROTMODE_RTSCTS:
2947 LINE_CHECK("protmode RTSCTS");
2948 break;
2949 default:
2950 LINE_CHECK("protmode UNKNOWN (0x%x)", val);
2951 break;
2466 }
2467 }
2468 }
2469
2952 }
2953 }
2954 }
2955
2470 ireq.i_type = IEEE80211_IOC_WME;
2471 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2472 wme = ireq.i_val;
2956 if (IEEE80211_IS_CHAN_HT(c) || verbose) {
2957 gethtconf(s);
2958 switch (htconf & 3) {
2959 case 0:
2960 case 2:
2961 LINE_CHECK("-ht");
2962 break;
2963 case 1:
2964 LINE_CHECK("ht20");
2965 break;
2966 case 3:
2967 if (verbose)
2968 LINE_CHECK("ht");
2969 break;
2970 }
2971 if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) {
2972 if (!val)
2973 LINE_CHECK("-htcompat");
2974 else if (verbose)
2975 LINE_CHECK("htcompat");
2976 }
2977 if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) {
2978 switch (val) {
2979 case 0:
2980 LINE_CHECK("-ampdu");
2981 break;
2982 case 1:
2983 LINE_CHECK("ampdutx -ampdurx");
2984 break;
2985 case 2:
2986 LINE_CHECK("-ampdutx ampdurx");
2987 break;
2988 case 3:
2989 if (verbose)
2990 LINE_CHECK("ampdu");
2991 break;
2992 }
2993 }
2994 if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) {
2995 switch (val) {
2996 case IEEE80211_HTCAP_MAXRXAMPDU_8K:
2997 LINE_CHECK("ampdulimit 8k");
2998 break;
2999 case IEEE80211_HTCAP_MAXRXAMPDU_16K:
3000 LINE_CHECK("ampdulimit 16k");
3001 break;
3002 case IEEE80211_HTCAP_MAXRXAMPDU_32K:
3003 LINE_CHECK("ampdulimit 32k");
3004 break;
3005 case IEEE80211_HTCAP_MAXRXAMPDU_64K:
3006 LINE_CHECK("ampdulimit 64k");
3007 break;
3008 }
3009 }
3010 if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) {
3011 switch (val) {
3012 case IEEE80211_HTCAP_MPDUDENSITY_NA:
3013 if (verbose)
3014 LINE_CHECK("ampdudensity -");
3015 break;
3016 case IEEE80211_HTCAP_MPDUDENSITY_025:
3017 LINE_CHECK("ampdudensity .25");
3018 break;
3019 case IEEE80211_HTCAP_MPDUDENSITY_05:
3020 LINE_CHECK("ampdudensity .5");
3021 break;
3022 case IEEE80211_HTCAP_MPDUDENSITY_1:
3023 LINE_CHECK("ampdudensity 1");
3024 break;
3025 case IEEE80211_HTCAP_MPDUDENSITY_2:
3026 LINE_CHECK("ampdudensity 2");
3027 break;
3028 case IEEE80211_HTCAP_MPDUDENSITY_4:
3029 LINE_CHECK("ampdudensity 4");
3030 break;
3031 case IEEE80211_HTCAP_MPDUDENSITY_8:
3032 LINE_CHECK("ampdudensity 8");
3033 break;
3034 case IEEE80211_HTCAP_MPDUDENSITY_16:
3035 LINE_CHECK("ampdudensity 16");
3036 break;
3037 }
3038 }
3039 if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) {
3040 switch (val) {
3041 case 0:
3042 LINE_CHECK("-amsdu");
3043 break;
3044 case 1:
3045 LINE_CHECK("amsdutx -amsdurx");
3046 break;
3047 case 2:
3048 LINE_CHECK("-amsdutx amsdurx");
3049 break;
3050 case 3:
3051 if (verbose)
3052 LINE_CHECK("amsdu");
3053 break;
3054 }
3055 }
3056 /* XXX amsdu limit */
3057 /* XXX 20/40 */
3058 if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) {
3059 if (val)
3060 LINE_CHECK("shortgi");
3061 else if (verbose)
3062 LINE_CHECK("-shortgi");
3063 }
3064 if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) {
3065 if (val == IEEE80211_PROTMODE_OFF)
3066 LINE_CHECK("htprotmode OFF");
3067 else if (val != IEEE80211_PROTMODE_RTSCTS)
3068 LINE_CHECK("htprotmode UNKNOWN (0x%x)", val);
3069 else if (verbose)
3070 LINE_CHECK("htprotmode RTSCTS");
3071 }
3072 if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) {
3073 if (val)
3074 LINE_CHECK("puren");
3075 else if (verbose)
3076 LINE_CHECK("-puren");
3077 }
3078 }
3079
3080 if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) {
2473 if (wme)
2474 LINE_CHECK("wme");
2475 else if (verbose)
2476 LINE_CHECK("-wme");
2477 } else
2478 wme = 0;
2479
3081 if (wme)
3082 LINE_CHECK("wme");
3083 else if (verbose)
3084 LINE_CHECK("-wme");
3085 } else
3086 wme = 0;
3087
2480 ireq.i_type = IEEE80211_IOC_BURST;
2481 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2482 if (ireq.i_val)
3088 if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) {
3089 if (val)
2483 LINE_CHECK("burst");
2484 else if (verbose)
2485 LINE_CHECK("-burst");
2486 }
2487
3090 LINE_CHECK("burst");
3091 else if (verbose)
3092 LINE_CHECK("-burst");
3093 }
3094
2488 ireq.i_type = IEEE80211_IOC_FF;
2489 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2490 if (ireq.i_val)
3095 if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) {
3096 if (val)
2491 LINE_CHECK("ff");
2492 else if (verbose)
2493 LINE_CHECK("-ff");
2494 }
3097 LINE_CHECK("ff");
3098 else if (verbose)
3099 LINE_CHECK("-ff");
3100 }
2495 ireq.i_type = IEEE80211_IOC_TURBOP;
2496 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2497 if (ireq.i_val)
3101 if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) {
3102 if (val)
2498 LINE_CHECK("dturbo");
2499 else if (verbose)
2500 LINE_CHECK("-dturbo");
2501 }
2502
2503 if (opmode == IEEE80211_M_HOSTAP) {
3103 LINE_CHECK("dturbo");
3104 else if (verbose)
3105 LINE_CHECK("-dturbo");
3106 }
3107
3108 if (opmode == IEEE80211_M_HOSTAP) {
2504 ireq.i_type = IEEE80211_IOC_HIDESSID;
2505 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2506 if (ireq.i_val)
3109 if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) {
3110 if (val)
2507 LINE_CHECK("hidessid");
2508 else if (verbose)
2509 LINE_CHECK("-hidessid");
2510 }
3111 LINE_CHECK("hidessid");
3112 else if (verbose)
3113 LINE_CHECK("-hidessid");
3114 }
2511
2512 ireq.i_type = IEEE80211_IOC_APBRIDGE;
2513 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2514 if (!ireq.i_val)
3115 if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) {
3116 if (!val)
2515 LINE_CHECK("-apbridge");
2516 else if (verbose)
2517 LINE_CHECK("apbridge");
2518 }
3117 LINE_CHECK("-apbridge");
3118 else if (verbose)
3119 LINE_CHECK("apbridge");
3120 }
3121 if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1)
3122 LINE_CHECK("dtimperiod %u", val);
2519
3123
2520 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
2521 if (ioctl(s, SIOCG80211, &ireq) != -1)
2522 LINE_CHECK("dtimperiod %u", ireq.i_val);
2523
2524 ireq.i_type = IEEE80211_IOC_DOTH;
2525 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2526 if (!ireq.i_val)
3124 if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) {
3125 if (!val)
2527 LINE_CHECK("-doth");
2528 else if (verbose)
2529 LINE_CHECK("doth");
2530 }
3126 LINE_CHECK("-doth");
3127 else if (verbose)
3128 LINE_CHECK("doth");
3129 }
3130 if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) {
3131 if (!val)
3132 LINE_CHECK("-inact");
3133 else if (verbose)
3134 LINE_CHECK("inact");
3135 }
2531 } else {
3136 } else {
2532 ireq.i_type = IEEE80211_IOC_ROAMING;
2533 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2534 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
2535 switch (ireq.i_val) {
3137 if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) {
3138 if (val != IEEE80211_ROAMING_AUTO || verbose) {
3139 switch (val) {
2536 case IEEE80211_ROAMING_DEVICE:
2537 LINE_CHECK("roaming DEVICE");
2538 break;
2539 case IEEE80211_ROAMING_AUTO:
2540 LINE_CHECK("roaming AUTO");
2541 break;
2542 case IEEE80211_ROAMING_MANUAL:
2543 LINE_CHECK("roaming MANUAL");
2544 break;
2545 default:
2546 LINE_CHECK("roaming UNKNOWN (0x%x)",
3140 case IEEE80211_ROAMING_DEVICE:
3141 LINE_CHECK("roaming DEVICE");
3142 break;
3143 case IEEE80211_ROAMING_AUTO:
3144 LINE_CHECK("roaming AUTO");
3145 break;
3146 case IEEE80211_ROAMING_MANUAL:
3147 LINE_CHECK("roaming MANUAL");
3148 break;
3149 default:
3150 LINE_CHECK("roaming UNKNOWN (0x%x)",
2547 ireq.i_val);
3151 val);
2548 break;
2549 }
2550 }
2551 }
2552 }
3152 break;
3153 }
3154 }
3155 }
3156 }
2553 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
2554 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2555 if (ireq.i_val)
2556 LINE_CHECK("bintval %u", ireq.i_val);
2557 else if (verbose)
2558 LINE_CHECK("bintval %u", ireq.i_val);
3157 if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
3158 /* XXX default define not visible */
3159 if (val != 100 || verbose)
3160 LINE_CHECK("bintval %u", val);
2559 }
2560
2561 if (wme && verbose) {
2562 LINE_BREAK();
2563 list_wme(s);
2564 }
3161 }
3162
3163 if (wme && verbose) {
3164 LINE_BREAK();
3165 list_wme(s);
3166 }
3167 LINE_BREAK();
3168}
2565
3169
2566 if (wpa) {
2567 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
2568 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2569 if (ireq.i_val)
2570 LINE_CHECK("countermeasures");
2571 else if (verbose)
2572 LINE_CHECK("-countermeasures");
2573 }
2574#if 0
2575 /* XXX not interesting with WPA done in user space */
2576 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
2577 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2578 }
3170static int
3171get80211(int s, int type, void *data, int len)
3172{
3173 struct ieee80211req ireq;
2579
3174
2580 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
2581 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2582 LINE_CHECK("mcastcipher ");
2583 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
2584 spacer = ' ';
2585 }
3175 (void) memset(&ireq, 0, sizeof(ireq));
3176 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
3177 ireq.i_type = type;
3178 ireq.i_data = data;
3179 ireq.i_len = len;
3180 return ioctl(s, SIOCG80211, &ireq);
3181}
2586
3182
2587 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
2588 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2589 LINE_CHECK("ucastcipher ");
2590 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
2591 }
3183static int
3184get80211len(int s, int type, void *data, int len, int *plen)
3185{
3186 struct ieee80211req ireq;
2592
3187
2593 if (wpa & 2) {
2594 ireq.i_type = IEEE80211_IOC_RSNCAPS;
2595 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2596 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
2597 spacer = ' ';
2598 }
2599 }
3188 (void) memset(&ireq, 0, sizeof(ireq));
3189 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
3190 ireq.i_type = type;
3191 ireq.i_len = len;
3192 ireq.i_data = data;
3193 if (ioctl(s, SIOCG80211, &ireq) < 0)
3194 return -1;
3195 *plen = ireq.i_len;
3196 return 0;
3197}
2600
3198
2601 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
2602 if (ioctl(s, SIOCG80211, &ireq) != -1) {
2603 }
2604#endif
2605 LINE_BREAK();
2606 }
2607 LINE_BREAK();
3199static int
3200get80211val(int s, int type, int *val)
3201{
3202 struct ieee80211req ireq;
2608
3203
2609end:
2610 return;
3204 (void) memset(&ireq, 0, sizeof(ireq));
3205 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
3206 ireq.i_type = type;
3207 if (ioctl(s, SIOCG80211, &ireq) < 0)
3208 return -1;
3209 *val = ireq.i_val;
3210 return 0;
2611}
2612
2613static void
2614set80211(int s, int type, int val, int len, void *data)
2615{
2616 struct ieee80211req ireq;
2617
2618 (void) memset(&ireq, 0, sizeof(ireq));
2619 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
2620 ireq.i_type = type;
2621 ireq.i_val = val;
2622 ireq.i_len = len;
2623 ireq.i_data = data;
2624 if (ioctl(s, SIOCS80211, &ireq) < 0)
2625 err(1, "SIOCS80211");
2626}
2627
2628static const char *
2629get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
2630{
2631 int len;
2632 int hexstr;
2633 u_int8_t *p;
2634
2635 len = *lenp;
2636 p = buf;
2637 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
2638 if (hexstr)
2639 val += 2;
2640 for (;;) {
2641 if (*val == '\0')
2642 break;
2643 if (sep != NULL && strchr(sep, *val) != NULL) {
2644 val++;
2645 break;
2646 }
2647 if (hexstr) {
2648 if (!isxdigit((u_char)val[0])) {
2649 warnx("bad hexadecimal digits");
2650 return NULL;
2651 }
2652 if (!isxdigit((u_char)val[1])) {
2653 warnx("odd count hexadecimal digits");
2654 return NULL;
2655 }
2656 }
2657 if (p >= buf + len) {
2658 if (hexstr)
2659 warnx("hexadecimal digits too long");
2660 else
2661 warnx("string too long");
2662 return NULL;
2663 }
2664 if (hexstr) {
2665#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
2666 *p++ = (tohex((u_char)val[0]) << 4) |
2667 tohex((u_char)val[1]);
2668#undef tohex
2669 val += 2;
2670 } else
2671 *p++ = *val++;
2672 }
2673 len = p - buf;
2674 /* The string "-" is treated as the empty string. */
2675 if (!hexstr && len == 1 && buf[0] == '-') {
2676 len = 0;
2677 memset(buf, 0, *lenp);
2678 } else if (len < *lenp)
2679 memset(p, 0, *lenp - len);
2680 *lenp = len;
2681 return val;
2682}
2683
2684static void
2685print_string(const u_int8_t *buf, int len)
2686{
2687 int i;
2688 int hasspc;
2689
2690 i = 0;
2691 hasspc = 0;
2692 for (; i < len; i++) {
2693 if (!isprint(buf[i]) && buf[i] != '\0')
2694 break;
2695 if (isspace(buf[i]))
2696 hasspc++;
2697 }
2698 if (i == len) {
2699 if (hasspc || len == 0 || buf[0] == '\0')
2700 printf("\"%.*s\"", len, buf);
2701 else
2702 printf("%.*s", len, buf);
2703 } else {
2704 printf("0x");
2705 for (i = 0; i < len; i++)
2706 printf("%02x", buf[i]);
2707 }
2708}
2709
2710static struct cmd ieee80211_cmds[] = {
2711 DEF_CMD_ARG("ssid", set80211ssid),
2712 DEF_CMD_ARG("nwid", set80211ssid),
2713 DEF_CMD_ARG("stationname", set80211stationname),
2714 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
2715 DEF_CMD_ARG("channel", set80211channel),
2716 DEF_CMD_ARG("authmode", set80211authmode),
2717 DEF_CMD_ARG("powersavemode", set80211powersavemode),
2718 DEF_CMD("powersave", 1, set80211powersave),
2719 DEF_CMD("-powersave", 0, set80211powersave),
2720 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
2721 DEF_CMD_ARG("wepmode", set80211wepmode),
2722 DEF_CMD("wep", 1, set80211wep),
2723 DEF_CMD("-wep", 0, set80211wep),
2724 DEF_CMD_ARG("deftxkey", set80211weptxkey),
2725 DEF_CMD_ARG("weptxkey", set80211weptxkey),
2726 DEF_CMD_ARG("wepkey", set80211wepkey),
2727 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
2728 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
2729 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
2730 DEF_CMD_ARG("protmode", set80211protmode),
2731 DEF_CMD_ARG("txpower", set80211txpower),
2732 DEF_CMD_ARG("roaming", set80211roaming),
2733 DEF_CMD("wme", 1, set80211wme),
2734 DEF_CMD("-wme", 0, set80211wme),
2735 DEF_CMD("hidessid", 1, set80211hidessid),
2736 DEF_CMD("-hidessid", 0, set80211hidessid),
2737 DEF_CMD("apbridge", 1, set80211apbridge),
2738 DEF_CMD("-apbridge", 0, set80211apbridge),
2739 DEF_CMD_ARG("chanlist", set80211chanlist),
2740 DEF_CMD_ARG("bssid", set80211bssid),
2741 DEF_CMD_ARG("ap", set80211bssid),
2742 DEF_CMD("scan", 0, set80211scan),
2743 DEF_CMD_ARG("list", set80211list),
2744 DEF_CMD_ARG2("cwmin", set80211cwmin),
2745 DEF_CMD_ARG2("cwmax", set80211cwmax),
2746 DEF_CMD_ARG2("aifs", set80211aifs),
2747 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
2748 DEF_CMD_ARG("acm", set80211acm),
2749 DEF_CMD_ARG("-acm", set80211noacm),
2750 DEF_CMD_ARG("ack", set80211ackpolicy),
2751 DEF_CMD_ARG("-ack", set80211noackpolicy),
2752 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
2753 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
2754 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
2755 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
2756 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
2757 DEF_CMD_ARG("bintval", set80211bintval),
2758 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
2759 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
2760 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
2761 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
2762 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
2763 DEF_CMD_ARG("mac:add", set80211addmac),
2764 DEF_CMD_ARG("mac:del", set80211delmac),
2765 DEF_CMD_ARG("mac:kick", set80211kickmac),
2766 DEF_CMD("pureg", 1, set80211pureg),
2767 DEF_CMD("-pureg", 0, set80211pureg),
2768 DEF_CMD("ff", 1, set80211fastframes),
2769 DEF_CMD("-ff", 0, set80211fastframes),
2770 DEF_CMD("dturbo", 1, set80211dturbo),
2771 DEF_CMD("-dturbo", 0, set80211dturbo),
2772 DEF_CMD("bgscan", 1, set80211bgscan),
2773 DEF_CMD("-bgscan", 0, set80211bgscan),
2774 DEF_CMD_ARG("bgscanidle", set80211bgscanidle),
2775 DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl),
2776 DEF_CMD_ARG("scanvalid", set80211scanvalid),
2777 DEF_CMD_ARG("roam:rssi11a", set80211roamrssi11a),
2778 DEF_CMD_ARG("roam:rssi11b", set80211roamrssi11b),
2779 DEF_CMD_ARG("roam:rssi11g", set80211roamrssi11g),
2780 DEF_CMD_ARG("roam:rate11a", set80211roamrate11a),
2781 DEF_CMD_ARG("roam:rate11b", set80211roamrate11b),
2782 DEF_CMD_ARG("roam:rate11g", set80211roamrate11g),
2783 DEF_CMD_ARG("mcastrate", set80211mcastrate),
2784 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
2785 DEF_CMD("burst", 1, set80211burst),
2786 DEF_CMD("-burst", 0, set80211burst),
2787 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
2788 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold),
3211}
3212
3213static void
3214set80211(int s, int type, int val, int len, void *data)
3215{
3216 struct ieee80211req ireq;
3217
3218 (void) memset(&ireq, 0, sizeof(ireq));
3219 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
3220 ireq.i_type = type;
3221 ireq.i_val = val;
3222 ireq.i_len = len;
3223 ireq.i_data = data;
3224 if (ioctl(s, SIOCS80211, &ireq) < 0)
3225 err(1, "SIOCS80211");
3226}
3227
3228static const char *
3229get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
3230{
3231 int len;
3232 int hexstr;
3233 u_int8_t *p;
3234
3235 len = *lenp;
3236 p = buf;
3237 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
3238 if (hexstr)
3239 val += 2;
3240 for (;;) {
3241 if (*val == '\0')
3242 break;
3243 if (sep != NULL && strchr(sep, *val) != NULL) {
3244 val++;
3245 break;
3246 }
3247 if (hexstr) {
3248 if (!isxdigit((u_char)val[0])) {
3249 warnx("bad hexadecimal digits");
3250 return NULL;
3251 }
3252 if (!isxdigit((u_char)val[1])) {
3253 warnx("odd count hexadecimal digits");
3254 return NULL;
3255 }
3256 }
3257 if (p >= buf + len) {
3258 if (hexstr)
3259 warnx("hexadecimal digits too long");
3260 else
3261 warnx("string too long");
3262 return NULL;
3263 }
3264 if (hexstr) {
3265#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
3266 *p++ = (tohex((u_char)val[0]) << 4) |
3267 tohex((u_char)val[1]);
3268#undef tohex
3269 val += 2;
3270 } else
3271 *p++ = *val++;
3272 }
3273 len = p - buf;
3274 /* The string "-" is treated as the empty string. */
3275 if (!hexstr && len == 1 && buf[0] == '-') {
3276 len = 0;
3277 memset(buf, 0, *lenp);
3278 } else if (len < *lenp)
3279 memset(p, 0, *lenp - len);
3280 *lenp = len;
3281 return val;
3282}
3283
3284static void
3285print_string(const u_int8_t *buf, int len)
3286{
3287 int i;
3288 int hasspc;
3289
3290 i = 0;
3291 hasspc = 0;
3292 for (; i < len; i++) {
3293 if (!isprint(buf[i]) && buf[i] != '\0')
3294 break;
3295 if (isspace(buf[i]))
3296 hasspc++;
3297 }
3298 if (i == len) {
3299 if (hasspc || len == 0 || buf[0] == '\0')
3300 printf("\"%.*s\"", len, buf);
3301 else
3302 printf("%.*s", len, buf);
3303 } else {
3304 printf("0x");
3305 for (i = 0; i < len; i++)
3306 printf("%02x", buf[i]);
3307 }
3308}
3309
3310static struct cmd ieee80211_cmds[] = {
3311 DEF_CMD_ARG("ssid", set80211ssid),
3312 DEF_CMD_ARG("nwid", set80211ssid),
3313 DEF_CMD_ARG("stationname", set80211stationname),
3314 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
3315 DEF_CMD_ARG("channel", set80211channel),
3316 DEF_CMD_ARG("authmode", set80211authmode),
3317 DEF_CMD_ARG("powersavemode", set80211powersavemode),
3318 DEF_CMD("powersave", 1, set80211powersave),
3319 DEF_CMD("-powersave", 0, set80211powersave),
3320 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
3321 DEF_CMD_ARG("wepmode", set80211wepmode),
3322 DEF_CMD("wep", 1, set80211wep),
3323 DEF_CMD("-wep", 0, set80211wep),
3324 DEF_CMD_ARG("deftxkey", set80211weptxkey),
3325 DEF_CMD_ARG("weptxkey", set80211weptxkey),
3326 DEF_CMD_ARG("wepkey", set80211wepkey),
3327 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
3328 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
3329 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
3330 DEF_CMD_ARG("protmode", set80211protmode),
3331 DEF_CMD_ARG("txpower", set80211txpower),
3332 DEF_CMD_ARG("roaming", set80211roaming),
3333 DEF_CMD("wme", 1, set80211wme),
3334 DEF_CMD("-wme", 0, set80211wme),
3335 DEF_CMD("hidessid", 1, set80211hidessid),
3336 DEF_CMD("-hidessid", 0, set80211hidessid),
3337 DEF_CMD("apbridge", 1, set80211apbridge),
3338 DEF_CMD("-apbridge", 0, set80211apbridge),
3339 DEF_CMD_ARG("chanlist", set80211chanlist),
3340 DEF_CMD_ARG("bssid", set80211bssid),
3341 DEF_CMD_ARG("ap", set80211bssid),
3342 DEF_CMD("scan", 0, set80211scan),
3343 DEF_CMD_ARG("list", set80211list),
3344 DEF_CMD_ARG2("cwmin", set80211cwmin),
3345 DEF_CMD_ARG2("cwmax", set80211cwmax),
3346 DEF_CMD_ARG2("aifs", set80211aifs),
3347 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
3348 DEF_CMD_ARG("acm", set80211acm),
3349 DEF_CMD_ARG("-acm", set80211noacm),
3350 DEF_CMD_ARG("ack", set80211ackpolicy),
3351 DEF_CMD_ARG("-ack", set80211noackpolicy),
3352 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
3353 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
3354 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
3355 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
3356 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
3357 DEF_CMD_ARG("bintval", set80211bintval),
3358 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
3359 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
3360 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
3361 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
3362 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
3363 DEF_CMD_ARG("mac:add", set80211addmac),
3364 DEF_CMD_ARG("mac:del", set80211delmac),
3365 DEF_CMD_ARG("mac:kick", set80211kickmac),
3366 DEF_CMD("pureg", 1, set80211pureg),
3367 DEF_CMD("-pureg", 0, set80211pureg),
3368 DEF_CMD("ff", 1, set80211fastframes),
3369 DEF_CMD("-ff", 0, set80211fastframes),
3370 DEF_CMD("dturbo", 1, set80211dturbo),
3371 DEF_CMD("-dturbo", 0, set80211dturbo),
3372 DEF_CMD("bgscan", 1, set80211bgscan),
3373 DEF_CMD("-bgscan", 0, set80211bgscan),
3374 DEF_CMD_ARG("bgscanidle", set80211bgscanidle),
3375 DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl),
3376 DEF_CMD_ARG("scanvalid", set80211scanvalid),
3377 DEF_CMD_ARG("roam:rssi11a", set80211roamrssi11a),
3378 DEF_CMD_ARG("roam:rssi11b", set80211roamrssi11b),
3379 DEF_CMD_ARG("roam:rssi11g", set80211roamrssi11g),
3380 DEF_CMD_ARG("roam:rate11a", set80211roamrate11a),
3381 DEF_CMD_ARG("roam:rate11b", set80211roamrate11b),
3382 DEF_CMD_ARG("roam:rate11g", set80211roamrate11g),
3383 DEF_CMD_ARG("mcastrate", set80211mcastrate),
3384 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
3385 DEF_CMD("burst", 1, set80211burst),
3386 DEF_CMD("-burst", 0, set80211burst),
3387 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
3388 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold),
3389 DEF_CMD("shortgi", 1, set80211shortgi),
3390 DEF_CMD("-shortgi", 0, set80211shortgi),
3391 DEF_CMD("ampdurx", 2, set80211ampdu),
3392 DEF_CMD("-ampdurx", -2, set80211ampdu),
3393 DEF_CMD("ampdutx", 1, set80211ampdu),
3394 DEF_CMD("-ampdutx", -1, set80211ampdu),
3395 DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */
3396 DEF_CMD("-ampdu", -3, set80211ampdu),
3397 DEF_CMD_ARG("ampdulimit", set80211ampdulimit),
3398 DEF_CMD_ARG("ampdudensity", set80211ampdudensity),
3399 DEF_CMD("amsdurx", 2, set80211amsdu),
3400 DEF_CMD("-amsdurx", -2, set80211amsdu),
3401 DEF_CMD("amsdutx", 1, set80211amsdu),
3402 DEF_CMD("-amsdutx", -1, set80211amsdu),
3403 DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */
3404 DEF_CMD("-amsdu", -3, set80211amsdu),
3405 DEF_CMD_ARG("amsdulimit", set80211amsdulimit),
3406 DEF_CMD("puren", 1, set80211puren),
3407 DEF_CMD("-puren", 0, set80211puren),
2789 DEF_CMD("doth", 1, set80211doth),
2790 DEF_CMD("-doth", 0, set80211doth),
3408 DEF_CMD("doth", 1, set80211doth),
3409 DEF_CMD("-doth", 0, set80211doth),
3410 DEF_CMD("htcompat", 1, set80211htcompat),
3411 DEF_CMD("-htcompat", 0, set80211htcompat),
3412 DEF_CMD("inact", 1, set80211inact),
3413 DEF_CMD("-inact", 0, set80211inact),
3414 DEF_CMD_ARG("htprotmode", set80211htprotmode),
3415 DEF_CMD("ht20", 1, set80211htconf),
3416 DEF_CMD("-ht20", 0, set80211htconf),
3417 DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */
3418 DEF_CMD("-ht40", 0, set80211htconf),
3419 DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */
3420 DEF_CMD("-ht", 0, set80211htconf),
2791};
2792static struct afswtch af_ieee80211 = {
2793 .af_name = "af_ieee80211",
2794 .af_af = AF_UNSPEC,
2795 .af_other_status = ieee80211_status,
2796};
2797
2798static __constructor void
2799ieee80211_ctor(void)
2800{
2801#define N(a) (sizeof(a) / sizeof(a[0]))
2802 int i;
2803
2804 for (i = 0; i < N(ieee80211_cmds); i++)
2805 cmd_register(&ieee80211_cmds[i]);
2806 af_register(&af_ieee80211);
2807#undef N
2808}
3421};
3422static struct afswtch af_ieee80211 = {
3423 .af_name = "af_ieee80211",
3424 .af_af = AF_UNSPEC,
3425 .af_other_status = ieee80211_status,
3426};
3427
3428static __constructor void
3429ieee80211_ctor(void)
3430{
3431#define N(a) (sizeof(a) / sizeof(a[0]))
3432 int i;
3433
3434 for (i = 0; i < N(ieee80211_cmds); i++)
3435 cmd_register(&ieee80211_cmds[i]);
3436 af_register(&af_ieee80211);
3437#undef N
3438}