Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ifconfig/ifieee80211.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright 2001 The Aerospace Corporation. All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. The name of The Aerospace Corporation may not be used to endorse or
15
* promote products derived from this software.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*-
31
* Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32
* All rights reserved.
33
*
34
* This code is derived from software contributed to The NetBSD Foundation
35
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36
* NASA Ames Research Center.
37
*
38
* Redistribution and use in source and binary forms, with or without
39
* modification, are permitted provided that the following conditions
40
* are met:
41
* 1. Redistributions of source code must retain the above copyright
42
* notice, this list of conditions and the following disclaimer.
43
* 2. Redistributions in binary form must reproduce the above copyright
44
* notice, this list of conditions and the following disclaimer in the
45
* documentation and/or other materials provided with the distribution.
46
*
47
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57
* POSSIBILITY OF SUCH DAMAGE.
58
*/
59
60
#include <sys/param.h>
61
#include <sys/ioctl.h>
62
#include <sys/socket.h>
63
#include <sys/sysctl.h>
64
#include <sys/time.h>
65
66
#include <net/ethernet.h>
67
#include <net/if.h>
68
#include <net/if_dl.h>
69
#include <net/if_types.h>
70
#include <net/if_media.h>
71
#include <net/route.h>
72
73
#define WANT_NET80211 1
74
#include <net80211/ieee80211_ioctl.h>
75
#include <net80211/ieee80211_freebsd.h>
76
#include <net80211/ieee80211_superg.h>
77
#include <net80211/ieee80211_tdma.h>
78
#include <net80211/ieee80211_mesh.h>
79
#include <net80211/ieee80211_wps.h>
80
81
#include <assert.h>
82
#include <ctype.h>
83
#include <err.h>
84
#include <errno.h>
85
#include <fcntl.h>
86
#include <inttypes.h>
87
#include <stdio.h>
88
#include <stdlib.h>
89
#include <string.h>
90
#include <unistd.h>
91
#include <stdarg.h>
92
#include <stddef.h> /* NB: for offsetof */
93
#include <locale.h>
94
#include <langinfo.h>
95
96
#include "ifconfig.h"
97
98
#include <lib80211/lib80211_regdomain.h>
99
#include <lib80211/lib80211_ioctl.h>
100
101
#ifndef IEEE80211_FIXED_RATE_NONE
102
#define IEEE80211_FIXED_RATE_NONE 0xff
103
#endif
104
105
/* XXX need these publicly defined or similar */
106
#ifndef IEEE80211_NODE_AUTH
107
#define IEEE80211_NODE_AUTH 0x000001 /* authorized for data */
108
#define IEEE80211_NODE_QOS 0x000002 /* QoS enabled */
109
#define IEEE80211_NODE_ERP 0x000004 /* ERP enabled */
110
#define IEEE80211_NODE_PWR_MGT 0x000010 /* power save mode enabled */
111
#define IEEE80211_NODE_AREF 0x000020 /* authentication ref held */
112
#define IEEE80211_NODE_HT 0x000040 /* HT enabled */
113
#define IEEE80211_NODE_HTCOMPAT 0x000080 /* HT setup w/ vendor OUI's */
114
#define IEEE80211_NODE_WPS 0x000100 /* WPS association */
115
#define IEEE80211_NODE_TSN 0x000200 /* TSN association */
116
#define IEEE80211_NODE_AMPDU_RX 0x000400 /* AMPDU rx enabled */
117
#define IEEE80211_NODE_AMPDU_TX 0x000800 /* AMPDU tx enabled */
118
#define IEEE80211_NODE_MIMO_PS 0x001000 /* MIMO power save enabled */
119
#define IEEE80211_NODE_MIMO_RTS 0x002000 /* send RTS in MIMO PS */
120
#define IEEE80211_NODE_RIFS 0x004000 /* RIFS enabled */
121
#define IEEE80211_NODE_SGI20 0x008000 /* Short GI in HT20 enabled */
122
#define IEEE80211_NODE_SGI40 0x010000 /* Short GI in HT40 enabled */
123
#define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */
124
#define IEEE80211_NODE_AMSDU_RX 0x040000 /* AMSDU rx enabled */
125
#define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */
126
#define IEEE80211_NODE_VHT 0x100000 /* VHT enabled */
127
#define IEEE80211_NODE_LDPC 0x200000 /* LDPC enabled */
128
#define IEEE80211_NODE_UAPSD 0x400000 /* UAPSD enabled */
129
#endif
130
131
/* XXX should also figure out where to put these for k/u-space sharing. */
132
#ifndef IEEE80211_FVHT_VHT
133
#define IEEE80211_FVHT_VHT 0x000000001 /* CONF: VHT supported */
134
#define IEEE80211_FVHT_USEVHT40 0x000000002 /* CONF: Use VHT40 */
135
#define IEEE80211_FVHT_USEVHT80 0x000000004 /* CONF: Use VHT80 */
136
#define IEEE80211_FVHT_USEVHT80P80 0x000000008 /* CONF: Use VHT 80+80 */
137
#define IEEE80211_FVHT_USEVHT160 0x000000010 /* CONF: Use VHT160 */
138
#define IEEE80211_FVHT_STBC_TX 0x00000020 /* CONF: STBC tx enabled */
139
#define IEEE80211_FVHT_STBC_RX 0x00000040 /* CONF: STBC rx enabled */
140
#endif
141
142
/* Helper macros unified. */
143
#ifndef _IEEE80211_MASKSHIFT
144
#define _IEEE80211_MASKSHIFT(_v, _f) (((_v) & _f) >> _f##_S)
145
#endif
146
#ifndef _IEEE80211_SHIFTMASK
147
#define _IEEE80211_SHIFTMASK(_v, _f) (((_v) << _f##_S) & _f)
148
#endif
149
150
#define MAXCHAN 1536 /* max 1.5K channels */
151
152
#define MAXCOL 78
153
static int col;
154
static char spacer;
155
156
static void LINE_INIT(char c);
157
static void LINE_BREAK(void);
158
static void LINE_CHECK(const char *fmt, ...);
159
160
static const char *modename[IEEE80211_MODE_MAX] = {
161
[IEEE80211_MODE_AUTO] = "auto",
162
[IEEE80211_MODE_11A] = "11a",
163
[IEEE80211_MODE_11B] = "11b",
164
[IEEE80211_MODE_11G] = "11g",
165
[IEEE80211_MODE_FH] = "fh",
166
[IEEE80211_MODE_TURBO_A] = "turboA",
167
[IEEE80211_MODE_TURBO_G] = "turboG",
168
[IEEE80211_MODE_STURBO_A] = "sturbo",
169
[IEEE80211_MODE_11NA] = "11na",
170
[IEEE80211_MODE_11NG] = "11ng",
171
[IEEE80211_MODE_HALF] = "half",
172
[IEEE80211_MODE_QUARTER] = "quarter",
173
[IEEE80211_MODE_VHT_2GHZ] = "11acg",
174
[IEEE80211_MODE_VHT_5GHZ] = "11ac",
175
};
176
177
static void set80211(if_ctx *ctx, int type, int val, int len, void *data);
178
static int get80211(if_ctx *ctx, int type, void *data, int len);
179
static int get80211len(if_ctx *ctx, int type, void *data, int len, int *plen);
180
static int get80211val(if_ctx *ctx, int type, int *val);
181
static const char *get_string(const char *val, const char *sep,
182
u_int8_t *buf, int *lenp);
183
static void print_string(const u_int8_t *buf, int len);
184
static void print_regdomain(const struct ieee80211_regdomain *, int);
185
static void print_channels(if_ctx *, const struct ieee80211req_chaninfo *,
186
int allchans, int verbose);
187
static void regdomain_makechannels(if_ctx *, struct ieee80211_regdomain_req *,
188
const struct ieee80211_devcaps_req *);
189
static const char *mesh_linkstate_string(uint8_t state);
190
191
static struct ieee80211req_chaninfo *chaninfo;
192
static struct ieee80211_regdomain regdomain;
193
static int gotregdomain = 0;
194
static struct ieee80211_roamparams_req roamparams;
195
static int gotroam = 0;
196
static struct ieee80211_txparams_req txparams;
197
static int gottxparams = 0;
198
static struct ieee80211_channel curchan;
199
static int gotcurchan = 0;
200
static struct ifmediareq *global_ifmr;
201
202
/* HT */
203
static int htconf = 0;
204
static int gothtconf = 0;
205
206
static void
207
gethtconf(if_ctx *ctx)
208
{
209
if (gothtconf)
210
return;
211
if (get80211val(ctx, IEEE80211_IOC_HTCONF, &htconf) < 0)
212
warn("unable to get HT configuration information");
213
gothtconf = 1;
214
}
215
216
/* VHT */
217
static int vhtconf = 0;
218
static int gotvhtconf = 0;
219
220
static void
221
getvhtconf(if_ctx *ctx)
222
{
223
if (gotvhtconf)
224
return;
225
if (get80211val(ctx, IEEE80211_IOC_VHTCONF, &vhtconf) < 0)
226
warn("unable to get VHT configuration information");
227
gotvhtconf = 1;
228
}
229
230
/*
231
* Collect channel info from the kernel. We use this (mostly)
232
* to handle mapping between frequency and IEEE channel number.
233
*/
234
static void
235
getchaninfo(if_ctx *ctx)
236
{
237
if (chaninfo != NULL)
238
return;
239
chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
240
if (chaninfo == NULL)
241
errx(1, "no space for channel list");
242
if (get80211(ctx, IEEE80211_IOC_CHANINFO, chaninfo,
243
IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
244
err(1, "unable to get channel information");
245
global_ifmr = ifmedia_getstate(ctx);
246
gethtconf(ctx);
247
getvhtconf(ctx);
248
}
249
250
static struct regdata *
251
getregdata(void)
252
{
253
static struct regdata *rdp = NULL;
254
if (rdp == NULL) {
255
rdp = lib80211_alloc_regdata();
256
if (rdp == NULL)
257
errx(-1, "missing or corrupted regdomain database");
258
}
259
return rdp;
260
}
261
262
/*
263
* Given the channel at index i with attributes from,
264
* check if there is a channel with attributes to in
265
* the channel table. With suitable attributes this
266
* allows the caller to look for promotion; e.g. from
267
* 11b > 11g.
268
*/
269
static int
270
canpromote(unsigned int i, uint32_t from, uint32_t to)
271
{
272
const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
273
u_int j;
274
275
if ((fc->ic_flags & from) != from)
276
return i;
277
/* NB: quick check exploiting ordering of chans w/ same frequency */
278
if (i+1 < chaninfo->ic_nchans &&
279
chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
280
(chaninfo->ic_chans[i+1].ic_flags & to) == to)
281
return i+1;
282
/* brute force search in case channel list is not ordered */
283
for (j = 0; j < chaninfo->ic_nchans; j++) {
284
const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
285
if (j != i &&
286
tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
287
return j;
288
}
289
return i;
290
}
291
292
/*
293
* Handle channel promotion. When a channel is specified with
294
* only a frequency we want to promote it to the ``best'' channel
295
* available. The channel list has separate entries for 11b, 11g,
296
* 11a, and 11n[ga] channels so specifying a frequency w/o any
297
* attributes requires we upgrade, e.g. from 11b -> 11g. This
298
* gets complicated when the channel is specified on the same
299
* command line with a media request that constrains the available
300
* channe list (e.g. mode 11a); we want to honor that to avoid
301
* confusing behaviour.
302
*/
303
/*
304
* XXX VHT
305
*/
306
static int
307
promote(unsigned int i)
308
{
309
/*
310
* Query the current mode of the interface in case it's
311
* constrained (e.g. to 11a). We must do this carefully
312
* as there may be a pending ifmedia request in which case
313
* asking the kernel will give us the wrong answer. This
314
* is an unfortunate side-effect of the way ifconfig is
315
* structure for modularity (yech).
316
*
317
* NB: ifmr is actually setup in getchaninfo (above); we
318
* assume it's called coincident with to this call so
319
* we have a ``current setting''; otherwise we must pass
320
* the socket descriptor down to here so we can make
321
* the ifmedia_getstate call ourselves.
322
*/
323
int chanmode = global_ifmr != NULL ? IFM_MODE(global_ifmr->ifm_current) : IFM_AUTO;
324
325
/* when ambiguous promote to ``best'' */
326
/* NB: we abitrarily pick HT40+ over HT40- */
327
if (chanmode != IFM_IEEE80211_11B)
328
i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
329
if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
330
i = canpromote(i, IEEE80211_CHAN_G,
331
IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
332
if (htconf & 2) {
333
i = canpromote(i, IEEE80211_CHAN_G,
334
IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
335
i = canpromote(i, IEEE80211_CHAN_G,
336
IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
337
}
338
}
339
if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
340
i = canpromote(i, IEEE80211_CHAN_A,
341
IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
342
if (htconf & 2) {
343
i = canpromote(i, IEEE80211_CHAN_A,
344
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
345
i = canpromote(i, IEEE80211_CHAN_A,
346
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
347
}
348
}
349
return i;
350
}
351
352
static void
353
mapfreq(struct ieee80211_channel *chan, uint16_t freq, unsigned int flags)
354
{
355
u_int i;
356
357
for (i = 0; i < chaninfo->ic_nchans; i++) {
358
const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
359
360
if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
361
if (flags == 0) {
362
/* when ambiguous promote to ``best'' */
363
c = &chaninfo->ic_chans[promote(i)];
364
}
365
*chan = *c;
366
return;
367
}
368
}
369
errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
370
}
371
372
static void
373
mapchan(struct ieee80211_channel *chan, uint8_t ieee, unsigned int flags)
374
{
375
u_int i;
376
377
for (i = 0; i < chaninfo->ic_nchans; i++) {
378
const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
379
380
if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
381
if (flags == 0) {
382
/* when ambiguous promote to ``best'' */
383
c = &chaninfo->ic_chans[promote(i)];
384
}
385
*chan = *c;
386
return;
387
}
388
}
389
errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
390
}
391
392
static const struct ieee80211_channel *
393
getcurchan(if_ctx *ctx)
394
{
395
if (gotcurchan)
396
return &curchan;
397
if (get80211(ctx, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
398
int val;
399
/* fall back to legacy ioctl */
400
if (get80211val(ctx, IEEE80211_IOC_CHANNEL, &val) < 0)
401
err(-1, "cannot figure out current channel");
402
getchaninfo(ctx);
403
mapchan(&curchan, val, 0);
404
}
405
gotcurchan = 1;
406
return &curchan;
407
}
408
409
static enum ieee80211_phymode
410
chan2mode(const struct ieee80211_channel *c)
411
{
412
if (IEEE80211_IS_CHAN_VHTA(c))
413
return IEEE80211_MODE_VHT_5GHZ;
414
if (IEEE80211_IS_CHAN_VHTG(c))
415
return IEEE80211_MODE_VHT_2GHZ;
416
if (IEEE80211_IS_CHAN_HTA(c))
417
return IEEE80211_MODE_11NA;
418
if (IEEE80211_IS_CHAN_HTG(c))
419
return IEEE80211_MODE_11NG;
420
if (IEEE80211_IS_CHAN_108A(c))
421
return IEEE80211_MODE_TURBO_A;
422
if (IEEE80211_IS_CHAN_108G(c))
423
return IEEE80211_MODE_TURBO_G;
424
if (IEEE80211_IS_CHAN_ST(c))
425
return IEEE80211_MODE_STURBO_A;
426
if (IEEE80211_IS_CHAN_FHSS(c))
427
return IEEE80211_MODE_FH;
428
if (IEEE80211_IS_CHAN_HALF(c))
429
return IEEE80211_MODE_HALF;
430
if (IEEE80211_IS_CHAN_QUARTER(c))
431
return IEEE80211_MODE_QUARTER;
432
if (IEEE80211_IS_CHAN_A(c))
433
return IEEE80211_MODE_11A;
434
if (IEEE80211_IS_CHAN_ANYG(c))
435
return IEEE80211_MODE_11G;
436
if (IEEE80211_IS_CHAN_B(c))
437
return IEEE80211_MODE_11B;
438
return IEEE80211_MODE_AUTO;
439
}
440
441
static void
442
getroam(if_ctx *ctx)
443
{
444
if (gotroam)
445
return;
446
if (get80211(ctx, IEEE80211_IOC_ROAM,
447
&roamparams, sizeof(roamparams)) < 0)
448
err(1, "unable to get roaming parameters");
449
gotroam = 1;
450
}
451
452
static void
453
setroam_cb(if_ctx *ctx, void *arg)
454
{
455
struct ieee80211_roamparams_req *roam = arg;
456
set80211(ctx, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam);
457
}
458
459
static void
460
gettxparams(if_ctx *ctx)
461
{
462
if (gottxparams)
463
return;
464
if (get80211(ctx, IEEE80211_IOC_TXPARAMS,
465
&txparams, sizeof(txparams)) < 0)
466
err(1, "unable to get transmit parameters");
467
gottxparams = 1;
468
}
469
470
static void
471
settxparams_cb(if_ctx *ctx, void *arg)
472
{
473
struct ieee80211_txparams_req *txp = arg;
474
set80211(ctx, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp);
475
}
476
477
static void
478
getregdomain(if_ctx *ctx)
479
{
480
if (gotregdomain)
481
return;
482
if (get80211(ctx, IEEE80211_IOC_REGDOMAIN,
483
&regdomain, sizeof(regdomain)) < 0)
484
err(1, "unable to get regulatory domain info");
485
gotregdomain = 1;
486
}
487
488
static void
489
getdevcaps(if_ctx *ctx, struct ieee80211_devcaps_req *dc)
490
{
491
if (get80211(ctx, IEEE80211_IOC_DEVCAPS, dc,
492
IEEE80211_DEVCAPS_SPACE(dc)) < 0)
493
err(1, "unable to get device capabilities");
494
}
495
496
static void
497
setregdomain_cb(if_ctx *ctx, void *arg)
498
{
499
struct ieee80211_regdomain_req *req;
500
struct ieee80211_regdomain *rd = arg;
501
struct ieee80211_devcaps_req *dc;
502
struct regdata *rdp = getregdata();
503
504
if (rd->country != NO_COUNTRY) {
505
const struct country *cc;
506
/*
507
* Check current country seting to make sure it's
508
* compatible with the new regdomain. If not, then
509
* override it with any default country for this
510
* SKU. If we cannot arrange a match, then abort.
511
*/
512
cc = lib80211_country_findbycc(rdp, rd->country);
513
if (cc == NULL)
514
errx(1, "unknown ISO country code %d", rd->country);
515
if (cc->rd->sku != rd->regdomain) {
516
const struct regdomain *rp;
517
/*
518
* Check if country is incompatible with regdomain.
519
* To enable multiple regdomains for a country code
520
* we permit a mismatch between the regdomain and
521
* the country's associated regdomain when the
522
* regdomain is setup w/o a default country. For
523
* example, US is bound to the FCC regdomain but
524
* we allow US to be combined with FCC3 because FCC3
525
* has not default country. This allows bogus
526
* combinations like FCC3+DK which are resolved when
527
* constructing the channel list by deferring to the
528
* regdomain to construct the channel list.
529
*/
530
rp = lib80211_regdomain_findbysku(rdp, rd->regdomain);
531
if (rp == NULL)
532
errx(1, "country %s (%s) is not usable with "
533
"regdomain %d", cc->isoname, cc->name,
534
rd->regdomain);
535
else if (rp->cc != NULL && rp->cc != cc)
536
errx(1, "country %s (%s) is not usable with "
537
"regdomain %s", cc->isoname, cc->name,
538
rp->name);
539
}
540
}
541
/*
542
* Fetch the device capabilities and calculate the
543
* full set of netbands for which we request a new
544
* channel list be constructed. Once that's done we
545
* push the regdomain info + channel list to the kernel.
546
*/
547
dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
548
if (dc == NULL)
549
errx(1, "no space for device capabilities");
550
dc->dc_chaninfo.ic_nchans = MAXCHAN;
551
getdevcaps(ctx, dc);
552
#if 0
553
if (verbose) {
554
printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
555
printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
556
printf("htcaps : 0x%x\n", dc->dc_htcaps);
557
printf("vhtcaps : 0x%x\n", dc->dc_vhtcaps);
558
#if 0
559
memcpy(chaninfo, &dc->dc_chaninfo,
560
IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
561
print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
562
#endif
563
}
564
#endif
565
req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
566
if (req == NULL)
567
errx(1, "no space for regdomain request");
568
req->rd = *rd;
569
regdomain_makechannels(ctx, req, dc);
570
if (ctx->args->verbose) {
571
LINE_INIT(':');
572
print_regdomain(rd, 1/*verbose*/);
573
LINE_BREAK();
574
/* blech, reallocate channel list for new data */
575
if (chaninfo != NULL)
576
free(chaninfo);
577
chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
578
if (chaninfo == NULL)
579
errx(1, "no space for channel list");
580
memcpy(chaninfo, &req->chaninfo,
581
IEEE80211_CHANINFO_SPACE(&req->chaninfo));
582
print_channels(ctx, &req->chaninfo, 1/*allchans*/, 1/*verbose*/);
583
}
584
if (req->chaninfo.ic_nchans == 0)
585
errx(1, "no channels calculated");
586
set80211(ctx, IEEE80211_IOC_REGDOMAIN, 0,
587
IEEE80211_REGDOMAIN_SPACE(req), req);
588
free(req);
589
free(dc);
590
}
591
592
static int
593
ieee80211_mhz2ieee(int freq, int flags)
594
{
595
struct ieee80211_channel chan;
596
mapfreq(&chan, freq, flags);
597
return chan.ic_ieee;
598
}
599
600
static int
601
isanyarg(const char *arg)
602
{
603
return (strncmp(arg, "-", 1) == 0 ||
604
strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0);
605
}
606
607
static void
608
set80211ssid(if_ctx *ctx, const char *val, int dummy __unused)
609
{
610
int ssid;
611
int len;
612
u_int8_t data[IEEE80211_NWID_LEN];
613
614
ssid = 0;
615
len = strlen(val);
616
if (len > 2 && isdigit((int)val[0]) && val[1] == ':') {
617
ssid = atoi(val)-1;
618
val += 2;
619
}
620
621
bzero(data, sizeof(data));
622
len = sizeof(data);
623
if (get_string(val, NULL, data, &len) == NULL)
624
exit(1);
625
626
set80211(ctx, IEEE80211_IOC_SSID, ssid, len, data);
627
}
628
629
static void
630
set80211meshid(if_ctx *ctx, const char *val, int dummy __unused)
631
{
632
int len;
633
u_int8_t data[IEEE80211_NWID_LEN];
634
635
memset(data, 0, sizeof(data));
636
len = sizeof(data);
637
if (get_string(val, NULL, data, &len) == NULL)
638
exit(1);
639
640
set80211(ctx, IEEE80211_IOC_MESH_ID, 0, len, data);
641
}
642
643
static void
644
set80211stationname(if_ctx *ctx, const char *val, int dummy __unused)
645
{
646
int len;
647
u_int8_t data[33];
648
649
bzero(data, sizeof(data));
650
len = sizeof(data);
651
get_string(val, NULL, data, &len);
652
653
set80211(ctx, IEEE80211_IOC_STATIONNAME, 0, len, data);
654
}
655
656
/*
657
* Parse a channel specification for attributes/flags.
658
* The syntax is:
659
* freq/xx channel width (5,10,20,40,40+,40-)
660
* freq:mode channel mode (a,b,g,h,n,t,s,d)
661
*
662
* These can be combined in either order; e.g. 2437:ng/40.
663
* Modes are case insensitive.
664
*
665
* The result is not validated here; it's assumed to be
666
* checked against the channel table fetched from the kernel.
667
*/
668
static unsigned int
669
getchannelflags(const char *val, int freq)
670
{
671
#define _CHAN_HT 0x80000000
672
const char *cp;
673
int flags;
674
int is_vht = 0;
675
676
flags = 0;
677
678
cp = strchr(val, ':');
679
if (cp != NULL) {
680
for (cp++; isalpha((int) *cp); cp++) {
681
/* accept mixed case */
682
int c = *cp;
683
if (isupper(c))
684
c = tolower(c);
685
switch (c) {
686
case 'a': /* 802.11a */
687
flags |= IEEE80211_CHAN_A;
688
break;
689
case 'b': /* 802.11b */
690
flags |= IEEE80211_CHAN_B;
691
break;
692
case 'g': /* 802.11g */
693
flags |= IEEE80211_CHAN_G;
694
break;
695
case 'v': /* vht: 802.11ac */
696
is_vht = 1;
697
/* Fallthrough */
698
case 'h': /* ht = 802.11n */
699
case 'n': /* 802.11n */
700
flags |= _CHAN_HT; /* NB: private */
701
break;
702
case 'd': /* dt = Atheros Dynamic Turbo */
703
flags |= IEEE80211_CHAN_TURBO;
704
break;
705
case 't': /* ht, dt, st, t */
706
/* dt and unadorned t specify Dynamic Turbo */
707
if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
708
flags |= IEEE80211_CHAN_TURBO;
709
break;
710
case 's': /* st = Atheros Static Turbo */
711
flags |= IEEE80211_CHAN_STURBO;
712
break;
713
default:
714
errx(-1, "%s: Invalid channel attribute %c\n",
715
val, *cp);
716
}
717
}
718
}
719
cp = strchr(val, '/');
720
if (cp != NULL) {
721
char *ep;
722
u_long cw = strtoul(cp+1, &ep, 10);
723
724
switch (cw) {
725
case 5:
726
flags |= IEEE80211_CHAN_QUARTER;
727
break;
728
case 10:
729
flags |= IEEE80211_CHAN_HALF;
730
break;
731
case 20:
732
/* NB: this may be removed below */
733
flags |= IEEE80211_CHAN_HT20;
734
break;
735
case 40:
736
case 80:
737
case 160:
738
/* Handle the 80/160 VHT flag */
739
if (cw == 80)
740
flags |= IEEE80211_CHAN_VHT80;
741
else if (cw == 160)
742
flags |= IEEE80211_CHAN_VHT160;
743
744
/* Fallthrough */
745
if (ep != NULL && *ep == '+')
746
flags |= IEEE80211_CHAN_HT40U;
747
else if (ep != NULL && *ep == '-')
748
flags |= IEEE80211_CHAN_HT40D;
749
break;
750
default:
751
errx(-1, "%s: Invalid channel width\n", val);
752
}
753
}
754
755
/*
756
* Cleanup specifications.
757
*/
758
if ((flags & _CHAN_HT) == 0) {
759
/*
760
* If user specified freq/20 or freq/40 quietly remove
761
* HT cw attributes depending on channel use. To give
762
* an explicit 20/40 width for an HT channel you must
763
* indicate it is an HT channel since all HT channels
764
* are also usable for legacy operation; e.g. freq:n/40.
765
*/
766
flags &= ~IEEE80211_CHAN_HT;
767
flags &= ~IEEE80211_CHAN_VHT;
768
} else {
769
/*
770
* Remove private indicator that this is an HT channel
771
* and if no explicit channel width has been given
772
* provide the default settings.
773
*/
774
flags &= ~_CHAN_HT;
775
if ((flags & IEEE80211_CHAN_HT) == 0) {
776
struct ieee80211_channel chan;
777
/*
778
* Consult the channel list to see if we can use
779
* HT40+ or HT40- (if both the map routines choose).
780
*/
781
if (freq > 255)
782
mapfreq(&chan, freq, 0);
783
else
784
mapchan(&chan, freq, 0);
785
flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
786
}
787
788
/*
789
* If VHT is enabled, then also set the VHT flag and the
790
* relevant channel up/down.
791
*/
792
if (is_vht && (flags & IEEE80211_CHAN_HT)) {
793
/*
794
* XXX yes, maybe we should just have VHT, and reuse
795
* HT20/HT40U/HT40D
796
*/
797
if (flags & IEEE80211_CHAN_VHT80)
798
;
799
else if (flags & IEEE80211_CHAN_HT20)
800
flags |= IEEE80211_CHAN_VHT20;
801
else if (flags & IEEE80211_CHAN_HT40U)
802
flags |= IEEE80211_CHAN_VHT40U;
803
else if (flags & IEEE80211_CHAN_HT40D)
804
flags |= IEEE80211_CHAN_VHT40D;
805
}
806
}
807
return flags;
808
#undef _CHAN_HT
809
}
810
811
static void
812
getchannel(if_ctx *ctx, struct ieee80211_channel *chan, const char *val)
813
{
814
unsigned int v, flags;
815
char *eptr;
816
817
memset(chan, 0, sizeof(*chan));
818
if (isanyarg(val)) {
819
chan->ic_freq = IEEE80211_CHAN_ANY;
820
return;
821
}
822
getchaninfo(ctx);
823
errno = 0;
824
v = strtol(val, &eptr, 10);
825
if (val[0] == '\0' || val == eptr || errno == ERANGE ||
826
/* channel may be suffixed with nothing, :flag, or /width */
827
(eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/'))
828
errx(1, "invalid channel specification%s",
829
errno == ERANGE ? " (out of range)" : "");
830
flags = getchannelflags(val, v);
831
if (v > 255) { /* treat as frequency */
832
mapfreq(chan, v, flags);
833
} else {
834
mapchan(chan, v, flags);
835
}
836
}
837
838
static void
839
set80211channel(if_ctx *ctx, const char *val, int dummy __unused)
840
{
841
struct ieee80211_channel chan;
842
843
getchannel(ctx, &chan, val);
844
set80211(ctx, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
845
}
846
847
static void
848
set80211chanswitch(if_ctx *ctx, const char *val, int dummy __unused)
849
{
850
struct ieee80211_chanswitch_req csr;
851
852
getchannel(ctx, &csr.csa_chan, val);
853
csr.csa_mode = 1;
854
csr.csa_count = 5;
855
set80211(ctx, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr);
856
}
857
858
static void
859
set80211authmode(if_ctx *ctx, const char *val, int dummy __unused)
860
{
861
int mode;
862
863
if (strcasecmp(val, "none") == 0) {
864
mode = IEEE80211_AUTH_NONE;
865
} else if (strcasecmp(val, "open") == 0) {
866
mode = IEEE80211_AUTH_OPEN;
867
} else if (strcasecmp(val, "shared") == 0) {
868
mode = IEEE80211_AUTH_SHARED;
869
} else if (strcasecmp(val, "8021x") == 0) {
870
mode = IEEE80211_AUTH_8021X;
871
} else if (strcasecmp(val, "wpa") == 0) {
872
mode = IEEE80211_AUTH_WPA;
873
} else {
874
errx(1, "unknown authmode");
875
}
876
877
set80211(ctx, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
878
}
879
880
static void
881
set80211powersavemode(if_ctx *ctx, const char *val, int dummy __unused)
882
{
883
int mode;
884
885
if (strcasecmp(val, "off") == 0) {
886
mode = IEEE80211_POWERSAVE_OFF;
887
} else if (strcasecmp(val, "on") == 0) {
888
mode = IEEE80211_POWERSAVE_ON;
889
} else if (strcasecmp(val, "cam") == 0) {
890
mode = IEEE80211_POWERSAVE_CAM;
891
} else if (strcasecmp(val, "psp") == 0) {
892
mode = IEEE80211_POWERSAVE_PSP;
893
} else if (strcasecmp(val, "psp-cam") == 0) {
894
mode = IEEE80211_POWERSAVE_PSP_CAM;
895
} else {
896
errx(1, "unknown powersavemode");
897
}
898
899
set80211(ctx, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
900
}
901
902
static void
903
set80211powersave(if_ctx *ctx, const char *val __unused, int d)
904
{
905
if (d == 0)
906
set80211(ctx, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
907
0, NULL);
908
else
909
set80211(ctx, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
910
0, NULL);
911
}
912
913
static void
914
set80211powersavesleep(if_ctx *ctx, const char *val, int dummy __unused)
915
{
916
set80211(ctx, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
917
}
918
919
static void
920
set80211wepmode(if_ctx *ctx, const char *val, int dummy __unused)
921
{
922
int mode;
923
924
if (strcasecmp(val, "off") == 0) {
925
mode = IEEE80211_WEP_OFF;
926
} else if (strcasecmp(val, "on") == 0) {
927
mode = IEEE80211_WEP_ON;
928
} else if (strcasecmp(val, "mixed") == 0) {
929
mode = IEEE80211_WEP_MIXED;
930
} else {
931
errx(1, "unknown wep mode");
932
}
933
934
set80211(ctx, IEEE80211_IOC_WEP, mode, 0, NULL);
935
}
936
937
static void
938
set80211wep(if_ctx *ctx, const char *val __unused, int d)
939
{
940
set80211(ctx, IEEE80211_IOC_WEP, d, 0, NULL);
941
}
942
943
static int
944
isundefarg(const char *arg)
945
{
946
return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
947
}
948
949
static void
950
set80211weptxkey(if_ctx *ctx, const char *val, int dummy __unused)
951
{
952
if (isundefarg(val))
953
set80211(ctx, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
954
else
955
set80211(ctx, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
956
}
957
958
static void
959
set80211wepkey(if_ctx *ctx, const char *val, int dummy __unused)
960
{
961
int key = 0;
962
int len;
963
u_int8_t data[IEEE80211_KEYBUF_SIZE];
964
965
if (isdigit((int)val[0]) && val[1] == ':') {
966
key = atoi(val)-1;
967
val += 2;
968
}
969
970
bzero(data, sizeof(data));
971
len = sizeof(data);
972
get_string(val, NULL, data, &len);
973
974
set80211(ctx, IEEE80211_IOC_WEPKEY, key, len, data);
975
}
976
977
/*
978
* This function is purely a NetBSD compatibility interface. The NetBSD
979
* interface is too inflexible, but it's there so we'll support it since
980
* it's not all that hard.
981
*/
982
static void
983
set80211nwkey(if_ctx *ctx, const char *val, int dummy __unused)
984
{
985
int txkey;
986
int i, len;
987
u_int8_t data[IEEE80211_KEYBUF_SIZE];
988
989
set80211(ctx, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
990
991
if (isdigit((int)val[0]) && val[1] == ':') {
992
txkey = val[0]-'0'-1;
993
val += 2;
994
995
for (i = 0; i < 4; i++) {
996
bzero(data, sizeof(data));
997
len = sizeof(data);
998
val = get_string(val, ",", data, &len);
999
if (val == NULL)
1000
exit(1);
1001
1002
set80211(ctx, IEEE80211_IOC_WEPKEY, i, len, data);
1003
}
1004
} else {
1005
bzero(data, sizeof(data));
1006
len = sizeof(data);
1007
get_string(val, NULL, data, &len);
1008
txkey = 0;
1009
1010
set80211(ctx, IEEE80211_IOC_WEPKEY, 0, len, data);
1011
1012
bzero(data, sizeof(data));
1013
for (i = 1; i < 4; i++)
1014
set80211(ctx, IEEE80211_IOC_WEPKEY, i, 0, data);
1015
}
1016
1017
set80211(ctx, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
1018
}
1019
1020
static void
1021
set80211rtsthreshold(if_ctx *ctx, const char *val, int dummy __unused)
1022
{
1023
set80211(ctx, IEEE80211_IOC_RTSTHRESHOLD,
1024
isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
1025
}
1026
1027
static void
1028
set80211protmode(if_ctx *ctx, const char *val, int dummy __unused)
1029
{
1030
int mode;
1031
1032
if (strcasecmp(val, "off") == 0) {
1033
mode = IEEE80211_PROTMODE_OFF;
1034
} else if (strcasecmp(val, "cts") == 0) {
1035
mode = IEEE80211_PROTMODE_CTS;
1036
} else if (strncasecmp(val, "rtscts", 3) == 0) {
1037
mode = IEEE80211_PROTMODE_RTSCTS;
1038
} else {
1039
errx(1, "unknown protection mode");
1040
}
1041
1042
set80211(ctx, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
1043
}
1044
1045
static void
1046
set80211htprotmode(if_ctx *ctx, const char *val, int dummy __unused)
1047
{
1048
int mode;
1049
1050
if (strcasecmp(val, "off") == 0) {
1051
mode = IEEE80211_PROTMODE_OFF;
1052
} else if (strncasecmp(val, "rts", 3) == 0) {
1053
mode = IEEE80211_PROTMODE_RTSCTS;
1054
} else {
1055
errx(1, "unknown protection mode");
1056
}
1057
1058
set80211(ctx, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
1059
}
1060
1061
static void
1062
set80211txpower(if_ctx *ctx, const char *val, int dummy __unused)
1063
{
1064
double v = atof(val);
1065
int txpow;
1066
1067
txpow = (int) (2*v);
1068
if (txpow != 2*v)
1069
errx(-1, "invalid tx power (must be .5 dBm units)");
1070
set80211(ctx, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
1071
}
1072
1073
#define IEEE80211_ROAMING_DEVICE 0
1074
#define IEEE80211_ROAMING_AUTO 1
1075
#define IEEE80211_ROAMING_MANUAL 2
1076
1077
static void
1078
set80211roaming(if_ctx *ctx, const char *val, int dummy __unused)
1079
{
1080
int mode;
1081
1082
if (strcasecmp(val, "device") == 0) {
1083
mode = IEEE80211_ROAMING_DEVICE;
1084
} else if (strcasecmp(val, "auto") == 0) {
1085
mode = IEEE80211_ROAMING_AUTO;
1086
} else if (strcasecmp(val, "manual") == 0) {
1087
mode = IEEE80211_ROAMING_MANUAL;
1088
} else {
1089
errx(1, "unknown roaming mode");
1090
}
1091
set80211(ctx, IEEE80211_IOC_ROAMING, mode, 0, NULL);
1092
}
1093
1094
static void
1095
set80211wme(if_ctx *ctx, const char *val __unused, int d)
1096
{
1097
set80211(ctx, IEEE80211_IOC_WME, d, 0, NULL);
1098
}
1099
1100
static void
1101
set80211hidessid(if_ctx *ctx, const char *val __unused, int d)
1102
{
1103
set80211(ctx, IEEE80211_IOC_HIDESSID, d, 0, NULL);
1104
}
1105
1106
static void
1107
set80211apbridge(if_ctx *ctx, const char *val __unused, int d)
1108
{
1109
set80211(ctx, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
1110
}
1111
1112
static void
1113
set80211fastframes(if_ctx *ctx, const char *val __unused, int d)
1114
{
1115
set80211(ctx, IEEE80211_IOC_FF, d, 0, NULL);
1116
}
1117
1118
static void
1119
set80211dturbo(if_ctx *ctx, const char *val __unused, int d)
1120
{
1121
set80211(ctx, IEEE80211_IOC_TURBOP, d, 0, NULL);
1122
}
1123
1124
static void
1125
set80211chanlist(if_ctx *ctx, const char *val, int dummy __unused)
1126
{
1127
struct ieee80211req_chanlist chanlist;
1128
char *temp, *cp, *tp;
1129
1130
temp = malloc(strlen(val) + 1);
1131
if (temp == NULL)
1132
errx(1, "malloc failed");
1133
strcpy(temp, val);
1134
memset(&chanlist, 0, sizeof(chanlist));
1135
cp = temp;
1136
for (;;) {
1137
int first, last, f, c;
1138
1139
tp = strchr(cp, ',');
1140
if (tp != NULL)
1141
*tp++ = '\0';
1142
switch (sscanf(cp, "%u-%u", &first, &last)) {
1143
case 1:
1144
if (first > IEEE80211_CHAN_MAX)
1145
errx(-1, "channel %u out of range, max %u",
1146
first, IEEE80211_CHAN_MAX);
1147
setbit(chanlist.ic_channels, first);
1148
break;
1149
case 2:
1150
if (first > IEEE80211_CHAN_MAX)
1151
errx(-1, "channel %u out of range, max %u",
1152
first, IEEE80211_CHAN_MAX);
1153
if (last > IEEE80211_CHAN_MAX)
1154
errx(-1, "channel %u out of range, max %u",
1155
last, IEEE80211_CHAN_MAX);
1156
if (first > last)
1157
errx(-1, "void channel range, %u > %u",
1158
first, last);
1159
for (f = first; f <= last; f++)
1160
setbit(chanlist.ic_channels, f);
1161
break;
1162
}
1163
if (tp == NULL)
1164
break;
1165
c = *tp;
1166
while (isspace(c))
1167
tp++;
1168
if (!isdigit(c))
1169
break;
1170
cp = tp;
1171
}
1172
set80211(ctx, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
1173
free(temp);
1174
}
1175
1176
static void
1177
set80211bssid(if_ctx *ctx, const char *val, int dummy __unused)
1178
{
1179
if (!isanyarg(val)) {
1180
char *temp;
1181
struct sockaddr_dl sdl;
1182
1183
temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1184
if (temp == NULL)
1185
errx(1, "malloc failed");
1186
temp[0] = ':';
1187
strcpy(temp + 1, val);
1188
sdl.sdl_len = sizeof(sdl);
1189
link_addr(temp, &sdl);
1190
free(temp);
1191
if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1192
errx(1, "malformed link-level address");
1193
set80211(ctx, IEEE80211_IOC_BSSID, 0,
1194
IEEE80211_ADDR_LEN, LLADDR(&sdl));
1195
} else {
1196
uint8_t zerobssid[IEEE80211_ADDR_LEN];
1197
memset(zerobssid, 0, sizeof(zerobssid));
1198
set80211(ctx, IEEE80211_IOC_BSSID, 0,
1199
IEEE80211_ADDR_LEN, zerobssid);
1200
}
1201
}
1202
1203
static int
1204
getac(const char *ac)
1205
{
1206
if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
1207
return WME_AC_BE;
1208
if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
1209
return WME_AC_BK;
1210
if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
1211
return WME_AC_VI;
1212
if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
1213
return WME_AC_VO;
1214
errx(1, "unknown wme access class %s", ac);
1215
}
1216
1217
static void
1218
set80211cwmin(if_ctx *ctx, const char *ac, const char *val)
1219
{
1220
set80211(ctx, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
1221
}
1222
1223
static void
1224
set80211cwmax(if_ctx *ctx, const char *ac, const char *val)
1225
{
1226
set80211(ctx, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
1227
}
1228
1229
static void
1230
set80211aifs(if_ctx *ctx, const char *ac, const char *val)
1231
{
1232
set80211(ctx, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
1233
}
1234
1235
static void
1236
set80211txoplimit(if_ctx *ctx, const char *ac, const char *val)
1237
{
1238
set80211(ctx, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
1239
}
1240
1241
static void
1242
set80211acm(if_ctx *ctx, const char *ac, int dummy __unused)
1243
{
1244
set80211(ctx, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
1245
}
1246
1247
static void
1248
set80211noacm(if_ctx *ctx, const char *ac, int dummy __unused)
1249
{
1250
set80211(ctx, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
1251
}
1252
1253
static void
1254
set80211ackpolicy(if_ctx *ctx, const char *ac, int dummy __unused)
1255
{
1256
set80211(ctx, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
1257
}
1258
static void
1259
set80211noackpolicy(if_ctx *ctx, const char *ac, int dummy __unused)
1260
{
1261
set80211(ctx, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
1262
}
1263
1264
static void
1265
set80211bsscwmin(if_ctx *ctx, const char *ac, const char *val)
1266
{
1267
set80211(ctx, IEEE80211_IOC_WME_CWMIN, atoi(val),
1268
getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1269
}
1270
1271
static void
1272
set80211bsscwmax(if_ctx *ctx, const char *ac, const char *val)
1273
{
1274
set80211(ctx, IEEE80211_IOC_WME_CWMAX, atoi(val),
1275
getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1276
}
1277
1278
static void
1279
set80211bssaifs(if_ctx *ctx, const char *ac, const char *val)
1280
{
1281
set80211(ctx, IEEE80211_IOC_WME_AIFS, atoi(val),
1282
getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1283
}
1284
1285
static void
1286
set80211bsstxoplimit(if_ctx *ctx, const char *ac, const char *val)
1287
{
1288
set80211(ctx, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
1289
getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
1290
}
1291
1292
static void
1293
set80211dtimperiod(if_ctx *ctx, const char *val, int dummy __unused)
1294
{
1295
set80211(ctx, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
1296
}
1297
1298
static void
1299
set80211bintval(if_ctx *ctx, const char *val, int dummy __unused)
1300
{
1301
set80211(ctx, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
1302
}
1303
1304
static void
1305
set80211macmac(if_ctx *ctx, int op, const char *val)
1306
{
1307
char *temp;
1308
struct sockaddr_dl sdl;
1309
1310
temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1311
if (temp == NULL)
1312
errx(1, "malloc failed");
1313
temp[0] = ':';
1314
strcpy(temp + 1, val);
1315
sdl.sdl_len = sizeof(sdl);
1316
link_addr(temp, &sdl);
1317
free(temp);
1318
if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1319
errx(1, "malformed link-level address");
1320
set80211(ctx, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
1321
}
1322
1323
static void
1324
set80211addmac(if_ctx *ctx, const char *val, int dummy __unused)
1325
{
1326
set80211macmac(ctx, IEEE80211_IOC_ADDMAC, val);
1327
}
1328
1329
static void
1330
set80211delmac(if_ctx *ctx, const char *val, int dummy __unused)
1331
{
1332
set80211macmac(ctx, IEEE80211_IOC_DELMAC, val);
1333
}
1334
1335
static void
1336
set80211kickmac(if_ctx *ctx, const char *val, int dummy __unused)
1337
{
1338
char *temp;
1339
struct sockaddr_dl sdl;
1340
struct ieee80211req_mlme mlme;
1341
1342
temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1343
if (temp == NULL)
1344
errx(1, "malloc failed");
1345
temp[0] = ':';
1346
strcpy(temp + 1, val);
1347
sdl.sdl_len = sizeof(sdl);
1348
link_addr(temp, &sdl);
1349
free(temp);
1350
if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1351
errx(1, "malformed link-level address");
1352
memset(&mlme, 0, sizeof(mlme));
1353
mlme.im_op = IEEE80211_MLME_DEAUTH;
1354
mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
1355
memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
1356
set80211(ctx, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
1357
}
1358
1359
static void
1360
set80211maccmd(if_ctx *ctx, const char *val __unused, int d)
1361
{
1362
set80211(ctx, IEEE80211_IOC_MACCMD, d, 0, NULL);
1363
}
1364
1365
static void
1366
set80211meshrtmac(if_ctx *ctx, int req, const char *val)
1367
{
1368
char *temp;
1369
struct sockaddr_dl sdl;
1370
1371
temp = malloc(strlen(val) + 2); /* ':' and '\0' */
1372
if (temp == NULL)
1373
errx(1, "malloc failed");
1374
temp[0] = ':';
1375
strcpy(temp + 1, val);
1376
sdl.sdl_len = sizeof(sdl);
1377
link_addr(temp, &sdl);
1378
free(temp);
1379
if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
1380
errx(1, "malformed link-level address");
1381
set80211(ctx, IEEE80211_IOC_MESH_RTCMD, req,
1382
IEEE80211_ADDR_LEN, LLADDR(&sdl));
1383
}
1384
1385
static void
1386
set80211addmeshrt(if_ctx *ctx, const char *val, int dummy __unused)
1387
{
1388
set80211meshrtmac(ctx, IEEE80211_MESH_RTCMD_ADD, val);
1389
}
1390
1391
static void
1392
set80211delmeshrt(if_ctx *ctx, const char *val, int dummy __unused)
1393
{
1394
set80211meshrtmac(ctx, IEEE80211_MESH_RTCMD_DELETE, val);
1395
}
1396
1397
static void
1398
set80211meshrtcmd(if_ctx *ctx, const char *val __unused, int d)
1399
{
1400
set80211(ctx, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL);
1401
}
1402
1403
static void
1404
set80211hwmprootmode(if_ctx *ctx, const char *val, int dummy __unused)
1405
{
1406
int mode;
1407
1408
if (strcasecmp(val, "normal") == 0)
1409
mode = IEEE80211_HWMP_ROOTMODE_NORMAL;
1410
else if (strcasecmp(val, "proactive") == 0)
1411
mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
1412
else if (strcasecmp(val, "rann") == 0)
1413
mode = IEEE80211_HWMP_ROOTMODE_RANN;
1414
else
1415
mode = IEEE80211_HWMP_ROOTMODE_DISABLED;
1416
set80211(ctx, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL);
1417
}
1418
1419
static void
1420
set80211hwmpmaxhops(if_ctx *ctx, const char *val, int dummy __unused)
1421
{
1422
set80211(ctx, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL);
1423
}
1424
1425
static void
1426
set80211pureg(if_ctx *ctx, const char *val __unused, int d)
1427
{
1428
set80211(ctx, IEEE80211_IOC_PUREG, d, 0, NULL);
1429
}
1430
1431
static void
1432
set80211quiet(if_ctx *ctx, const char *val __unused, int d)
1433
{
1434
set80211(ctx, IEEE80211_IOC_QUIET, d, 0, NULL);
1435
}
1436
1437
static void
1438
set80211quietperiod(if_ctx *ctx, const char *val, int dummy __unused)
1439
{
1440
set80211(ctx, IEEE80211_IOC_QUIET_PERIOD, atoi(val), 0, NULL);
1441
}
1442
1443
static void
1444
set80211quietcount(if_ctx *ctx, const char *val, int dummy __unused)
1445
{
1446
set80211(ctx, IEEE80211_IOC_QUIET_COUNT, atoi(val), 0, NULL);
1447
}
1448
1449
static void
1450
set80211quietduration(if_ctx *ctx, const char *val, int dummy __unused)
1451
{
1452
set80211(ctx, IEEE80211_IOC_QUIET_DUR, atoi(val), 0, NULL);
1453
}
1454
1455
static void
1456
set80211quietoffset(if_ctx *ctx, const char *val, int dummy __unused)
1457
{
1458
set80211(ctx, IEEE80211_IOC_QUIET_OFFSET, atoi(val), 0, NULL);
1459
}
1460
1461
static void
1462
set80211bgscan(if_ctx *ctx, const char *val __unused, int d)
1463
{
1464
set80211(ctx, IEEE80211_IOC_BGSCAN, d, 0, NULL);
1465
}
1466
1467
static void
1468
set80211bgscanidle(if_ctx *ctx, const char *val, int dummy __unused)
1469
{
1470
set80211(ctx, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
1471
}
1472
1473
static void
1474
set80211bgscanintvl(if_ctx *ctx, const char *val, int dummy __unused)
1475
{
1476
set80211(ctx, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
1477
}
1478
1479
static void
1480
set80211scanvalid(if_ctx *ctx, const char *val, int dummy __unused)
1481
{
1482
set80211(ctx, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
1483
}
1484
1485
/*
1486
* Parse an optional trailing specification of which netbands
1487
* to apply a parameter to. This is basically the same syntax
1488
* as used for channels but you can concatenate to specify
1489
* multiple. For example:
1490
* 14:abg apply to 11a, 11b, and 11g
1491
* 6:ht apply to 11na and 11ng
1492
* We don't make a big effort to catch silly things; this is
1493
* really a convenience mechanism.
1494
*/
1495
static int
1496
getmodeflags(const char *val)
1497
{
1498
const char *cp;
1499
int flags;
1500
1501
flags = 0;
1502
1503
cp = strchr(val, ':');
1504
if (cp != NULL) {
1505
for (cp++; isalpha((int) *cp); cp++) {
1506
/* accept mixed case */
1507
int c = *cp;
1508
if (isupper(c))
1509
c = tolower(c);
1510
switch (c) {
1511
case 'a': /* 802.11a */
1512
flags |= IEEE80211_CHAN_A;
1513
break;
1514
case 'b': /* 802.11b */
1515
flags |= IEEE80211_CHAN_B;
1516
break;
1517
case 'g': /* 802.11g */
1518
flags |= IEEE80211_CHAN_G;
1519
break;
1520
case 'n': /* 802.11n */
1521
flags |= IEEE80211_CHAN_HT;
1522
break;
1523
case 'd': /* dt = Atheros Dynamic Turbo */
1524
flags |= IEEE80211_CHAN_TURBO;
1525
break;
1526
case 't': /* ht, dt, st, t */
1527
/* dt and unadorned t specify Dynamic Turbo */
1528
if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0)
1529
flags |= IEEE80211_CHAN_TURBO;
1530
break;
1531
case 's': /* st = Atheros Static Turbo */
1532
flags |= IEEE80211_CHAN_STURBO;
1533
break;
1534
case 'h': /* 1/2-width channels */
1535
flags |= IEEE80211_CHAN_HALF;
1536
break;
1537
case 'q': /* 1/4-width channels */
1538
flags |= IEEE80211_CHAN_QUARTER;
1539
break;
1540
case 'v':
1541
/* XXX set HT too? */
1542
flags |= IEEE80211_CHAN_VHT;
1543
break;
1544
default:
1545
errx(-1, "%s: Invalid mode attribute %c\n",
1546
val, *cp);
1547
}
1548
}
1549
}
1550
return flags;
1551
}
1552
1553
#define _APPLY(_flags, _base, _param, _v) do { \
1554
if (_flags & IEEE80211_CHAN_HT) { \
1555
if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1556
_base.params[IEEE80211_MODE_11NA]._param = _v; \
1557
_base.params[IEEE80211_MODE_11NG]._param = _v; \
1558
} else if (_flags & IEEE80211_CHAN_5GHZ) \
1559
_base.params[IEEE80211_MODE_11NA]._param = _v; \
1560
else \
1561
_base.params[IEEE80211_MODE_11NG]._param = _v; \
1562
} \
1563
if (_flags & IEEE80211_CHAN_TURBO) { \
1564
if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
1565
_base.params[IEEE80211_MODE_TURBO_A]._param = _v; \
1566
_base.params[IEEE80211_MODE_TURBO_G]._param = _v; \
1567
} else if (_flags & IEEE80211_CHAN_5GHZ) \
1568
_base.params[IEEE80211_MODE_TURBO_A]._param = _v; \
1569
else \
1570
_base.params[IEEE80211_MODE_TURBO_G]._param = _v; \
1571
} \
1572
if (_flags & IEEE80211_CHAN_STURBO) \
1573
_base.params[IEEE80211_MODE_STURBO_A]._param = _v; \
1574
if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \
1575
_base.params[IEEE80211_MODE_11A]._param = _v; \
1576
if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \
1577
_base.params[IEEE80211_MODE_11G]._param = _v; \
1578
if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \
1579
_base.params[IEEE80211_MODE_11B]._param = _v; \
1580
if (_flags & IEEE80211_CHAN_HALF) \
1581
_base.params[IEEE80211_MODE_HALF]._param = _v; \
1582
if (_flags & IEEE80211_CHAN_QUARTER) \
1583
_base.params[IEEE80211_MODE_QUARTER]._param = _v; \
1584
} while (0)
1585
#define _APPLY1(_flags, _base, _param, _v) do { \
1586
if (_flags & IEEE80211_CHAN_HT) { \
1587
if (_flags & IEEE80211_CHAN_5GHZ) \
1588
_base.params[IEEE80211_MODE_11NA]._param = _v; \
1589
else \
1590
_base.params[IEEE80211_MODE_11NG]._param = _v; \
1591
} else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) \
1592
_base.params[IEEE80211_MODE_TURBO_A]._param = _v; \
1593
else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) \
1594
_base.params[IEEE80211_MODE_TURBO_G]._param = _v; \
1595
else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) \
1596
_base.params[IEEE80211_MODE_STURBO_A]._param = _v; \
1597
else if (_flags & IEEE80211_CHAN_HALF) \
1598
_base.params[IEEE80211_MODE_HALF]._param = _v; \
1599
else if (_flags & IEEE80211_CHAN_QUARTER) \
1600
_base.params[IEEE80211_MODE_QUARTER]._param = _v; \
1601
else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \
1602
_base.params[IEEE80211_MODE_11A]._param = _v; \
1603
else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \
1604
_base.params[IEEE80211_MODE_11G]._param = _v; \
1605
else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \
1606
_base.params[IEEE80211_MODE_11B]._param = _v; \
1607
} while (0)
1608
#define _APPLY_RATE(_flags, _base, _param, _v) do { \
1609
if (_flags & IEEE80211_CHAN_HT) { \
1610
(_v) = (_v / 2) | IEEE80211_RATE_MCS; \
1611
} \
1612
_APPLY(_flags, _base, _param, _v); \
1613
} while (0)
1614
#define _APPLY_RATE1(_flags, _base, _param, _v) do { \
1615
if (_flags & IEEE80211_CHAN_HT) { \
1616
(_v) = (_v / 2) | IEEE80211_RATE_MCS; \
1617
} \
1618
_APPLY1(_flags, _base, _param, _v); \
1619
} while (0)
1620
1621
static void
1622
set80211roamrssi(if_ctx *ctx, const char *val, int dummy __unused)
1623
{
1624
double v = atof(val);
1625
int rssi, flags;
1626
1627
rssi = (int) (2*v);
1628
if (rssi != 2*v)
1629
errx(-1, "invalid rssi (must be .5 dBm units)");
1630
flags = getmodeflags(val);
1631
getroam(ctx);
1632
if (flags == 0) { /* NB: no flags => current channel */
1633
flags = getcurchan(ctx)->ic_flags;
1634
_APPLY1(flags, roamparams, rssi, rssi);
1635
} else
1636
_APPLY(flags, roamparams, rssi, rssi);
1637
callback_register(setroam_cb, &roamparams);
1638
}
1639
1640
static int
1641
getrate(const char *val, const char *tag)
1642
{
1643
double v = atof(val);
1644
int rate;
1645
1646
rate = (int) (2*v);
1647
if (rate != 2*v)
1648
errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag);
1649
return rate; /* NB: returns 2x the specified value */
1650
}
1651
1652
static void
1653
set80211roamrate(if_ctx *ctx, const char *val, int dummy __unused)
1654
{
1655
int rate, flags;
1656
1657
rate = getrate(val, "roam");
1658
flags = getmodeflags(val);
1659
getroam(ctx);
1660
if (flags == 0) { /* NB: no flags => current channel */
1661
flags = getcurchan(ctx)->ic_flags;
1662
_APPLY_RATE1(flags, roamparams, rate, rate);
1663
} else
1664
_APPLY_RATE(flags, roamparams, rate, rate);
1665
callback_register(setroam_cb, &roamparams);
1666
}
1667
1668
static void
1669
set80211mcastrate(if_ctx *ctx, const char *val, int dummy __unused)
1670
{
1671
int rate, flags;
1672
1673
rate = getrate(val, "mcast");
1674
flags = getmodeflags(val);
1675
gettxparams(ctx);
1676
if (flags == 0) { /* NB: no flags => current channel */
1677
flags = getcurchan(ctx)->ic_flags;
1678
_APPLY_RATE1(flags, txparams, mcastrate, rate);
1679
} else
1680
_APPLY_RATE(flags, txparams, mcastrate, rate);
1681
callback_register(settxparams_cb, &txparams);
1682
}
1683
1684
static void
1685
set80211mgtrate(if_ctx *ctx, const char *val, int dummy __unused)
1686
{
1687
int rate, flags;
1688
1689
rate = getrate(val, "mgmt");
1690
flags = getmodeflags(val);
1691
gettxparams(ctx);
1692
if (flags == 0) { /* NB: no flags => current channel */
1693
flags = getcurchan(ctx)->ic_flags;
1694
_APPLY_RATE1(flags, txparams, mgmtrate, rate);
1695
} else
1696
_APPLY_RATE(flags, txparams, mgmtrate, rate);
1697
callback_register(settxparams_cb, &txparams);
1698
}
1699
1700
static void
1701
set80211ucastrate(if_ctx *ctx, const char *val, int dummy __unused)
1702
{
1703
int flags;
1704
1705
gettxparams(ctx);
1706
flags = getmodeflags(val);
1707
if (isanyarg(val)) {
1708
if (flags == 0) { /* NB: no flags => current channel */
1709
flags = getcurchan(ctx)->ic_flags;
1710
_APPLY1(flags, txparams, ucastrate,
1711
IEEE80211_FIXED_RATE_NONE);
1712
} else
1713
_APPLY(flags, txparams, ucastrate,
1714
IEEE80211_FIXED_RATE_NONE);
1715
} else {
1716
int rate = getrate(val, "ucast");
1717
if (flags == 0) { /* NB: no flags => current channel */
1718
flags = getcurchan(ctx)->ic_flags;
1719
_APPLY_RATE1(flags, txparams, ucastrate, rate);
1720
} else
1721
_APPLY_RATE(flags, txparams, ucastrate, rate);
1722
}
1723
callback_register(settxparams_cb, &txparams);
1724
}
1725
1726
static void
1727
set80211maxretry(if_ctx *ctx, const char *val, int dummy __unused)
1728
{
1729
int v = atoi(val), flags;
1730
1731
flags = getmodeflags(val);
1732
gettxparams(ctx);
1733
if (flags == 0) { /* NB: no flags => current channel */
1734
flags = getcurchan(ctx)->ic_flags;
1735
_APPLY1(flags, txparams, maxretry, v);
1736
} else
1737
_APPLY(flags, txparams, maxretry, v);
1738
callback_register(settxparams_cb, &txparams);
1739
}
1740
#undef _APPLY_RATE
1741
#undef _APPLY
1742
1743
static void
1744
set80211fragthreshold(if_ctx *ctx, const char *val, int dummy __unused)
1745
{
1746
set80211(ctx, IEEE80211_IOC_FRAGTHRESHOLD,
1747
isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
1748
}
1749
1750
static void
1751
set80211bmissthreshold(if_ctx *ctx, const char *val, int dummy __unused)
1752
{
1753
set80211(ctx, IEEE80211_IOC_BMISSTHRESHOLD,
1754
isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
1755
}
1756
1757
static void
1758
set80211burst(if_ctx *ctx, const char *val __unused, int d)
1759
{
1760
set80211(ctx, IEEE80211_IOC_BURST, d, 0, NULL);
1761
}
1762
1763
static void
1764
set80211doth(if_ctx *ctx, const char *val __unused, int d)
1765
{
1766
set80211(ctx, IEEE80211_IOC_DOTH, d, 0, NULL);
1767
}
1768
1769
static void
1770
set80211dfs(if_ctx *ctx, const char *val __unused, int d)
1771
{
1772
set80211(ctx, IEEE80211_IOC_DFS, d, 0, NULL);
1773
}
1774
1775
static void
1776
set80211shortgi(if_ctx *ctx, const char *val __unused, int d)
1777
{
1778
set80211(ctx, IEEE80211_IOC_SHORTGI,
1779
d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
1780
0, NULL);
1781
}
1782
1783
/* XXX 11ac density/size is different */
1784
static void
1785
set80211ampdu(if_ctx *ctx, const char *val __unused, int d)
1786
{
1787
int ampdu;
1788
1789
if (get80211val(ctx, IEEE80211_IOC_AMPDU, &ampdu) < 0)
1790
errx(-1, "cannot set AMPDU setting");
1791
if (d < 0) {
1792
d = -d;
1793
ampdu &= ~d;
1794
} else
1795
ampdu |= d;
1796
set80211(ctx, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
1797
}
1798
1799
static void
1800
set80211stbc(if_ctx *ctx, const char *val __unused, int d)
1801
{
1802
int stbc;
1803
1804
if (get80211val(ctx, IEEE80211_IOC_STBC, &stbc) < 0)
1805
errx(-1, "cannot set STBC setting");
1806
if (d < 0) {
1807
d = -d;
1808
stbc &= ~d;
1809
} else
1810
stbc |= d;
1811
set80211(ctx, IEEE80211_IOC_STBC, stbc, 0, NULL);
1812
}
1813
1814
static void
1815
set80211ldpc(if_ctx *ctx, const char *val __unused, int d)
1816
{
1817
int ldpc;
1818
1819
if (get80211val(ctx, IEEE80211_IOC_LDPC, &ldpc) < 0)
1820
errx(-1, "cannot set LDPC setting");
1821
if (d < 0) {
1822
d = -d;
1823
ldpc &= ~d;
1824
} else
1825
ldpc |= d;
1826
set80211(ctx, IEEE80211_IOC_LDPC, ldpc, 0, NULL);
1827
}
1828
1829
static void
1830
set80211uapsd(if_ctx *ctx, const char *val __unused, int d)
1831
{
1832
set80211(ctx, IEEE80211_IOC_UAPSD, d, 0, NULL);
1833
}
1834
1835
static void
1836
set80211ampdulimit(if_ctx *ctx, const char *val, int dummy __unused)
1837
{
1838
int v;
1839
1840
switch (atoi(val)) {
1841
case 8:
1842
case 8*1024:
1843
v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
1844
break;
1845
case 16:
1846
case 16*1024:
1847
v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
1848
break;
1849
case 32:
1850
case 32*1024:
1851
v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
1852
break;
1853
case 64:
1854
case 64*1024:
1855
v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
1856
break;
1857
default:
1858
errx(-1, "invalid A-MPDU limit %s", val);
1859
}
1860
set80211(ctx, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
1861
}
1862
1863
/* XXX 11ac density/size is different */
1864
static void
1865
set80211ampdudensity(if_ctx *ctx, const char *val, int dummy __unused)
1866
{
1867
int v;
1868
1869
if (isanyarg(val) || strcasecmp(val, "na") == 0)
1870
v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1871
else switch ((int)(atof(val)*4)) {
1872
case 0:
1873
v = IEEE80211_HTCAP_MPDUDENSITY_NA;
1874
break;
1875
case 1:
1876
v = IEEE80211_HTCAP_MPDUDENSITY_025;
1877
break;
1878
case 2:
1879
v = IEEE80211_HTCAP_MPDUDENSITY_05;
1880
break;
1881
case 4:
1882
v = IEEE80211_HTCAP_MPDUDENSITY_1;
1883
break;
1884
case 8:
1885
v = IEEE80211_HTCAP_MPDUDENSITY_2;
1886
break;
1887
case 16:
1888
v = IEEE80211_HTCAP_MPDUDENSITY_4;
1889
break;
1890
case 32:
1891
v = IEEE80211_HTCAP_MPDUDENSITY_8;
1892
break;
1893
case 64:
1894
v = IEEE80211_HTCAP_MPDUDENSITY_16;
1895
break;
1896
default:
1897
errx(-1, "invalid A-MPDU density %s", val);
1898
}
1899
set80211(ctx, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
1900
}
1901
1902
static void
1903
set80211amsdu(if_ctx *ctx, const char *val __unused, int d)
1904
{
1905
int amsdu;
1906
1907
if (get80211val(ctx, IEEE80211_IOC_AMSDU, &amsdu) < 0)
1908
err(-1, "cannot get AMSDU setting");
1909
if (d < 0) {
1910
d = -d;
1911
amsdu &= ~d;
1912
} else
1913
amsdu |= d;
1914
set80211(ctx, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
1915
}
1916
1917
static void
1918
set80211amsdulimit(if_ctx *ctx, const char *val, int dummy __unused)
1919
{
1920
set80211(ctx, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
1921
}
1922
1923
static void
1924
set80211puren(if_ctx *ctx, const char *val __unused, int d)
1925
{
1926
set80211(ctx, IEEE80211_IOC_PUREN, d, 0, NULL);
1927
}
1928
1929
static void
1930
set80211htcompat(if_ctx *ctx, const char *val __unused, int d)
1931
{
1932
set80211(ctx, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
1933
}
1934
1935
static void
1936
set80211htconf(if_ctx *ctx, const char *val __unused, int d)
1937
{
1938
set80211(ctx, IEEE80211_IOC_HTCONF, d, 0, NULL);
1939
htconf = d;
1940
}
1941
1942
static void
1943
set80211dwds(if_ctx *ctx, const char *val __unused, int d)
1944
{
1945
set80211(ctx, IEEE80211_IOC_DWDS, d, 0, NULL);
1946
}
1947
1948
static void
1949
set80211inact(if_ctx *ctx, const char *val __unused, int d)
1950
{
1951
set80211(ctx, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
1952
}
1953
1954
static void
1955
set80211tsn(if_ctx *ctx, const char *val __unused, int d)
1956
{
1957
set80211(ctx, IEEE80211_IOC_TSN, d, 0, NULL);
1958
}
1959
1960
static void
1961
set80211dotd(if_ctx *ctx, const char *val __unused, int d)
1962
{
1963
set80211(ctx, IEEE80211_IOC_DOTD, d, 0, NULL);
1964
}
1965
1966
static void
1967
set80211smps(if_ctx *ctx, const char *val __unused, int d)
1968
{
1969
set80211(ctx, IEEE80211_IOC_SMPS, d, 0, NULL);
1970
}
1971
1972
static void
1973
set80211rifs(if_ctx *ctx, const char *val __unused, int d)
1974
{
1975
set80211(ctx, IEEE80211_IOC_RIFS, d, 0, NULL);
1976
}
1977
1978
static void
1979
set80211vhtconf(if_ctx *ctx, const char *val __unused, int d)
1980
{
1981
if (get80211val(ctx, IEEE80211_IOC_VHTCONF, &vhtconf) < 0)
1982
errx(-1, "cannot set VHT setting");
1983
if (d < 0) {
1984
d = -d;
1985
vhtconf &= ~d;
1986
} else
1987
vhtconf |= d;
1988
set80211(ctx, IEEE80211_IOC_VHTCONF, vhtconf, 0, NULL);
1989
}
1990
1991
static void
1992
set80211tdmaslot(if_ctx *ctx, const char *val, int dummy __unused)
1993
{
1994
set80211(ctx, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
1995
}
1996
1997
static void
1998
set80211tdmaslotcnt(if_ctx *ctx, const char *val, int dummy __unused)
1999
{
2000
set80211(ctx, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
2001
}
2002
2003
static void
2004
set80211tdmaslotlen(if_ctx *ctx, const char *val, int dummy __unused)
2005
{
2006
set80211(ctx, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
2007
}
2008
2009
static void
2010
set80211tdmabintval(if_ctx *ctx, const char *val, int dummy __unused)
2011
{
2012
set80211(ctx, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
2013
}
2014
2015
static void
2016
set80211meshttl(if_ctx *ctx, const char *val, int dummy __unused)
2017
{
2018
set80211(ctx, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
2019
}
2020
2021
static void
2022
set80211meshforward(if_ctx *ctx, const char *val __unused, int d)
2023
{
2024
set80211(ctx, IEEE80211_IOC_MESH_FWRD, d, 0, NULL);
2025
}
2026
2027
static void
2028
set80211meshgate(if_ctx *ctx, const char *val __unused, int d)
2029
{
2030
set80211(ctx, IEEE80211_IOC_MESH_GATE, d, 0, NULL);
2031
}
2032
2033
static void
2034
set80211meshpeering(if_ctx *ctx, const char *val __unused, int d)
2035
{
2036
set80211(ctx, IEEE80211_IOC_MESH_AP, d, 0, NULL);
2037
}
2038
2039
static void
2040
set80211meshmetric(if_ctx *ctx, const char *val, int dummy __unused)
2041
{
2042
char v[12];
2043
2044
memcpy(v, val, sizeof(v));
2045
set80211(ctx, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
2046
}
2047
2048
static void
2049
set80211meshpath(if_ctx *ctx, const char *val, int dummy __unused)
2050
{
2051
char v[12];
2052
2053
memcpy(v, val, sizeof(v));
2054
set80211(ctx, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
2055
}
2056
2057
static int
2058
regdomain_sort(const void *a, const void *b)
2059
{
2060
#define CHAN_ALL \
2061
(IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)
2062
const struct ieee80211_channel *ca = a;
2063
const struct ieee80211_channel *cb = b;
2064
2065
return ca->ic_freq == cb->ic_freq ?
2066
(int)(ca->ic_flags & CHAN_ALL) - (int)(cb->ic_flags & CHAN_ALL) :
2067
ca->ic_freq - cb->ic_freq;
2068
#undef CHAN_ALL
2069
}
2070
2071
static const struct ieee80211_channel *
2072
chanlookup(const struct ieee80211_channel chans[], int nchans,
2073
int freq, uint32_t flags)
2074
{
2075
int i;
2076
2077
flags &= IEEE80211_CHAN_ALLTURBO;
2078
for (i = 0; i < nchans; i++) {
2079
const struct ieee80211_channel *c = &chans[i];
2080
if (c->ic_freq == freq &&
2081
(c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
2082
return c;
2083
}
2084
return NULL;
2085
}
2086
2087
static int
2088
chanfind(const struct ieee80211_channel chans[], int nchans, uint32_t flags)
2089
{
2090
for (int i = 0; i < nchans; i++) {
2091
const struct ieee80211_channel *c = &chans[i];
2092
if ((c->ic_flags & flags) == flags)
2093
return 1;
2094
}
2095
return 0;
2096
}
2097
2098
/*
2099
* Check channel compatibility.
2100
*/
2101
static int
2102
checkchan(const struct ieee80211req_chaninfo *avail, int freq, uint32_t flags)
2103
{
2104
flags &= ~REQ_FLAGS;
2105
/*
2106
* Check if exact channel is in the calibration table;
2107
* everything below is to deal with channels that we
2108
* want to include but that are not explicitly listed.
2109
*/
2110
if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL)
2111
return 1;
2112
if (flags & IEEE80211_CHAN_GSM) {
2113
/*
2114
* XXX GSM frequency mapping is handled in the kernel
2115
* so we cannot find them in the calibration table;
2116
* just accept the channel and the kernel will reject
2117
* the channel list if it's wrong.
2118
*/
2119
return 1;
2120
}
2121
/*
2122
* If this is a 1/2 or 1/4 width channel allow it if a full
2123
* width channel is present for this frequency, and the device
2124
* supports fractional channels on this band. This is a hack
2125
* that avoids bloating the calibration table; it may be better
2126
* by per-band attributes though (we are effectively calculating
2127
* this attribute by scanning the channel list ourself).
2128
*/
2129
if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0)
2130
return 0;
2131
if (chanlookup(avail->ic_chans, avail->ic_nchans, freq,
2132
flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL)
2133
return 0;
2134
if (flags & IEEE80211_CHAN_HALF) {
2135
return chanfind(avail->ic_chans, avail->ic_nchans,
2136
IEEE80211_CHAN_HALF |
2137
(flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
2138
} else {
2139
return chanfind(avail->ic_chans, avail->ic_nchans,
2140
IEEE80211_CHAN_QUARTER |
2141
(flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
2142
}
2143
}
2144
2145
static void
2146
regdomain_addchans(if_ctx *ctx, struct ieee80211req_chaninfo *ci,
2147
const netband_head *bands,
2148
const struct ieee80211_regdomain *reg,
2149
uint32_t chanFlags,
2150
const struct ieee80211req_chaninfo *avail)
2151
{
2152
const struct netband *nb;
2153
const struct freqband *b;
2154
struct ieee80211_channel *c, *prev;
2155
int freq, hi_adj, lo_adj, channelSep;
2156
uint32_t flags;
2157
const int verbose = ctx->args->verbose;
2158
2159
hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
2160
lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
2161
channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
2162
2163
LIST_FOREACH(nb, bands, next) {
2164
b = nb->band;
2165
if (verbose) {
2166
printf("%s:", __func__);
2167
printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
2168
printb(" bandFlags", nb->flags | b->flags,
2169
IEEE80211_CHAN_BITS);
2170
putchar('\n');
2171
}
2172
prev = NULL;
2173
2174
for (freq = b->freqStart + lo_adj;
2175
freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
2176
/*
2177
* Construct flags for the new channel. We take
2178
* the attributes from the band descriptions except
2179
* for HT40 which is enabled generically (i.e. +/-
2180
* extension channel) in the band description and
2181
* then constrained according by channel separation.
2182
*/
2183
flags = nb->flags | b->flags;
2184
2185
/*
2186
* VHT first - HT is a subset.
2187
*/
2188
if (flags & IEEE80211_CHAN_VHT) {
2189
if ((chanFlags & IEEE80211_CHAN_VHT20) &&
2190
(flags & IEEE80211_CHAN_VHT20) == 0) {
2191
if (verbose)
2192
printf("%u: skip, not a "
2193
"VHT20 channel\n", freq);
2194
continue;
2195
}
2196
if ((chanFlags & IEEE80211_CHAN_VHT40) &&
2197
(flags & IEEE80211_CHAN_VHT40) == 0) {
2198
if (verbose)
2199
printf("%u: skip, not a "
2200
"VHT40 channel\n", freq);
2201
continue;
2202
}
2203
if ((chanFlags & IEEE80211_CHAN_VHT80) &&
2204
(flags & IEEE80211_CHAN_VHT80) == 0) {
2205
if (verbose)
2206
printf("%u: skip, not a "
2207
"VHT80 channel\n", freq);
2208
continue;
2209
}
2210
if ((chanFlags & IEEE80211_CHAN_VHT160) &&
2211
(flags & IEEE80211_CHAN_VHT160) == 0) {
2212
if (verbose)
2213
printf("%u: skip, not a "
2214
"VHT160 channel\n", freq);
2215
continue;
2216
}
2217
if ((chanFlags & IEEE80211_CHAN_VHT80P80) &&
2218
(flags & IEEE80211_CHAN_VHT80P80) == 0) {
2219
if (verbose)
2220
printf("%u: skip, not a "
2221
"VHT80+80 channel\n", freq);
2222
continue;
2223
}
2224
flags &= ~IEEE80211_CHAN_VHT;
2225
flags |= chanFlags & IEEE80211_CHAN_VHT;
2226
}
2227
2228
/* Now, constrain HT */
2229
if (flags & IEEE80211_CHAN_HT) {
2230
/*
2231
* HT channels are generated specially; we're
2232
* called to add HT20, HT40+, and HT40- chan's
2233
* so we need to expand only band specs for
2234
* the HT channel type being added.
2235
*/
2236
if ((chanFlags & IEEE80211_CHAN_HT20) &&
2237
(flags & IEEE80211_CHAN_HT20) == 0) {
2238
if (verbose)
2239
printf("%u: skip, not an "
2240
"HT20 channel\n", freq);
2241
continue;
2242
}
2243
if ((chanFlags & IEEE80211_CHAN_HT40) &&
2244
(flags & IEEE80211_CHAN_HT40) == 0) {
2245
if (verbose)
2246
printf("%u: skip, not an "
2247
"HT40 channel\n", freq);
2248
continue;
2249
}
2250
/* NB: HT attribute comes from caller */
2251
flags &= ~IEEE80211_CHAN_HT;
2252
flags |= chanFlags & IEEE80211_CHAN_HT;
2253
}
2254
/*
2255
* Check if device can operate on this frequency.
2256
*/
2257
if (!checkchan(avail, freq, flags)) {
2258
if (verbose) {
2259
printf("%u: skip, ", freq);
2260
printb("flags", flags,
2261
IEEE80211_CHAN_BITS);
2262
printf(" not available\n");
2263
}
2264
continue;
2265
}
2266
if ((flags & REQ_ECM) && !reg->ecm) {
2267
if (verbose)
2268
printf("%u: skip, ECM channel\n", freq);
2269
continue;
2270
}
2271
if ((flags & REQ_INDOOR) && reg->location == 'O') {
2272
if (verbose)
2273
printf("%u: skip, indoor channel\n",
2274
freq);
2275
continue;
2276
}
2277
if ((flags & REQ_OUTDOOR) && reg->location == 'I') {
2278
if (verbose)
2279
printf("%u: skip, outdoor channel\n",
2280
freq);
2281
continue;
2282
}
2283
if ((flags & IEEE80211_CHAN_HT40) &&
2284
prev != NULL && (freq - prev->ic_freq) < channelSep) {
2285
if (verbose)
2286
printf("%u: skip, only %u channel "
2287
"separation, need %d\n", freq,
2288
freq - prev->ic_freq, channelSep);
2289
continue;
2290
}
2291
if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
2292
if (verbose)
2293
printf("%u: skip, channel table full\n",
2294
freq);
2295
break;
2296
}
2297
c = &ci->ic_chans[ci->ic_nchans++];
2298
memset(c, 0, sizeof(*c));
2299
c->ic_freq = freq;
2300
c->ic_flags = flags;
2301
if (c->ic_flags & IEEE80211_CHAN_DFS)
2302
c->ic_maxregpower = nb->maxPowerDFS;
2303
else
2304
c->ic_maxregpower = nb->maxPower;
2305
if (verbose) {
2306
printf("[%3d] add freq %u ",
2307
ci->ic_nchans-1, c->ic_freq);
2308
printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
2309
printf(" power %u\n", c->ic_maxregpower);
2310
}
2311
/* NB: kernel fills in other fields */
2312
prev = c;
2313
}
2314
}
2315
}
2316
2317
static void
2318
regdomain_makechannels(
2319
if_ctx *ctx,
2320
struct ieee80211_regdomain_req *req,
2321
const struct ieee80211_devcaps_req *dc)
2322
{
2323
struct regdata *rdp = getregdata();
2324
const struct country *cc;
2325
const struct ieee80211_regdomain *reg = &req->rd;
2326
struct ieee80211req_chaninfo *ci = &req->chaninfo;
2327
const struct regdomain *rd;
2328
2329
/*
2330
* Locate construction table for new channel list. We treat
2331
* the regdomain/SKU as definitive so a country can be in
2332
* multiple with different properties (e.g. US in FCC+FCC3).
2333
* If no regdomain is specified then we fallback on the country
2334
* code to find the associated regdomain since countries always
2335
* belong to at least one regdomain.
2336
*/
2337
if (reg->regdomain == 0) {
2338
cc = lib80211_country_findbycc(rdp, reg->country);
2339
if (cc == NULL)
2340
errx(1, "internal error, country %d not found",
2341
reg->country);
2342
rd = cc->rd;
2343
} else
2344
rd = lib80211_regdomain_findbysku(rdp, reg->regdomain);
2345
if (rd == NULL)
2346
errx(1, "internal error, regdomain %d not found",
2347
reg->regdomain);
2348
if (rd->sku != SKU_DEBUG) {
2349
/*
2350
* regdomain_addchans incrememnts the channel count for
2351
* each channel it adds so initialize ic_nchans to zero.
2352
* Note that we know we have enough space to hold all possible
2353
* channels because the devcaps list size was used to
2354
* allocate our request.
2355
*/
2356
ci->ic_nchans = 0;
2357
if (!LIST_EMPTY(&rd->bands_11b))
2358
regdomain_addchans(ctx, ci, &rd->bands_11b, reg,
2359
IEEE80211_CHAN_B, &dc->dc_chaninfo);
2360
if (!LIST_EMPTY(&rd->bands_11g))
2361
regdomain_addchans(ctx, ci, &rd->bands_11g, reg,
2362
IEEE80211_CHAN_G, &dc->dc_chaninfo);
2363
if (!LIST_EMPTY(&rd->bands_11a))
2364
regdomain_addchans(ctx, ci, &rd->bands_11a, reg,
2365
IEEE80211_CHAN_A, &dc->dc_chaninfo);
2366
if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) {
2367
regdomain_addchans(ctx, ci, &rd->bands_11na, reg,
2368
IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
2369
&dc->dc_chaninfo);
2370
if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2371
regdomain_addchans(ctx, ci, &rd->bands_11na, reg,
2372
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,
2373
&dc->dc_chaninfo);
2374
regdomain_addchans(ctx, ci, &rd->bands_11na, reg,
2375
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,
2376
&dc->dc_chaninfo);
2377
}
2378
}
2379
if (!LIST_EMPTY(&rd->bands_11ac) && dc->dc_vhtcaps != 0) {
2380
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2381
IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 |
2382
IEEE80211_CHAN_VHT20,
2383
&dc->dc_chaninfo);
2384
2385
/* VHT40 is a function of HT40.. */
2386
if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2387
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2388
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
2389
IEEE80211_CHAN_VHT40U,
2390
&dc->dc_chaninfo);
2391
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2392
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
2393
IEEE80211_CHAN_VHT40D,
2394
&dc->dc_chaninfo);
2395
}
2396
2397
/* VHT80 is mandatory (and so should be VHT40 above). */
2398
if (1) {
2399
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2400
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
2401
IEEE80211_CHAN_VHT80,
2402
&dc->dc_chaninfo);
2403
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2404
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
2405
IEEE80211_CHAN_VHT80,
2406
&dc->dc_chaninfo);
2407
}
2408
2409
/* VHT160 */
2410
if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(
2411
dc->dc_vhtcaps)) {
2412
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2413
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
2414
IEEE80211_CHAN_VHT160,
2415
&dc->dc_chaninfo);
2416
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2417
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
2418
IEEE80211_CHAN_VHT160,
2419
&dc->dc_chaninfo);
2420
}
2421
2422
/* VHT80P80 */
2423
if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(
2424
dc->dc_vhtcaps)) {
2425
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2426
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
2427
IEEE80211_CHAN_VHT80P80,
2428
&dc->dc_chaninfo);
2429
regdomain_addchans(ctx, ci, &rd->bands_11ac, reg,
2430
IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
2431
IEEE80211_CHAN_VHT80P80,
2432
&dc->dc_chaninfo);
2433
}
2434
}
2435
2436
if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
2437
regdomain_addchans(ctx, ci, &rd->bands_11ng, reg,
2438
IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
2439
&dc->dc_chaninfo);
2440
if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
2441
regdomain_addchans(ctx, ci, &rd->bands_11ng, reg,
2442
IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,
2443
&dc->dc_chaninfo);
2444
regdomain_addchans(ctx, ci, &rd->bands_11ng, reg,
2445
IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,
2446
&dc->dc_chaninfo);
2447
}
2448
}
2449
qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
2450
regdomain_sort);
2451
} else
2452
memcpy(ci, &dc->dc_chaninfo,
2453
IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
2454
}
2455
2456
static void
2457
list_countries(void)
2458
{
2459
struct regdata *rdp = getregdata();
2460
const struct country *cp;
2461
const struct regdomain *dp;
2462
int i;
2463
2464
i = 0;
2465
printf("\nCountry codes:\n");
2466
LIST_FOREACH(cp, &rdp->countries, next) {
2467
printf("%2s %-15.15s%s", cp->isoname,
2468
cp->name, ((i+1)%4) == 0 ? "\n" : " ");
2469
i++;
2470
}
2471
i = 0;
2472
printf("\nRegulatory domains:\n");
2473
LIST_FOREACH(dp, &rdp->domains, next) {
2474
printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " ");
2475
i++;
2476
}
2477
printf("\n");
2478
}
2479
2480
static void
2481
defaultcountry(const struct regdomain *rd)
2482
{
2483
struct regdata *rdp = getregdata();
2484
const struct country *cc;
2485
2486
cc = lib80211_country_findbycc(rdp, rd->cc->code);
2487
if (cc == NULL)
2488
errx(1, "internal error, ISO country code %d not "
2489
"defined for regdomain %s", rd->cc->code, rd->name);
2490
regdomain.country = cc->code;
2491
regdomain.isocc[0] = cc->isoname[0];
2492
regdomain.isocc[1] = cc->isoname[1];
2493
}
2494
2495
static void
2496
set80211regdomain(if_ctx *ctx, const char *val, int dummy __unused)
2497
{
2498
struct regdata *rdp = getregdata();
2499
const struct regdomain *rd;
2500
2501
rd = lib80211_regdomain_findbyname(rdp, val);
2502
if (rd == NULL) {
2503
char *eptr;
2504
long sku = strtol(val, &eptr, 0);
2505
2506
if (eptr != val)
2507
rd = lib80211_regdomain_findbysku(rdp, sku);
2508
if (eptr == val || rd == NULL)
2509
errx(1, "unknown regdomain %s", val);
2510
}
2511
getregdomain(ctx);
2512
regdomain.regdomain = rd->sku;
2513
if (regdomain.country == 0 && rd->cc != NULL) {
2514
/*
2515
* No country code setup and there's a default
2516
* one for this regdomain fill it in.
2517
*/
2518
defaultcountry(rd);
2519
}
2520
callback_register(setregdomain_cb, &regdomain);
2521
}
2522
2523
static void
2524
set80211country(if_ctx *ctx, const char *val, int dummy __unused)
2525
{
2526
struct regdata *rdp = getregdata();
2527
const struct country *cc;
2528
2529
cc = lib80211_country_findbyname(rdp, val);
2530
if (cc == NULL) {
2531
char *eptr;
2532
long code = strtol(val, &eptr, 0);
2533
2534
if (eptr != val)
2535
cc = lib80211_country_findbycc(rdp, code);
2536
if (eptr == val || cc == NULL)
2537
errx(1, "unknown ISO country code %s", val);
2538
}
2539
getregdomain(ctx);
2540
regdomain.regdomain = cc->rd->sku;
2541
regdomain.country = cc->code;
2542
regdomain.isocc[0] = cc->isoname[0];
2543
regdomain.isocc[1] = cc->isoname[1];
2544
callback_register(setregdomain_cb, &regdomain);
2545
}
2546
2547
static void
2548
set80211location(if_ctx *ctx, const char *val __unused, int d)
2549
{
2550
getregdomain(ctx);
2551
regdomain.location = d;
2552
callback_register(setregdomain_cb, &regdomain);
2553
}
2554
2555
static void
2556
set80211ecm(if_ctx *ctx, const char *val __unused, int d)
2557
{
2558
getregdomain(ctx);
2559
regdomain.ecm = d;
2560
callback_register(setregdomain_cb, &regdomain);
2561
}
2562
2563
static void
2564
LINE_INIT(char c)
2565
{
2566
spacer = c;
2567
if (c == '\t')
2568
col = 8;
2569
else
2570
col = 1;
2571
}
2572
2573
static void
2574
LINE_BREAK(void)
2575
{
2576
if (spacer != '\t') {
2577
printf("\n");
2578
spacer = '\t';
2579
}
2580
col = 8; /* 8-col tab */
2581
}
2582
2583
static void
2584
LINE_CHECK(const char *fmt, ...)
2585
{
2586
char buf[80];
2587
va_list ap;
2588
int n;
2589
2590
va_start(ap, fmt);
2591
n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
2592
va_end(ap);
2593
col += 1+n;
2594
if (col > MAXCOL) {
2595
LINE_BREAK();
2596
col += n;
2597
}
2598
buf[0] = spacer;
2599
printf("%s", buf);
2600
spacer = ' ';
2601
}
2602
2603
static int
2604
getmaxrate(const uint8_t rates[15], uint8_t nrates)
2605
{
2606
int i, maxrate = -1;
2607
2608
for (i = 0; i < nrates; i++) {
2609
int rate = rates[i] & IEEE80211_RATE_VAL;
2610
if (rate > maxrate)
2611
maxrate = rate;
2612
}
2613
return maxrate / 2;
2614
}
2615
2616
static const char *
2617
getcaps(int capinfo)
2618
{
2619
static char capstring[32];
2620
char *cp = capstring;
2621
2622
if (capinfo & IEEE80211_CAPINFO_ESS)
2623
*cp++ = 'E';
2624
if (capinfo & IEEE80211_CAPINFO_IBSS)
2625
*cp++ = 'I';
2626
if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
2627
*cp++ = 'c';
2628
if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
2629
*cp++ = 'C';
2630
if (capinfo & IEEE80211_CAPINFO_PRIVACY)
2631
*cp++ = 'P';
2632
if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
2633
*cp++ = 'S';
2634
if (capinfo & IEEE80211_CAPINFO_PBCC)
2635
*cp++ = 'B';
2636
if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
2637
*cp++ = 'A';
2638
if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
2639
*cp++ = 's';
2640
if (capinfo & IEEE80211_CAPINFO_RSN)
2641
*cp++ = 'R';
2642
if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
2643
*cp++ = 'D';
2644
*cp = '\0';
2645
return capstring;
2646
}
2647
2648
static const char *
2649
getflags(int flags)
2650
{
2651
static char flagstring[32];
2652
char *cp = flagstring;
2653
2654
if (flags & IEEE80211_NODE_AUTH)
2655
*cp++ = 'A';
2656
if (flags & IEEE80211_NODE_QOS)
2657
*cp++ = 'Q';
2658
if (flags & IEEE80211_NODE_ERP)
2659
*cp++ = 'E';
2660
if (flags & IEEE80211_NODE_PWR_MGT)
2661
*cp++ = 'P';
2662
if (flags & IEEE80211_NODE_HT) {
2663
*cp++ = 'H';
2664
if (flags & IEEE80211_NODE_HTCOMPAT)
2665
*cp++ = '+';
2666
}
2667
if (flags & IEEE80211_NODE_VHT)
2668
*cp++ = 'V';
2669
if (flags & IEEE80211_NODE_WPS)
2670
*cp++ = 'W';
2671
if (flags & IEEE80211_NODE_TSN)
2672
*cp++ = 'N';
2673
if (flags & IEEE80211_NODE_AMPDU_TX)
2674
*cp++ = 'T';
2675
if (flags & IEEE80211_NODE_AMPDU_RX)
2676
*cp++ = 'R';
2677
if (flags & IEEE80211_NODE_MIMO_PS) {
2678
*cp++ = 'M';
2679
if (flags & IEEE80211_NODE_MIMO_RTS)
2680
*cp++ = '+';
2681
}
2682
if (flags & IEEE80211_NODE_RIFS)
2683
*cp++ = 'I';
2684
if (flags & IEEE80211_NODE_SGI40) {
2685
*cp++ = 'S';
2686
if (flags & IEEE80211_NODE_SGI20)
2687
*cp++ = '+';
2688
} else if (flags & IEEE80211_NODE_SGI20)
2689
*cp++ = 's';
2690
if (flags & IEEE80211_NODE_AMSDU_TX)
2691
*cp++ = 't';
2692
if (flags & IEEE80211_NODE_AMSDU_RX)
2693
*cp++ = 'r';
2694
if (flags & IEEE80211_NODE_UAPSD)
2695
*cp++ = 'U';
2696
if (flags & IEEE80211_NODE_LDPC)
2697
*cp++ = 'L';
2698
*cp = '\0';
2699
return flagstring;
2700
}
2701
2702
static void
2703
printie(if_ctx *ctx, const char* tag, const uint8_t *ie, size_t ielen, unsigned int maxlen)
2704
{
2705
printf("%s", tag);
2706
if (ctx->args->verbose) {
2707
maxlen -= strlen(tag)+2;
2708
if (2*ielen > maxlen)
2709
maxlen--;
2710
printf("<");
2711
for (; ielen > 0; ie++, ielen--) {
2712
if (maxlen-- <= 0)
2713
break;
2714
printf("%02x", *ie);
2715
}
2716
if (ielen != 0)
2717
printf("-");
2718
printf(">");
2719
}
2720
}
2721
2722
#define LE_READ_2(p) \
2723
((u_int16_t) \
2724
((((const u_int8_t *)(p))[0] ) | \
2725
(((const u_int8_t *)(p))[1] << 8)))
2726
#define LE_READ_4(p) \
2727
((u_int32_t) \
2728
((((const u_int8_t *)(p))[0] ) | \
2729
(((const u_int8_t *)(p))[1] << 8) | \
2730
(((const u_int8_t *)(p))[2] << 16) | \
2731
(((const u_int8_t *)(p))[3] << 24)))
2732
2733
/*
2734
* NB: The decoding routines assume a properly formatted ie
2735
* which should be safe as the kernel only retains them
2736
* if they parse ok.
2737
*/
2738
2739
static void
2740
printwmeparam(if_ctx *ctx, const char *tag, const u_int8_t *ie)
2741
{
2742
static const char *acnames[] = { "BE", "BK", "VO", "VI" };
2743
const struct ieee80211_wme_param *wme =
2744
(const struct ieee80211_wme_param *) ie;
2745
int i;
2746
2747
printf("%s", tag);
2748
if (!ctx->args->verbose)
2749
return;
2750
printf("<qosinfo 0x%x", wme->param_qosInfo);
2751
ie += offsetof(struct ieee80211_wme_param, params_acParams);
2752
for (i = 0; i < WME_NUM_AC; i++) {
2753
const struct ieee80211_wme_acparams *ac =
2754
&wme->params_acParams[i];
2755
2756
printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]", acnames[i],
2757
_IEEE80211_MASKSHIFT(ac->acp_aci_aifsn, WME_PARAM_ACM) ?
2758
"acm " : "",
2759
_IEEE80211_MASKSHIFT(ac->acp_aci_aifsn, WME_PARAM_AIFSN),
2760
_IEEE80211_MASKSHIFT(ac->acp_logcwminmax,
2761
WME_PARAM_LOGCWMIN),
2762
_IEEE80211_MASKSHIFT(ac->acp_logcwminmax,
2763
WME_PARAM_LOGCWMAX),
2764
LE_READ_2(&ac->acp_txop));
2765
}
2766
printf(">");
2767
}
2768
2769
static void
2770
printwmeinfo(if_ctx *ctx, const char *tag, const u_int8_t *ie)
2771
{
2772
printf("%s", tag);
2773
if (ctx->args->verbose) {
2774
const struct ieee80211_wme_info *wme =
2775
(const struct ieee80211_wme_info *) ie;
2776
printf("<version 0x%x info 0x%x>",
2777
wme->wme_version, wme->wme_info);
2778
}
2779
}
2780
2781
static void
2782
printhecap(if_ctx *ctx, const char *tag, const uint8_t *ie)
2783
{
2784
const struct ieee80211_he_cap_elem *hecap;
2785
const struct ieee80211_he_mcs_nss_supp *mcsnss;
2786
unsigned int i;
2787
uint8_t chw;
2788
2789
printf("%s", tag);
2790
if (!ctx->args->verbose)
2791
return;
2792
2793
/* Check that the right size. */
2794
if (ie[1] < 1 + sizeof(*hecap) + 4) {
2795
printf("<err: he_cap inval. length %#0x>", ie[1]);
2796
return;
2797
}
2798
/* Skip Element ID, Length, EID Extension. */
2799
hecap = (const struct ieee80211_he_cap_elem *)(ie + 3);
2800
2801
/* XXX-BZ we need to somehow decode each field? */
2802
printf("<mac_cap");
2803
for (i = 0; i < nitems(hecap->mac_cap_info); i++)
2804
printf(" %#04x", hecap->mac_cap_info[i]);
2805
printf(" phy_cap");
2806
for (i = 0; i < nitems(hecap->phy_cap_info); i++)
2807
printf(" %#04x", hecap->phy_cap_info[i]);
2808
2809
chw = hecap->phy_cap_info[0];
2810
ie = (const uint8_t *)(const void *)(hecap + 1);
2811
mcsnss = (const struct ieee80211_he_mcs_nss_supp *)ie;
2812
/* Cannot use <= as < is a delimiter. */
2813
printf(" rx/tx_he_mcs map: loweq80 %#06x/%#06x",
2814
mcsnss->rx_mcs_80, mcsnss->tx_mcs_80);
2815
ie += 2;
2816
if ((chw & (1<<2)) != 0) {
2817
printf(" 160 %#06x/%#06x",
2818
mcsnss->rx_mcs_160, mcsnss->tx_mcs_160);
2819
ie += 2;
2820
}
2821
if ((chw & (1<<3)) != 0) {
2822
printf(" 80+80 %#06x/%#06x",
2823
mcsnss->rx_mcs_80p80, mcsnss->tx_mcs_80p80);
2824
ie += 2;
2825
}
2826
/* TODO: ppet = (struct ... *)ie; */
2827
2828
printf(">");
2829
}
2830
2831
static void
2832
printheoper(if_ctx *ctx, const char *tag, const uint8_t *ie)
2833
{
2834
printf("%s", tag);
2835
if (ctx->args->verbose) {
2836
const struct ieee80211_he_operation *heoper;
2837
uint32_t params;
2838
2839
/* Check that the right size. */
2840
if (ie[1] < 1 + sizeof(*heoper)) {
2841
printf("<err: he_oper inval. length %#0x>", ie[1]);
2842
return;
2843
}
2844
/* Skip Element ID, Length, EID Extension. */
2845
heoper = (const struct ieee80211_he_operation *)(ie + 3);
2846
2847
/* XXX-BZ we need to somehow decode each field? */
2848
params = heoper->he_oper_params & 0x00ffffff;
2849
printf("<params %#08x", params);
2850
printf(" bss_col %#04x", (heoper->he_oper_params & 0xff000000) >> 24);
2851
printf(" mcs_nss %#06x", heoper->he_mcs_nss_set);
2852
if ((params & (1 << 14)) != 0) {
2853
printf(" vht_op 0-3");
2854
}
2855
if ((params & (1 << 15)) != 0) {
2856
printf(" max_coh_bssid 0-1");
2857
}
2858
if ((params & (1 << 17)) != 0) {
2859
printf(" 6ghz_op 0-5");
2860
}
2861
printf(">");
2862
}
2863
}
2864
2865
static void
2866
printmuedcaparamset(if_ctx *ctx, const char *tag, const uint8_t *ie)
2867
{
2868
static const char *acnames[] = { "BE", "BK", "VO", "VI" };
2869
const struct ieee80211_mu_edca_param_set *mu_edca;
2870
int i;
2871
2872
printf("%s", tag);
2873
if (!ctx->args->verbose)
2874
return;
2875
2876
/* Check that the right size. */
2877
if (ie[1] != 1 + sizeof(*mu_edca)) {
2878
printf("<err: mu_edca inval. length %#04x>", ie[1]);
2879
return;
2880
}
2881
/* Skip Element ID, Length, EID Extension. */
2882
mu_edca = (const struct ieee80211_mu_edca_param_set *)(ie + 3);
2883
2884
printf("<qosinfo 0x%x", mu_edca->mu_qos_info);
2885
ie++;
2886
for (i = 0; i < WME_NUM_AC; i++) {
2887
const struct ieee80211_he_mu_edca_param_ac_rec *ac =
2888
&mu_edca->param_ac_recs[i];
2889
2890
printf(" %s[aifsn %u ecwmin %u ecwmax %u timer %u]", acnames[i],
2891
ac->aifsn,
2892
_IEEE80211_MASKSHIFT(ac->ecw_min_max, WME_PARAM_LOGCWMIN),
2893
_IEEE80211_MASKSHIFT(ac->ecw_min_max, WME_PARAM_LOGCWMAX),
2894
ac->mu_edca_timer);
2895
}
2896
printf(">");
2897
}
2898
2899
static void
2900
printsupopclass(if_ctx *ctx, const char *tag, const u_int8_t *ie)
2901
{
2902
uint8_t len, i;
2903
2904
printf("%s", tag);
2905
if (!ctx->args->verbose)
2906
return;
2907
2908
/* Check that the right size. */
2909
len = ie[1];
2910
if (len < 2) {
2911
printf("<err: sup_op_class inval. length %#04x>", ie[1]);
2912
return;
2913
}
2914
2915
ie += 2;
2916
i = 0;
2917
printf("<cur op class %u", *ie);
2918
i++;
2919
if (i < len && *(ie + i) != 130)
2920
printf(" op classes");
2921
while (i < len && *(ie + i) != 130) {
2922
printf(" %u", *(ie + i));
2923
i++;
2924
}
2925
if (i > 1 && i < len && *(ie + i) != 130) {
2926
printf(" parsing error at %#0x>", i);
2927
return;
2928
}
2929
/* Skip OneHundredAndThirty Delimiter. */
2930
i++;
2931
if (i < len && *(ie + i) != 0)
2932
printf(" ext seq");
2933
while (i < len && *(ie + i) != 0) {
2934
printf(" %u", *(ie + i));
2935
i++;
2936
}
2937
if (i > 1 && i < len && *(ie + i) != 0) {
2938
printf(" parsing error at %#0x>", i);
2939
return;
2940
}
2941
/* Skip Zero Delimiter. */
2942
i++;
2943
if ((i + 1) < len)
2944
printf(" duple seq");
2945
while ((i + 1) < len) {
2946
printf(" %u/%u", *(ie + i), *(ie + i + 1));
2947
i += 2;
2948
}
2949
printf(">");
2950
}
2951
2952
static void
2953
printvhtcap(if_ctx *ctx, const char *tag, const u_int8_t *ie)
2954
{
2955
printf("%s", tag);
2956
if (ctx->args->verbose) {
2957
const struct ieee80211_vht_cap *vhtcap;
2958
uint32_t vhtcap_info;
2959
2960
/* Check that the right size. */
2961
if (ie[1] != sizeof(*vhtcap)) {
2962
printf("<err: vht_cap inval. length>");
2963
return;
2964
}
2965
/* Skip Element ID and Length. */
2966
vhtcap = (const struct ieee80211_vht_cap *)(ie + 2);
2967
2968
vhtcap_info = LE_READ_4(&vhtcap->vht_cap_info);
2969
printf("<cap 0x%08x", vhtcap_info);
2970
printf(" rx_mcs_map 0x%x",
2971
LE_READ_2(&vhtcap->supp_mcs.rx_mcs_map));
2972
printf(" rx_highest %d",
2973
LE_READ_2(&vhtcap->supp_mcs.rx_highest) & 0x1fff);
2974
printf(" tx_mcs_map 0x%x",
2975
LE_READ_2(&vhtcap->supp_mcs.tx_mcs_map));
2976
printf(" tx_highest %d",
2977
LE_READ_2(&vhtcap->supp_mcs.tx_highest) & 0x1fff);
2978
2979
printf(">");
2980
}
2981
}
2982
2983
static void
2984
printvhtinfo(if_ctx *ctx, const char *tag, const u_int8_t *ie)
2985
{
2986
printf("%s", tag);
2987
if (ctx->args->verbose) {
2988
const struct ieee80211_vht_operation *vhtinfo;
2989
2990
/* Check that the right size. */
2991
if (ie[1] != sizeof(*vhtinfo)) {
2992
printf("<err: vht_operation inval. length>");
2993
return;
2994
}
2995
/* Skip Element ID and Length. */
2996
vhtinfo = (const struct ieee80211_vht_operation *)(ie + 2);
2997
2998
printf("<chw %d freq0_idx %d freq1_idx %d basic_mcs_set 0x%04x>",
2999
vhtinfo->chan_width,
3000
vhtinfo->center_freq_seq0_idx,
3001
vhtinfo->center_freq_seq1_idx,
3002
LE_READ_2(&vhtinfo->basic_mcs_set));
3003
}
3004
}
3005
3006
static void
3007
printvhtpwrenv(if_ctx *ctx, const char *tag, const u_int8_t *ie, size_t ielen)
3008
{
3009
printf("%s", tag);
3010
static const char *txpwrmap[] = {
3011
"20",
3012
"40",
3013
"80",
3014
"160",
3015
};
3016
if (ctx->args->verbose) {
3017
const struct ieee80211_ie_vht_txpwrenv *vhtpwr =
3018
(const struct ieee80211_ie_vht_txpwrenv *) ie;
3019
size_t i, n;
3020
const char *sep = "";
3021
3022
/* Get count; trim at ielen */
3023
n = (vhtpwr->tx_info &
3024
IEEE80211_VHT_TXPWRENV_INFO_COUNT_MASK) + 1;
3025
/* Trim at ielen */
3026
if (n + 3 > ielen)
3027
n = ielen - 3;
3028
printf("<tx_info 0x%02x pwr:[", vhtpwr->tx_info);
3029
for (i = 0; i < n; i++) {
3030
printf("%s%s:%.2f", sep, txpwrmap[i],
3031
((float) ((int8_t) ie[i+3])) / 2.0);
3032
sep = " ";
3033
}
3034
3035
printf("]>");
3036
}
3037
}
3038
3039
static void
3040
printhtcap(if_ctx *ctx, const char *tag, const u_int8_t *ie)
3041
{
3042
printf("%s", tag);
3043
if (ctx->args->verbose) {
3044
const struct ieee80211_ie_htcap *htcap =
3045
(const struct ieee80211_ie_htcap *) ie;
3046
const char *sep;
3047
int i, j;
3048
3049
printf("<cap 0x%x param 0x%x",
3050
LE_READ_2(&htcap->hc_cap), htcap->hc_param);
3051
printf(" mcsset[");
3052
sep = "";
3053
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
3054
if (isset(htcap->hc_mcsset, i)) {
3055
for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
3056
if (isclr(htcap->hc_mcsset, j))
3057
break;
3058
j--;
3059
if (i == j)
3060
printf("%s%u", sep, i);
3061
else
3062
printf("%s%u-%u", sep, i, j);
3063
i += j-i;
3064
sep = ",";
3065
}
3066
printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
3067
LE_READ_2(&htcap->hc_extcap),
3068
LE_READ_4(&htcap->hc_txbf),
3069
htcap->hc_antenna);
3070
}
3071
}
3072
3073
static void
3074
printhtinfo(if_ctx *ctx, const char *tag, const u_int8_t *ie)
3075
{
3076
printf("%s", tag);
3077
if (ctx->args->verbose) {
3078
const struct ieee80211_ie_htinfo *htinfo =
3079
(const struct ieee80211_ie_htinfo *) ie;
3080
const char *sep;
3081
int i, j;
3082
3083
printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
3084
htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
3085
LE_READ_2(&htinfo->hi_byte45));
3086
printf(" basicmcs[");
3087
sep = "";
3088
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
3089
if (isset(htinfo->hi_basicmcsset, i)) {
3090
for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
3091
if (isclr(htinfo->hi_basicmcsset, j))
3092
break;
3093
j--;
3094
if (i == j)
3095
printf("%s%u", sep, i);
3096
else
3097
printf("%s%u-%u", sep, i, j);
3098
i += j-i;
3099
sep = ",";
3100
}
3101
printf("]>");
3102
}
3103
}
3104
3105
static void
3106
printathie(if_ctx *ctx, const char *tag, const u_int8_t *ie)
3107
{
3108
3109
printf("%s", tag);
3110
if (ctx->args->verbose) {
3111
const struct ieee80211_ath_ie *ath =
3112
(const struct ieee80211_ath_ie *)ie;
3113
3114
printf("<");
3115
if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
3116
printf("DTURBO,");
3117
if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
3118
printf("COMP,");
3119
if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
3120
printf("FF,");
3121
if (ath->ath_capability & ATHEROS_CAP_XR)
3122
printf("XR,");
3123
if (ath->ath_capability & ATHEROS_CAP_AR)
3124
printf("AR,");
3125
if (ath->ath_capability & ATHEROS_CAP_BURST)
3126
printf("BURST,");
3127
if (ath->ath_capability & ATHEROS_CAP_WME)
3128
printf("WME,");
3129
if (ath->ath_capability & ATHEROS_CAP_BOOST)
3130
printf("BOOST,");
3131
printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
3132
}
3133
}
3134
3135
3136
static void
3137
printmeshconf(if_ctx *ctx, const char *tag, const uint8_t *ie)
3138
{
3139
3140
printf("%s", tag);
3141
if (ctx->args->verbose) {
3142
const struct ieee80211_meshconf_ie *mconf =
3143
(const struct ieee80211_meshconf_ie *)ie;
3144
printf("<PATH:");
3145
if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP)
3146
printf("HWMP");
3147
else
3148
printf("UNKNOWN");
3149
printf(" LINK:");
3150
if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME)
3151
printf("AIRTIME");
3152
else
3153
printf("UNKNOWN");
3154
printf(" CONGESTION:");
3155
if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED)
3156
printf("DISABLED");
3157
else
3158
printf("UNKNOWN");
3159
printf(" SYNC:");
3160
if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF)
3161
printf("NEIGHOFF");
3162
else
3163
printf("UNKNOWN");
3164
printf(" AUTH:");
3165
if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED)
3166
printf("DISABLED");
3167
else
3168
printf("UNKNOWN");
3169
printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
3170
mconf->conf_cap);
3171
}
3172
}
3173
3174
static void
3175
printbssload(if_ctx *ctx, const char *tag, const uint8_t *ie)
3176
{
3177
printf("%s", tag);
3178
if (ctx->args->verbose) {
3179
const struct ieee80211_bss_load_ie *bssload =
3180
(const struct ieee80211_bss_load_ie *) ie;
3181
printf("<sta count %d, chan load %d, aac %d>",
3182
LE_READ_2(&bssload->sta_count),
3183
bssload->chan_load,
3184
bssload->aac);
3185
}
3186
}
3187
3188
static void
3189
printapchanrep(if_ctx *ctx, const char *tag, const u_int8_t *ie, size_t ielen)
3190
{
3191
printf("%s", tag);
3192
if (ctx->args->verbose) {
3193
const struct ieee80211_ap_chan_report_ie *ap =
3194
(const struct ieee80211_ap_chan_report_ie *) ie;
3195
const char *sep = "";
3196
3197
printf("<class %u, chan:[", ap->i_class);
3198
3199
for (size_t i = 3; i < ielen; i++) {
3200
printf("%s%u", sep, ie[i]);
3201
sep = ",";
3202
}
3203
printf("]>");
3204
}
3205
}
3206
3207
static const char *
3208
wpa_cipher(const u_int8_t *sel)
3209
{
3210
#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
3211
u_int32_t w = LE_READ_4(sel);
3212
3213
switch (w) {
3214
case WPA_SEL(WPA_CSE_NULL):
3215
return "NONE";
3216
case WPA_SEL(WPA_CSE_WEP40):
3217
return "WEP40";
3218
case WPA_SEL(WPA_CSE_WEP104):
3219
return "WEP104";
3220
case WPA_SEL(WPA_CSE_TKIP):
3221
return "TKIP";
3222
case WPA_SEL(WPA_CSE_CCMP):
3223
return "AES-CCMP";
3224
}
3225
return "?"; /* NB: so 1<< is discarded */
3226
#undef WPA_SEL
3227
}
3228
3229
static const char *
3230
wpa_keymgmt(const u_int8_t *sel)
3231
{
3232
#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
3233
u_int32_t w = LE_READ_4(sel);
3234
3235
switch (w) {
3236
case WPA_SEL(WPA_ASE_8021X_UNSPEC):
3237
return "8021X-UNSPEC";
3238
case WPA_SEL(WPA_ASE_8021X_PSK):
3239
return "8021X-PSK";
3240
case WPA_SEL(WPA_ASE_NONE):
3241
return "NONE";
3242
}
3243
return "?";
3244
#undef WPA_SEL
3245
}
3246
3247
static void
3248
printwpaie(if_ctx *ctx, const char *tag, const u_int8_t *ie)
3249
{
3250
u_int8_t len = ie[1];
3251
3252
printf("%s", tag);
3253
if (ctx->args->verbose) {
3254
const char *sep;
3255
int n;
3256
3257
ie += 6, len -= 4; /* NB: len is payload only */
3258
3259
printf("<v%u", LE_READ_2(ie));
3260
ie += 2, len -= 2;
3261
3262
printf(" mc:%s", wpa_cipher(ie));
3263
ie += 4, len -= 4;
3264
3265
/* unicast ciphers */
3266
n = LE_READ_2(ie);
3267
ie += 2, len -= 2;
3268
sep = " uc:";
3269
for (; n > 0; n--) {
3270
printf("%s%s", sep, wpa_cipher(ie));
3271
ie += 4, len -= 4;
3272
sep = "+";
3273
}
3274
3275
/* key management algorithms */
3276
n = LE_READ_2(ie);
3277
ie += 2, len -= 2;
3278
sep = " km:";
3279
for (; n > 0; n--) {
3280
printf("%s%s", sep, wpa_keymgmt(ie));
3281
ie += 4, len -= 4;
3282
sep = "+";
3283
}
3284
3285
if (len > 2) /* optional capabilities */
3286
printf(", caps 0x%x", LE_READ_2(ie));
3287
printf(">");
3288
}
3289
}
3290
3291
static const char *
3292
rsn_cipher(const u_int8_t *sel)
3293
{
3294
#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
3295
u_int32_t w = LE_READ_4(sel);
3296
3297
switch (w) {
3298
case RSN_SEL(RSN_CSE_NULL):
3299
return "NONE";
3300
case RSN_SEL(RSN_CSE_WEP40):
3301
return "WEP40";
3302
case RSN_SEL(RSN_CSE_WEP104):
3303
return "WEP104";
3304
case RSN_SEL(RSN_CSE_TKIP):
3305
return "TKIP";
3306
case RSN_SEL(RSN_CSE_CCMP):
3307
return "AES-CCMP";
3308
case RSN_SEL(RSN_CSE_WRAP):
3309
return "AES-OCB";
3310
case RSN_SEL(RSN_CSE_GCMP_128):
3311
return "AES-GCMP";
3312
case RSN_SEL(RSN_CSE_CCMP_256):
3313
return "AES-CCMP-256";
3314
case RSN_SEL(RSN_CSE_GCMP_256):
3315
return "AES-GCMP-256";
3316
}
3317
return "?";
3318
#undef WPA_SEL
3319
}
3320
3321
static const char *
3322
rsn_keymgmt(const u_int8_t *sel)
3323
{
3324
#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
3325
u_int32_t w = LE_READ_4(sel);
3326
3327
switch (w) {
3328
case RSN_SEL(RSN_ASE_8021X_UNSPEC):
3329
return "8021X-UNSPEC";
3330
case RSN_SEL(RSN_ASE_8021X_PSK):
3331
return "8021X-PSK";
3332
case RSN_SEL(RSN_ASE_8021X_UNSPEC_SHA256):
3333
return "8021X-UNSPEC-SHA256";
3334
case RSN_SEL(RSN_ASE_8021X_PSK_SHA256):
3335
return "8021X-PSK-256";
3336
case RSN_SEL(RSN_ASE_NONE):
3337
return "NONE";
3338
}
3339
return "?";
3340
#undef RSN_SEL
3341
}
3342
3343
static void
3344
printrsnie(if_ctx *ctx, const char *tag, const u_int8_t *ie, size_t ielen)
3345
{
3346
printf("%s", tag);
3347
if (ctx->args->verbose) {
3348
const char *sep;
3349
int n;
3350
3351
ie += 2, ielen -= 2;
3352
3353
printf("<v%u", LE_READ_2(ie));
3354
ie += 2, ielen -= 2;
3355
3356
printf(" mc:%s", rsn_cipher(ie));
3357
ie += 4, ielen -= 4;
3358
3359
/* unicast ciphers */
3360
n = LE_READ_2(ie);
3361
ie += 2, ielen -= 2;
3362
sep = " uc:";
3363
for (; n > 0; n--) {
3364
printf("%s%s", sep, rsn_cipher(ie));
3365
ie += 4, ielen -= 4;
3366
sep = "+";
3367
}
3368
3369
/* key management algorithms */
3370
n = LE_READ_2(ie);
3371
ie += 2, ielen -= 2;
3372
sep = " km:";
3373
for (; n > 0; n--) {
3374
printf("%s%s", sep, rsn_keymgmt(ie));
3375
ie += 4, ielen -= 4;
3376
sep = "+";
3377
}
3378
3379
if (ielen > 2) /* optional capabilities */
3380
printf(", caps 0x%x", LE_READ_2(ie));
3381
/* XXXPMKID */
3382
printf(">");
3383
}
3384
}
3385
3386
static void
3387
printrsnxe(if_ctx *ctx, const char *tag, const u_int8_t *ie, size_t ielen)
3388
{
3389
size_t n;
3390
3391
printf("%s", tag);
3392
if (!ctx->args->verbose)
3393
return;
3394
3395
ie += 2, ielen -= 2;
3396
3397
n = (*ie & 0x0f);
3398
printf("<%zu", n + 1);
3399
3400
/* We do not yet know about more than n=1 (0). */
3401
if (n != 0)
3402
goto end;
3403
3404
if (*ie & 0x10)
3405
printf(" PTWTOPS");
3406
if (*ie & 0x20)
3407
printf(" SAE h-t-e");
3408
3409
end:
3410
printf(">");
3411
}
3412
3413
#define BE_READ_2(p) \
3414
((u_int16_t) \
3415
((((const u_int8_t *)(p))[1] ) | \
3416
(((const u_int8_t *)(p))[0] << 8)))
3417
3418
static void
3419
printwpsie(if_ctx *ctx, const char *tag, const u_int8_t *ie)
3420
{
3421
u_int8_t len = ie[1];
3422
3423
printf("%s", tag);
3424
if (ctx->args->verbose) {
3425
static const char *dev_pass_id[] = {
3426
"D", /* Default (PIN) */
3427
"U", /* User-specified */
3428
"M", /* Machine-specified */
3429
"K", /* Rekey */
3430
"P", /* PushButton */
3431
"R" /* Registrar-specified */
3432
};
3433
int n;
3434
int f;
3435
3436
ie +=6, len -= 4; /* NB: len is payload only */
3437
3438
/* WPS IE in Beacon and Probe Resp frames have different fields */
3439
printf("<");
3440
while (len) {
3441
uint16_t tlv_type = BE_READ_2(ie);
3442
uint16_t tlv_len = BE_READ_2(ie + 2);
3443
uint16_t cfg_mthd;
3444
3445
/* some devices broadcast invalid WPS frames */
3446
if (tlv_len > len) {
3447
printf("bad frame length tlv_type=0x%02x "
3448
"tlv_len=%d len=%d", tlv_type, tlv_len,
3449
len);
3450
break;
3451
}
3452
3453
ie += 4, len -= 4;
3454
3455
switch (tlv_type) {
3456
case IEEE80211_WPS_ATTR_VERSION:
3457
printf("v:%d.%d", *ie >> 4, *ie & 0xf);
3458
break;
3459
case IEEE80211_WPS_ATTR_AP_SETUP_LOCKED:
3460
printf(" ap_setup:%s", *ie ? "locked" :
3461
"unlocked");
3462
break;
3463
case IEEE80211_WPS_ATTR_CONFIG_METHODS:
3464
case IEEE80211_WPS_ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
3465
if (tlv_type == IEEE80211_WPS_ATTR_SELECTED_REGISTRAR_CONFIG_METHODS)
3466
printf(" sel_reg_cfg_mthd:");
3467
else
3468
printf(" cfg_mthd:" );
3469
cfg_mthd = BE_READ_2(ie);
3470
f = 0;
3471
for (n = 15; n >= 0; n--) {
3472
if (f) {
3473
printf(",");
3474
f = 0;
3475
}
3476
switch (cfg_mthd & (1 << n)) {
3477
case 0:
3478
break;
3479
case IEEE80211_WPS_CONFIG_USBA:
3480
printf("usba");
3481
f++;
3482
break;
3483
case IEEE80211_WPS_CONFIG_ETHERNET:
3484
printf("ethernet");
3485
f++;
3486
break;
3487
case IEEE80211_WPS_CONFIG_LABEL:
3488
printf("label");
3489
f++;
3490
break;
3491
case IEEE80211_WPS_CONFIG_DISPLAY:
3492
if (!(cfg_mthd &
3493
(IEEE80211_WPS_CONFIG_VIRT_DISPLAY |
3494
IEEE80211_WPS_CONFIG_PHY_DISPLAY)))
3495
{
3496
printf("display");
3497
f++;
3498
}
3499
break;
3500
case IEEE80211_WPS_CONFIG_EXT_NFC_TOKEN:
3501
printf("ext_nfc_tokenk");
3502
f++;
3503
break;
3504
case IEEE80211_WPS_CONFIG_INT_NFC_TOKEN:
3505
printf("int_nfc_token");
3506
f++;
3507
break;
3508
case IEEE80211_WPS_CONFIG_NFC_INTERFACE:
3509
printf("nfc_interface");
3510
f++;
3511
break;
3512
case IEEE80211_WPS_CONFIG_PUSHBUTTON:
3513
if (!(cfg_mthd &
3514
(IEEE80211_WPS_CONFIG_VIRT_PUSHBUTTON |
3515
IEEE80211_WPS_CONFIG_PHY_PUSHBUTTON))) {
3516
printf("push_button");
3517
f++;
3518
}
3519
break;
3520
case IEEE80211_WPS_CONFIG_KEYPAD:
3521
printf("keypad");
3522
f++;
3523
break;
3524
case IEEE80211_WPS_CONFIG_VIRT_PUSHBUTTON:
3525
printf("virtual_push_button");
3526
f++;
3527
break;
3528
case IEEE80211_WPS_CONFIG_PHY_PUSHBUTTON:
3529
printf("physical_push_button");
3530
f++;
3531
break;
3532
case IEEE80211_WPS_CONFIG_P2PS:
3533
printf("p2ps");
3534
f++;
3535
break;
3536
case IEEE80211_WPS_CONFIG_VIRT_DISPLAY:
3537
printf("virtual_display");
3538
f++;
3539
break;
3540
case IEEE80211_WPS_CONFIG_PHY_DISPLAY:
3541
printf("physical_display");
3542
f++;
3543
break;
3544
default:
3545
printf("unknown_wps_config<%04x>",
3546
cfg_mthd & (1 << n));
3547
f++;
3548
break;
3549
}
3550
}
3551
break;
3552
case IEEE80211_WPS_ATTR_DEV_NAME:
3553
printf(" device_name:<%.*s>", tlv_len, ie);
3554
break;
3555
case IEEE80211_WPS_ATTR_DEV_PASSWORD_ID:
3556
n = LE_READ_2(ie);
3557
if (n < (int)nitems(dev_pass_id))
3558
printf(" dpi:%s", dev_pass_id[n]);
3559
break;
3560
case IEEE80211_WPS_ATTR_MANUFACTURER:
3561
printf(" manufacturer:<%.*s>", tlv_len, ie);
3562
break;
3563
case IEEE80211_WPS_ATTR_MODEL_NAME:
3564
printf(" model_name:<%.*s>", tlv_len, ie);
3565
break;
3566
case IEEE80211_WPS_ATTR_MODEL_NUMBER:
3567
printf(" model_number:<%.*s>", tlv_len, ie);
3568
break;
3569
case IEEE80211_WPS_ATTR_PRIMARY_DEV_TYPE:
3570
printf(" prim_dev:");
3571
for (n = 0; n < tlv_len; n++)
3572
printf("%02x", ie[n]);
3573
break;
3574
case IEEE80211_WPS_ATTR_RF_BANDS:
3575
printf(" rf:");
3576
f = 0;
3577
for (n = 7; n >= 0; n--) {
3578
if (f) {
3579
printf(",");
3580
f = 0;
3581
}
3582
switch (*ie & (1 << n)) {
3583
case 0:
3584
break;
3585
case IEEE80211_WPS_RF_BAND_24GHZ:
3586
printf("2.4Ghz");
3587
f++;
3588
break;
3589
case IEEE80211_WPS_RF_BAND_50GHZ:
3590
printf("5Ghz");
3591
f++;
3592
break;
3593
case IEEE80211_WPS_RF_BAND_600GHZ:
3594
printf("60Ghz");
3595
f++;
3596
break;
3597
default:
3598
printf("unknown<%02x>",
3599
*ie & (1 << n));
3600
f++;
3601
break;
3602
}
3603
}
3604
break;
3605
case IEEE80211_WPS_ATTR_RESPONSE_TYPE:
3606
printf(" resp_type:0x%02x", *ie);
3607
break;
3608
case IEEE80211_WPS_ATTR_SELECTED_REGISTRAR:
3609
printf(" sel:%s", *ie ? "T" : "F");
3610
break;
3611
case IEEE80211_WPS_ATTR_SERIAL_NUMBER:
3612
printf(" serial_number:<%.*s>", tlv_len, ie);
3613
break;
3614
case IEEE80211_WPS_ATTR_UUID_E:
3615
printf(" uuid-e:");
3616
for (n = 0; n < (tlv_len - 1); n++)
3617
printf("%02x-", ie[n]);
3618
printf("%02x", ie[n]);
3619
break;
3620
case IEEE80211_WPS_ATTR_VENDOR_EXT:
3621
printf(" vendor:");
3622
for (n = 0; n < tlv_len; n++)
3623
printf("%02x", ie[n]);
3624
break;
3625
case IEEE80211_WPS_ATTR_WPS_STATE:
3626
switch (*ie) {
3627
case IEEE80211_WPS_STATE_NOT_CONFIGURED:
3628
printf(" state:N");
3629
break;
3630
case IEEE80211_WPS_STATE_CONFIGURED:
3631
printf(" state:C");
3632
break;
3633
default:
3634
printf(" state:B<%02x>", *ie);
3635
break;
3636
}
3637
break;
3638
default:
3639
printf(" unknown_wps_attr:0x%x", tlv_type);
3640
break;
3641
}
3642
ie += tlv_len, len -= tlv_len;
3643
}
3644
printf(">");
3645
}
3646
}
3647
3648
static void
3649
printtdmaie(if_ctx *ctx, const char *tag, const u_int8_t *ie, size_t ielen)
3650
{
3651
printf("%s", tag);
3652
if (ctx->args->verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
3653
const struct ieee80211_tdma_param *tdma =
3654
(const struct ieee80211_tdma_param *) ie;
3655
3656
/* XXX tstamp */
3657
printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
3658
tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
3659
LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
3660
tdma->tdma_inuse[0]);
3661
}
3662
}
3663
3664
/*
3665
* Copy the ssid string contents into buf, truncating to fit. If the
3666
* ssid is entirely printable then just copy intact. Otherwise convert
3667
* to hexadecimal. If the result is truncated then replace the last
3668
* three characters with "...".
3669
*/
3670
static int
3671
copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
3672
{
3673
const u_int8_t *p;
3674
size_t maxlen;
3675
u_int i;
3676
3677
if (essid_len > bufsize)
3678
maxlen = bufsize;
3679
else
3680
maxlen = essid_len;
3681
/* determine printable or not */
3682
for (i = 0, p = essid; i < maxlen; i++, p++) {
3683
if (*p < ' ' || *p > 0x7e)
3684
break;
3685
}
3686
if (i != maxlen) { /* not printable, print as hex */
3687
if (bufsize < 3)
3688
return 0;
3689
strlcpy(buf, "0x", bufsize);
3690
bufsize -= 2;
3691
p = essid;
3692
for (i = 0; i < maxlen && bufsize >= 2; i++) {
3693
sprintf(&buf[2+2*i], "%02x", p[i]);
3694
bufsize -= 2;
3695
}
3696
if (i != essid_len)
3697
memcpy(&buf[2+2*i-3], "...", 3);
3698
} else { /* printable, truncate as needed */
3699
memcpy(buf, essid, maxlen);
3700
if (maxlen != essid_len)
3701
memcpy(&buf[maxlen-3], "...", 3);
3702
}
3703
return maxlen;
3704
}
3705
3706
static void
3707
printssid(const char *tag, const u_int8_t *ie, int maxlen)
3708
{
3709
char ssid[2*IEEE80211_NWID_LEN+1];
3710
3711
printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
3712
}
3713
3714
static void
3715
printrates(const char *tag, const u_int8_t *ie, size_t ielen)
3716
{
3717
const char *sep;
3718
3719
printf("%s", tag);
3720
sep = "<";
3721
for (size_t i = 2; i < ielen; i++) {
3722
printf("%s%s%d", sep,
3723
ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
3724
ie[i] & IEEE80211_RATE_VAL);
3725
sep = ",";
3726
}
3727
printf(">");
3728
}
3729
3730
static void
3731
printcountry(const char *tag, const u_int8_t *ie)
3732
{
3733
const struct ieee80211_country_ie *cie =
3734
(const struct ieee80211_country_ie *) ie;
3735
int i, nbands, schan, nchan;
3736
3737
printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
3738
nbands = (cie->len - 3) / sizeof(cie->band[0]);
3739
for (i = 0; i < nbands; i++) {
3740
schan = cie->band[i].schan;
3741
nchan = cie->band[i].nchan;
3742
if (nchan != 1)
3743
printf(" %u-%u,%u", schan, schan + nchan-1,
3744
cie->band[i].maxtxpwr);
3745
else
3746
printf(" %u,%u", schan, cie->band[i].maxtxpwr);
3747
}
3748
printf(">");
3749
}
3750
3751
static __inline int
3752
iswpaoui(const u_int8_t *frm)
3753
{
3754
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
3755
}
3756
3757
static __inline int
3758
iswmeinfo(const u_int8_t *frm)
3759
{
3760
return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3761
frm[6] == WME_INFO_OUI_SUBTYPE;
3762
}
3763
3764
static __inline int
3765
iswmeparam(const u_int8_t *frm)
3766
{
3767
return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
3768
frm[6] == WME_PARAM_OUI_SUBTYPE;
3769
}
3770
3771
static __inline int
3772
isatherosoui(const u_int8_t *frm)
3773
{
3774
return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
3775
}
3776
3777
static __inline int
3778
istdmaoui(const uint8_t *frm)
3779
{
3780
return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
3781
}
3782
3783
static __inline int
3784
iswpsoui(const uint8_t *frm)
3785
{
3786
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
3787
}
3788
3789
static const char *
3790
ie_ext_name(uint8_t ext_elemid)
3791
{
3792
static char iename_buf[32];
3793
3794
switch (ext_elemid) {
3795
case IEEE80211_ELEMID_EXT_HE_CAPA: return " HECAP";
3796
case IEEE80211_ELEMID_EXT_HE_OPER: return " HEOPER";
3797
case IEEE80211_ELEMID_EXT_MU_EDCA_PARAM_SET: return " MU_EDCA_PARAM_SET";
3798
}
3799
snprintf(iename_buf, sizeof(iename_buf), " ELEMID_EXT_%d",
3800
ext_elemid & 0xff);
3801
return (const char *) iename_buf;
3802
}
3803
3804
static const char *
3805
iename(uint8_t elemid, const u_int8_t *vp)
3806
{
3807
static char iename_buf[64];
3808
switch (elemid) {
3809
case IEEE80211_ELEMID_FHPARMS: return " FHPARMS";
3810
case IEEE80211_ELEMID_CFPARMS: return " CFPARMS";
3811
case IEEE80211_ELEMID_TIM: return " TIM";
3812
case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
3813
case IEEE80211_ELEMID_BSSLOAD: return " BSSLOAD";
3814
case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
3815
case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR";
3816
case IEEE80211_ELEMID_PWRCAP: return " PWRCAP";
3817
case IEEE80211_ELEMID_TPCREQ: return " TPCREQ";
3818
case IEEE80211_ELEMID_TPCREP: return " TPCREP";
3819
case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN";
3820
case IEEE80211_ELEMID_CSA: return " CSA";
3821
case IEEE80211_ELEMID_MEASREQ: return " MEASREQ";
3822
case IEEE80211_ELEMID_MEASREP: return " MEASREP";
3823
case IEEE80211_ELEMID_QUIET: return " QUIET";
3824
case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS";
3825
case IEEE80211_ELEMID_RESERVED_47:
3826
return " RESERVED_47";
3827
case IEEE80211_ELEMID_SUP_OP_CLASS:
3828
return " SUP_OP_CLASS";
3829
case IEEE80211_ELEMID_MOBILITY_DOMAIN:
3830
return " MOBILITY_DOMAIN";
3831
case IEEE80211_ELEMID_RRM_ENACAPS:
3832
return " RRM_ENCAPS";
3833
case IEEE80211_ELEMID_OVERLAP_BSS_SCAN_PARAM:
3834
return " OVERLAP_BSS";
3835
case IEEE80211_ELEMID_TPC: return " TPC";
3836
case IEEE80211_ELEMID_CCKM: return " CCKM";
3837
case IEEE80211_ELEMID_EXTCAP: return " EXTCAP";
3838
case IEEE80211_ELEMID_RSN_EXT: return " RSNXE";
3839
case IEEE80211_ELEMID_EXTFIELD:
3840
if (vp[1] >= 1)
3841
return ie_ext_name(vp[2]);
3842
break;
3843
}
3844
snprintf(iename_buf, sizeof(iename_buf), " ELEMID_%d",
3845
elemid);
3846
return (const char *) iename_buf;
3847
}
3848
3849
static void
3850
printexties(if_ctx *ctx, const u_int8_t *vp, unsigned int maxcols)
3851
{
3852
const int verbose = ctx->args->verbose;
3853
3854
if (vp[1] < 1)
3855
return;
3856
3857
switch (vp[2]) {
3858
case IEEE80211_ELEMID_EXT_HE_CAPA:
3859
printhecap(ctx, " HECAP", vp);
3860
break;
3861
case IEEE80211_ELEMID_EXT_HE_OPER:
3862
printheoper(ctx, " HEOPER", vp);
3863
break;
3864
case IEEE80211_ELEMID_EXT_MU_EDCA_PARAM_SET:
3865
printmuedcaparamset(ctx, " MU_EDCA_PARAM_SET", vp);
3866
break;
3867
default:
3868
if (verbose)
3869
printie(ctx, iename(vp[0], vp), vp, 2+vp[1], maxcols);
3870
break;
3871
}
3872
}
3873
3874
static void
3875
printies(if_ctx *ctx, const u_int8_t *vp, int ielen, unsigned int maxcols)
3876
{
3877
const int verbose = ctx->args->verbose;
3878
3879
while (ielen > 0) {
3880
switch (vp[0]) {
3881
case IEEE80211_ELEMID_SSID:
3882
if (verbose)
3883
printssid(" SSID", vp, maxcols);
3884
break;
3885
case IEEE80211_ELEMID_RATES:
3886
case IEEE80211_ELEMID_XRATES:
3887
if (verbose)
3888
printrates(vp[0] == IEEE80211_ELEMID_RATES ?
3889
" RATES" : " XRATES", vp, 2+vp[1]);
3890
break;
3891
case IEEE80211_ELEMID_DSPARMS:
3892
if (verbose)
3893
printf(" DSPARMS<%u>", vp[2]);
3894
break;
3895
case IEEE80211_ELEMID_COUNTRY:
3896
if (verbose)
3897
printcountry(" COUNTRY", vp);
3898
break;
3899
case IEEE80211_ELEMID_ERP:
3900
if (verbose)
3901
printf(" ERP<0x%x>", vp[2]);
3902
break;
3903
case IEEE80211_ELEMID_VENDOR:
3904
if (iswpaoui(vp))
3905
printwpaie(ctx, " WPA", vp);
3906
else if (iswmeinfo(vp))
3907
printwmeinfo(ctx, " WME", vp);
3908
else if (iswmeparam(vp))
3909
printwmeparam(ctx, " WME", vp);
3910
else if (isatherosoui(vp))
3911
printathie(ctx, " ATH", vp);
3912
else if (iswpsoui(vp))
3913
printwpsie(ctx, " WPS", vp);
3914
else if (istdmaoui(vp))
3915
printtdmaie(ctx, " TDMA", vp, 2+vp[1]);
3916
else if (verbose)
3917
printie(ctx, " VEN", vp, 2+vp[1], maxcols);
3918
break;
3919
case IEEE80211_ELEMID_RSN:
3920
printrsnie(ctx, " RSN", vp, 2+vp[1]);
3921
break;
3922
case IEEE80211_ELEMID_HTCAP:
3923
printhtcap(ctx, " HTCAP", vp);
3924
break;
3925
case IEEE80211_ELEMID_SUP_OP_CLASS:
3926
printsupopclass(ctx, " SUP_OP_CLASS", vp);
3927
break;
3928
case IEEE80211_ELEMID_HTINFO:
3929
if (verbose)
3930
printhtinfo(ctx, " HTINFO", vp);
3931
break;
3932
case IEEE80211_ELEMID_MESHID:
3933
if (verbose)
3934
printssid(" MESHID", vp, maxcols);
3935
break;
3936
case IEEE80211_ELEMID_MESHCONF:
3937
printmeshconf(ctx, " MESHCONF", vp);
3938
break;
3939
case IEEE80211_ELEMID_VHT_CAP:
3940
printvhtcap(ctx, " VHTCAP", vp);
3941
break;
3942
case IEEE80211_ELEMID_VHT_OPMODE:
3943
printvhtinfo(ctx, " VHTOPMODE", vp);
3944
break;
3945
case IEEE80211_ELEMID_VHT_PWR_ENV:
3946
printvhtpwrenv(ctx, " VHTPWRENV", vp, 2+vp[1]);
3947
break;
3948
case IEEE80211_ELEMID_BSSLOAD:
3949
printbssload(ctx, " BSSLOAD", vp);
3950
break;
3951
case IEEE80211_ELEMID_APCHANREP:
3952
printapchanrep(ctx, " APCHANREP", vp, 2+vp[1]);
3953
break;
3954
case IEEE80211_ELEMID_RSN_EXT:
3955
printrsnxe(ctx, " RSNXE", vp, 2+vp[1]);
3956
break;
3957
case IEEE80211_ELEMID_EXTFIELD:
3958
printexties(ctx, vp, maxcols);
3959
break;
3960
default:
3961
if (verbose)
3962
printie(ctx, iename(vp[0], vp), vp, 2+vp[1], maxcols);
3963
break;
3964
}
3965
ielen -= 2+vp[1];
3966
vp += 2+vp[1];
3967
}
3968
}
3969
3970
static void
3971
printmimo(const struct ieee80211_mimo_info *mi)
3972
{
3973
int i;
3974
int r = 0;
3975
3976
for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
3977
if (mi->ch[i].rssi[0] != 0) {
3978
r = 1;
3979
break;
3980
}
3981
}
3982
3983
/* NB: don't muddy display unless there's something to show */
3984
if (r == 0)
3985
return;
3986
3987
/* XXX TODO: ignore EVM; secondary channels for now */
3988
printf(" (rssi %.1f:%.1f:%.1f:%.1f nf %d:%d:%d:%d)",
3989
mi->ch[0].rssi[0] / 2.0,
3990
mi->ch[1].rssi[0] / 2.0,
3991
mi->ch[2].rssi[0] / 2.0,
3992
mi->ch[3].rssi[0] / 2.0,
3993
mi->ch[0].noise[0],
3994
mi->ch[1].noise[0],
3995
mi->ch[2].noise[0],
3996
mi->ch[3].noise[0]);
3997
}
3998
3999
static void
4000
printbssidname(const struct ether_addr *n)
4001
{
4002
char name[MAXHOSTNAMELEN + 1];
4003
4004
if (ether_ntohost(name, n) != 0)
4005
return;
4006
4007
printf(" (%s)", name);
4008
}
4009
4010
static void
4011
list_scan(if_ctx *ctx)
4012
{
4013
uint8_t buf[24*1024];
4014
char ssid[IEEE80211_NWID_LEN+1];
4015
const uint8_t *cp;
4016
int len, idlen;
4017
4018
if (get80211len(ctx, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
4019
errx(1, "unable to get scan results");
4020
if (len < (int)sizeof(struct ieee80211req_scan_result))
4021
return;
4022
4023
getchaninfo(ctx);
4024
4025
printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
4026
, IEEE80211_NWID_LEN, IEEE80211_NWID_LEN, "SSID/MESH ID"
4027
, "BSSID"
4028
, "CHAN"
4029
, "RATE"
4030
, " S:N"
4031
, "INT"
4032
, "CAPS"
4033
);
4034
cp = buf;
4035
do {
4036
const struct ieee80211req_scan_result *sr;
4037
const uint8_t *vp, *idp;
4038
4039
sr = (const struct ieee80211req_scan_result *)(const void *) cp;
4040
vp = cp + sr->isr_ie_off;
4041
if (sr->isr_meshid_len) {
4042
idp = vp + sr->isr_ssid_len;
4043
idlen = sr->isr_meshid_len;
4044
} else {
4045
idp = vp;
4046
idlen = sr->isr_ssid_len;
4047
}
4048
printf("%-*.*s %s %3d %3dM %4d:%-4d %4d %-4.4s"
4049
, IEEE80211_NWID_LEN
4050
, copy_essid(ssid, IEEE80211_NWID_LEN, idp, idlen)
4051
, ssid
4052
, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
4053
, ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
4054
, getmaxrate(sr->isr_rates, sr->isr_nrates)
4055
, (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
4056
, sr->isr_intval
4057
, getcaps(sr->isr_capinfo)
4058
);
4059
printies(ctx, vp + sr->isr_ssid_len + sr->isr_meshid_len,
4060
sr->isr_ie_len, 24);
4061
printbssidname((const struct ether_addr *)sr->isr_bssid);
4062
printf("\n");
4063
cp += sr->isr_len, len -= sr->isr_len;
4064
} while (len >= (int)sizeof(struct ieee80211req_scan_result));
4065
}
4066
4067
static void
4068
scan_and_wait(if_ctx *ctx)
4069
{
4070
struct ieee80211_scan_req sr;
4071
struct ieee80211req ireq;
4072
int sroute;
4073
4074
sroute = socket(PF_ROUTE, SOCK_RAW, 0);
4075
if (sroute < 0) {
4076
perror("socket(PF_ROUTE,SOCK_RAW)");
4077
return;
4078
}
4079
memset(&ireq, 0, sizeof(ireq));
4080
strlcpy(ireq.i_name, ctx->ifname, sizeof(ireq.i_name));
4081
ireq.i_type = IEEE80211_IOC_SCAN_REQ;
4082
4083
memset(&sr, 0, sizeof(sr));
4084
sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
4085
| IEEE80211_IOC_SCAN_BGSCAN
4086
| IEEE80211_IOC_SCAN_NOPICK
4087
| IEEE80211_IOC_SCAN_ONCE;
4088
sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
4089
sr.sr_nssid = 0;
4090
4091
ireq.i_data = &sr;
4092
ireq.i_len = sizeof(sr);
4093
/*
4094
* NB: only root can trigger a scan so ignore errors. Also ignore
4095
* possible errors from net80211, even if no new scan could be
4096
* started there might still be a valid scan cache.
4097
*/
4098
if (ioctl_ctx(ctx, SIOCS80211, &ireq) == 0) {
4099
char buf[2048];
4100
struct if_announcemsghdr *ifan;
4101
struct rt_msghdr *rtm;
4102
4103
do {
4104
if (read(sroute, buf, sizeof(buf)) < 0) {
4105
perror("read(PF_ROUTE)");
4106
break;
4107
}
4108
rtm = (struct rt_msghdr *)(void *)buf;
4109
if (rtm->rtm_version != RTM_VERSION)
4110
break;
4111
ifan = (struct if_announcemsghdr *) rtm;
4112
} while (rtm->rtm_type != RTM_IEEE80211 ||
4113
ifan->ifan_what != RTM_IEEE80211_SCAN);
4114
}
4115
close(sroute);
4116
}
4117
4118
static void
4119
set80211scan(if_ctx *ctx, const char *val __unused, int dummy __unused)
4120
{
4121
scan_and_wait(ctx);
4122
list_scan(ctx);
4123
}
4124
4125
static enum ieee80211_opmode get80211opmode(if_ctx *ctx);
4126
4127
static int
4128
gettxseq(const struct ieee80211req_sta_info *si)
4129
{
4130
int i, txseq;
4131
4132
if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
4133
return si->isi_txseqs[0];
4134
/* XXX not right but usually what folks want */
4135
txseq = 0;
4136
for (i = 0; i < IEEE80211_TID_SIZE; i++)
4137
if (si->isi_txseqs[i] > txseq)
4138
txseq = si->isi_txseqs[i];
4139
return txseq;
4140
}
4141
4142
static int
4143
getrxseq(const struct ieee80211req_sta_info *si)
4144
{
4145
int rxseq;
4146
4147
if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
4148
return si->isi_rxseqs[0];
4149
/* XXX not right but usually what folks want */
4150
rxseq = 0;
4151
for (unsigned int i = 0; i < IEEE80211_TID_SIZE; i++)
4152
if (si->isi_rxseqs[i] > rxseq)
4153
rxseq = si->isi_rxseqs[i];
4154
return rxseq;
4155
}
4156
4157
static void
4158
list_stations(if_ctx *ctx)
4159
{
4160
union {
4161
struct ieee80211req_sta_req req;
4162
uint8_t buf[24*1024];
4163
} u;
4164
enum ieee80211_opmode opmode = get80211opmode(ctx);
4165
const uint8_t *cp;
4166
int len;
4167
4168
/* broadcast address =>'s get all stations */
4169
(void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
4170
if (opmode == IEEE80211_M_STA) {
4171
/*
4172
* Get information about the associated AP.
4173
*/
4174
(void) get80211(ctx, IEEE80211_IOC_BSSID,
4175
u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
4176
}
4177
if (get80211len(ctx, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
4178
errx(1, "unable to get station information");
4179
if (len < (int)sizeof(struct ieee80211req_sta_info))
4180
return;
4181
4182
getchaninfo(ctx);
4183
4184
if (opmode == IEEE80211_M_MBSS)
4185
printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
4186
, "ADDR"
4187
, "CHAN"
4188
, "LOCAL"
4189
, "PEER"
4190
, "STATE"
4191
, "RATE"
4192
, "RSSI"
4193
, "IDLE"
4194
, "TXSEQ"
4195
, "RXSEQ"
4196
);
4197
else
4198
printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-12s\n"
4199
, "ADDR"
4200
, "AID"
4201
, "CHAN"
4202
, "RATE"
4203
, "RSSI"
4204
, "IDLE"
4205
, "TXSEQ"
4206
, "RXSEQ"
4207
, "CAPS"
4208
, "FLAG"
4209
);
4210
cp = (const uint8_t *) u.req.info;
4211
do {
4212
const struct ieee80211req_sta_info *si;
4213
4214
si = (const struct ieee80211req_sta_info *)(const void *)cp;
4215
if (si->isi_len < sizeof(*si))
4216
break;
4217
if (opmode == IEEE80211_M_MBSS)
4218
printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
4219
, ether_ntoa((const struct ether_addr*)
4220
si->isi_macaddr)
4221
, ieee80211_mhz2ieee(si->isi_freq,
4222
si->isi_flags)
4223
, si->isi_localid
4224
, si->isi_peerid
4225
, mesh_linkstate_string(si->isi_peerstate)
4226
, si->isi_txmbps/2
4227
, si->isi_rssi/2.
4228
, si->isi_inact
4229
, gettxseq(si)
4230
, getrxseq(si)
4231
);
4232
else
4233
printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-12.12s"
4234
, ether_ntoa((const struct ether_addr*)
4235
si->isi_macaddr)
4236
, IEEE80211_AID(si->isi_associd)
4237
, ieee80211_mhz2ieee(si->isi_freq,
4238
si->isi_flags)
4239
, si->isi_txmbps/2
4240
, si->isi_rssi/2.
4241
, si->isi_inact
4242
, gettxseq(si)
4243
, getrxseq(si)
4244
, getcaps(si->isi_capinfo)
4245
, getflags(si->isi_state)
4246
);
4247
printies(ctx, cp + si->isi_ie_off, si->isi_ie_len, 24);
4248
printmimo(&si->isi_mimo);
4249
printf("\n");
4250
cp += si->isi_len, len -= si->isi_len;
4251
} while (len >= (int)sizeof(struct ieee80211req_sta_info));
4252
}
4253
4254
static const char *
4255
mesh_linkstate_string(uint8_t state)
4256
{
4257
static const char *state_names[] = {
4258
[0] = "IDLE",
4259
[1] = "OPEN-TX",
4260
[2] = "OPEN-RX",
4261
[3] = "CONF-RX",
4262
[4] = "ESTAB",
4263
[5] = "HOLDING",
4264
};
4265
4266
if (state >= nitems(state_names)) {
4267
static char buf[10];
4268
snprintf(buf, sizeof(buf), "#%u", state);
4269
return buf;
4270
} else
4271
return state_names[state];
4272
}
4273
4274
static const char *
4275
get_chaninfo(const struct ieee80211_channel *c, int precise,
4276
char buf[], size_t bsize)
4277
{
4278
buf[0] = '\0';
4279
if (IEEE80211_IS_CHAN_FHSS(c))
4280
strlcat(buf, " FHSS", bsize);
4281
if (IEEE80211_IS_CHAN_A(c))
4282
strlcat(buf, " 11a", bsize);
4283
else if (IEEE80211_IS_CHAN_ANYG(c))
4284
strlcat(buf, " 11g", bsize);
4285
else if (IEEE80211_IS_CHAN_B(c))
4286
strlcat(buf, " 11b", bsize);
4287
if (IEEE80211_IS_CHAN_HALF(c))
4288
strlcat(buf, "/10MHz", bsize);
4289
if (IEEE80211_IS_CHAN_QUARTER(c))
4290
strlcat(buf, "/5MHz", bsize);
4291
if (IEEE80211_IS_CHAN_TURBO(c))
4292
strlcat(buf, " Turbo", bsize);
4293
if (precise) {
4294
if (IEEE80211_IS_CHAN_VHT80P80(c))
4295
strlcat(buf, " vht/80p80", bsize);
4296
else if (IEEE80211_IS_CHAN_VHT160(c))
4297
strlcat(buf, " vht/160", bsize);
4298
else if (IEEE80211_IS_CHAN_VHT80(c) &&
4299
IEEE80211_IS_CHAN_HT40D(c))
4300
strlcat(buf, " vht/80-", bsize);
4301
else if (IEEE80211_IS_CHAN_VHT80(c) &&
4302
IEEE80211_IS_CHAN_HT40U(c))
4303
strlcat(buf, " vht/80+", bsize);
4304
else if (IEEE80211_IS_CHAN_VHT80(c))
4305
strlcat(buf, " vht/80", bsize);
4306
else if (IEEE80211_IS_CHAN_VHT40D(c))
4307
strlcat(buf, " vht/40-", bsize);
4308
else if (IEEE80211_IS_CHAN_VHT40U(c))
4309
strlcat(buf, " vht/40+", bsize);
4310
else if (IEEE80211_IS_CHAN_VHT20(c))
4311
strlcat(buf, " vht/20", bsize);
4312
else if (IEEE80211_IS_CHAN_HT20(c))
4313
strlcat(buf, " ht/20", bsize);
4314
else if (IEEE80211_IS_CHAN_HT40D(c))
4315
strlcat(buf, " ht/40-", bsize);
4316
else if (IEEE80211_IS_CHAN_HT40U(c))
4317
strlcat(buf, " ht/40+", bsize);
4318
} else {
4319
if (IEEE80211_IS_CHAN_VHT(c))
4320
strlcat(buf, " vht", bsize);
4321
else if (IEEE80211_IS_CHAN_HT(c))
4322
strlcat(buf, " ht", bsize);
4323
}
4324
return buf;
4325
}
4326
4327
static void
4328
print_chaninfo(const struct ieee80211_channel *c, int verb)
4329
{
4330
char buf[14];
4331
4332
if (verb)
4333
printf("Channel %3u : %u%c%c%c%c%c MHz%-14.14s",
4334
ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
4335
IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
4336
IEEE80211_IS_CHAN_DFS(c) ? 'D' : ' ',
4337
IEEE80211_IS_CHAN_RADAR(c) ? 'R' : ' ',
4338
IEEE80211_IS_CHAN_CWINT(c) ? 'I' : ' ',
4339
IEEE80211_IS_CHAN_CACDONE(c) ? 'C' : ' ',
4340
get_chaninfo(c, verb, buf, sizeof(buf)));
4341
else
4342
printf("Channel %3u : %u%c MHz%-14.14s",
4343
ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
4344
IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
4345
get_chaninfo(c, verb, buf, sizeof(buf)));
4346
4347
}
4348
4349
static int
4350
chanpref(const struct ieee80211_channel *c)
4351
{
4352
4353
if (IEEE80211_IS_CHAN_VHT80P80(c))
4354
return 90;
4355
if (IEEE80211_IS_CHAN_VHT160(c))
4356
return 80;
4357
if (IEEE80211_IS_CHAN_VHT80(c))
4358
return 70;
4359
if (IEEE80211_IS_CHAN_VHT40(c))
4360
return 60;
4361
if (IEEE80211_IS_CHAN_VHT20(c))
4362
return 50;
4363
if (IEEE80211_IS_CHAN_HT40(c))
4364
return 40;
4365
if (IEEE80211_IS_CHAN_HT20(c))
4366
return 30;
4367
if (IEEE80211_IS_CHAN_HALF(c))
4368
return 10;
4369
if (IEEE80211_IS_CHAN_QUARTER(c))
4370
return 5;
4371
if (IEEE80211_IS_CHAN_TURBO(c))
4372
return 25;
4373
if (IEEE80211_IS_CHAN_A(c))
4374
return 20;
4375
if (IEEE80211_IS_CHAN_G(c))
4376
return 20;
4377
if (IEEE80211_IS_CHAN_B(c))
4378
return 15;
4379
if (IEEE80211_IS_CHAN_PUREG(c))
4380
return 15;
4381
return 0;
4382
}
4383
4384
static void
4385
print_channels(if_ctx *ctx, const struct ieee80211req_chaninfo *chans,
4386
int allchans, int verb)
4387
{
4388
struct ieee80211req_chaninfo *achans;
4389
uint8_t reported[IEEE80211_CHAN_BYTES];
4390
const struct ieee80211_channel *c;
4391
unsigned int i, half;
4392
4393
achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
4394
if (achans == NULL)
4395
errx(1, "no space for active channel list");
4396
achans->ic_nchans = 0;
4397
memset(reported, 0, sizeof(reported));
4398
if (!allchans) {
4399
struct ieee80211req_chanlist active;
4400
4401
if (get80211(ctx, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
4402
errx(1, "unable to get active channel list");
4403
for (i = 0; i < chans->ic_nchans; i++) {
4404
c = &chans->ic_chans[i];
4405
if (!isset(active.ic_channels, c->ic_ieee))
4406
continue;
4407
/*
4408
* Suppress compatible duplicates unless
4409
* verbose. The kernel gives us it's
4410
* complete channel list which has separate
4411
* entries for 11g/11b and 11a/turbo.
4412
*/
4413
if (isset(reported, c->ic_ieee) && !verb) {
4414
/* XXX we assume duplicates are adjacent */
4415
achans->ic_chans[achans->ic_nchans-1] = *c;
4416
} else {
4417
achans->ic_chans[achans->ic_nchans++] = *c;
4418
setbit(reported, c->ic_ieee);
4419
}
4420
}
4421
} else {
4422
for (i = 0; i < chans->ic_nchans; i++) {
4423
c = &chans->ic_chans[i];
4424
/* suppress duplicates as above */
4425
if (isset(reported, c->ic_ieee) && !verb) {
4426
/* XXX we assume duplicates are adjacent */
4427
struct ieee80211_channel *a =
4428
&achans->ic_chans[achans->ic_nchans-1];
4429
if (chanpref(c) > chanpref(a))
4430
*a = *c;
4431
} else {
4432
achans->ic_chans[achans->ic_nchans++] = *c;
4433
setbit(reported, c->ic_ieee);
4434
}
4435
}
4436
}
4437
half = achans->ic_nchans / 2;
4438
if (achans->ic_nchans % 2)
4439
half++;
4440
4441
for (i = 0; i < achans->ic_nchans / 2; i++) {
4442
print_chaninfo(&achans->ic_chans[i], verb);
4443
print_chaninfo(&achans->ic_chans[half+i], verb);
4444
printf("\n");
4445
}
4446
if (achans->ic_nchans % 2) {
4447
print_chaninfo(&achans->ic_chans[i], verb);
4448
printf("\n");
4449
}
4450
free(achans);
4451
}
4452
4453
static void
4454
list_channels(if_ctx *ctx, int allchans)
4455
{
4456
getchaninfo(ctx);
4457
print_channels(ctx, chaninfo, allchans, ctx->args->verbose);
4458
}
4459
4460
static void
4461
print_txpow(const struct ieee80211_channel *c)
4462
{
4463
printf("Channel %3u : %u MHz %3.1f reg %2d ",
4464
c->ic_ieee, c->ic_freq,
4465
c->ic_maxpower/2., c->ic_maxregpower);
4466
}
4467
4468
static void
4469
print_txpow_verbose(const struct ieee80211_channel *c)
4470
{
4471
print_chaninfo(c, 1);
4472
printf("min %4.1f dBm max %3.1f dBm reg %2d dBm",
4473
c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
4474
/* indicate where regulatory cap limits power use */
4475
if (c->ic_maxpower > 2*c->ic_maxregpower)
4476
printf(" <");
4477
}
4478
4479
static void
4480
list_txpow(if_ctx *ctx)
4481
{
4482
struct ieee80211req_chaninfo *achans;
4483
uint8_t reported[IEEE80211_CHAN_BYTES];
4484
struct ieee80211_channel *c, *prev;
4485
unsigned int i, half;
4486
4487
getchaninfo(ctx);
4488
achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
4489
if (achans == NULL)
4490
errx(1, "no space for active channel list");
4491
achans->ic_nchans = 0;
4492
memset(reported, 0, sizeof(reported));
4493
for (i = 0; i < chaninfo->ic_nchans; i++) {
4494
c = &chaninfo->ic_chans[i];
4495
/* suppress duplicates as above */
4496
if (isset(reported, c->ic_ieee) && !ctx->args->verbose) {
4497
/* XXX we assume duplicates are adjacent */
4498
assert(achans->ic_nchans > 0);
4499
prev = &achans->ic_chans[achans->ic_nchans-1];
4500
/* display highest power on channel */
4501
if (c->ic_maxpower > prev->ic_maxpower)
4502
*prev = *c;
4503
} else {
4504
achans->ic_chans[achans->ic_nchans++] = *c;
4505
setbit(reported, c->ic_ieee);
4506
}
4507
}
4508
if (!ctx->args->verbose) {
4509
half = achans->ic_nchans / 2;
4510
if (achans->ic_nchans % 2)
4511
half++;
4512
4513
for (i = 0; i < achans->ic_nchans / 2; i++) {
4514
print_txpow(&achans->ic_chans[i]);
4515
print_txpow(&achans->ic_chans[half+i]);
4516
printf("\n");
4517
}
4518
if (achans->ic_nchans % 2) {
4519
print_txpow(&achans->ic_chans[i]);
4520
printf("\n");
4521
}
4522
} else {
4523
for (i = 0; i < achans->ic_nchans; i++) {
4524
print_txpow_verbose(&achans->ic_chans[i]);
4525
printf("\n");
4526
}
4527
}
4528
free(achans);
4529
}
4530
4531
static void
4532
list_keys(int s __unused)
4533
{
4534
}
4535
4536
static void
4537
list_capabilities(if_ctx *ctx)
4538
{
4539
struct ieee80211_devcaps_req *dc;
4540
const int verbose = ctx->args->verbose;
4541
4542
if (verbose)
4543
dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
4544
else
4545
dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
4546
if (dc == NULL)
4547
errx(1, "no space for device capabilities");
4548
dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
4549
getdevcaps(ctx, dc);
4550
printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
4551
if (dc->dc_cryptocaps != 0 || verbose) {
4552
putchar('\n');
4553
printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
4554
}
4555
if (dc->dc_htcaps != 0 || verbose) {
4556
putchar('\n');
4557
printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
4558
}
4559
if (dc->dc_vhtcaps != 0 || verbose) {
4560
putchar('\n');
4561
printb("vhtcaps", dc->dc_vhtcaps, IEEE80211_VHTCAP_BITS);
4562
}
4563
4564
putchar('\n');
4565
if (verbose) {
4566
chaninfo = &dc->dc_chaninfo; /* XXX */
4567
print_channels(ctx, &dc->dc_chaninfo, 1/*allchans*/, verbose);
4568
}
4569
free(dc);
4570
}
4571
4572
static int
4573
get80211wme(if_ctx *ctx, int param, int ac, int *val)
4574
{
4575
struct ieee80211req ireq = {};
4576
4577
strlcpy(ireq.i_name, ctx->ifname, sizeof(ireq.i_name));
4578
ireq.i_type = param;
4579
ireq.i_len = ac;
4580
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0) {
4581
warn("cannot get WME parameter %d, ac %d%s",
4582
param, ac & IEEE80211_WMEPARAM_VAL,
4583
ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
4584
return -1;
4585
}
4586
*val = ireq.i_val;
4587
return 0;
4588
}
4589
4590
static void
4591
list_wme_aci(if_ctx *ctx, const char *tag, int ac)
4592
{
4593
int val;
4594
4595
printf("\t%s", tag);
4596
4597
/* show WME BSS parameters */
4598
if (get80211wme(ctx, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
4599
printf(" cwmin %2u", val);
4600
if (get80211wme(ctx, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
4601
printf(" cwmax %2u", val);
4602
if (get80211wme(ctx, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
4603
printf(" aifs %2u", val);
4604
if (get80211wme(ctx, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
4605
printf(" txopLimit %3u", val);
4606
if (get80211wme(ctx, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
4607
if (val)
4608
printf(" acm");
4609
else if (ctx->args->verbose)
4610
printf(" -acm");
4611
}
4612
/* !BSS only */
4613
if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
4614
if (get80211wme(ctx, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
4615
if (!val)
4616
printf(" -ack");
4617
else if (ctx->args->verbose)
4618
printf(" ack");
4619
}
4620
}
4621
printf("\n");
4622
}
4623
4624
static void
4625
list_wme(if_ctx *ctx)
4626
{
4627
static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
4628
int ac;
4629
4630
if (ctx->args->verbose) {
4631
/* display both BSS and local settings */
4632
for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
4633
again:
4634
if (ac & IEEE80211_WMEPARAM_BSS)
4635
list_wme_aci(ctx, " ", ac);
4636
else
4637
list_wme_aci(ctx, acnames[ac], ac);
4638
if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
4639
ac |= IEEE80211_WMEPARAM_BSS;
4640
goto again;
4641
} else
4642
ac &= ~IEEE80211_WMEPARAM_BSS;
4643
}
4644
} else {
4645
/* display only channel settings */
4646
for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++)
4647
list_wme_aci(ctx, acnames[ac], ac);
4648
}
4649
}
4650
4651
static void
4652
list_roam(if_ctx *ctx)
4653
{
4654
const struct ieee80211_roamparam *rp;
4655
int mode;
4656
4657
getroam(ctx);
4658
for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
4659
rp = &roamparams.params[mode];
4660
if (rp->rssi == 0 && rp->rate == 0)
4661
continue;
4662
if (mode == IEEE80211_MODE_11NA ||
4663
mode == IEEE80211_MODE_11NG ||
4664
mode == IEEE80211_MODE_VHT_2GHZ ||
4665
mode == IEEE80211_MODE_VHT_5GHZ) {
4666
if (rp->rssi & 1)
4667
LINE_CHECK("roam:%-7.7s rssi %2u.5dBm MCS %2u ",
4668
modename[mode], rp->rssi/2,
4669
rp->rate &~ IEEE80211_RATE_MCS);
4670
else
4671
LINE_CHECK("roam:%-7.7s rssi %4udBm MCS %2u ",
4672
modename[mode], rp->rssi/2,
4673
rp->rate &~ IEEE80211_RATE_MCS);
4674
} else {
4675
if (rp->rssi & 1)
4676
LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s",
4677
modename[mode], rp->rssi/2, rp->rate/2);
4678
else
4679
LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s",
4680
modename[mode], rp->rssi/2, rp->rate/2);
4681
}
4682
}
4683
}
4684
4685
/* XXX TODO: rate-to-string method... */
4686
static const char*
4687
get_mcs_mbs_rate_str(uint8_t rate)
4688
{
4689
return (rate & IEEE80211_RATE_MCS) ? "MCS " : "Mb/s";
4690
}
4691
4692
static uint8_t
4693
get_rate_value(uint8_t rate)
4694
{
4695
if (rate & IEEE80211_RATE_MCS)
4696
return (rate &~ IEEE80211_RATE_MCS);
4697
return (rate / 2);
4698
}
4699
4700
static void
4701
list_txparams(if_ctx *ctx)
4702
{
4703
const struct ieee80211_txparam *tp;
4704
int mode;
4705
4706
gettxparams(ctx);
4707
for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
4708
tp = &txparams.params[mode];
4709
if (tp->mgmtrate == 0 && tp->mcastrate == 0)
4710
continue;
4711
if (mode == IEEE80211_MODE_11NA ||
4712
mode == IEEE80211_MODE_11NG ||
4713
mode == IEEE80211_MODE_VHT_2GHZ ||
4714
mode == IEEE80211_MODE_VHT_5GHZ) {
4715
if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
4716
LINE_CHECK("%-7.7s ucast NONE mgmt %2u %s "
4717
"mcast %2u %s maxretry %u",
4718
modename[mode],
4719
get_rate_value(tp->mgmtrate),
4720
get_mcs_mbs_rate_str(tp->mgmtrate),
4721
get_rate_value(tp->mcastrate),
4722
get_mcs_mbs_rate_str(tp->mcastrate),
4723
tp->maxretry);
4724
else
4725
LINE_CHECK("%-7.7s ucast %2u MCS mgmt %2u %s "
4726
"mcast %2u %s maxretry %u",
4727
modename[mode],
4728
tp->ucastrate &~ IEEE80211_RATE_MCS,
4729
get_rate_value(tp->mgmtrate),
4730
get_mcs_mbs_rate_str(tp->mgmtrate),
4731
get_rate_value(tp->mcastrate),
4732
get_mcs_mbs_rate_str(tp->mcastrate),
4733
tp->maxretry);
4734
} else {
4735
if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
4736
LINE_CHECK("%-7.7s ucast NONE mgmt %2u Mb/s "
4737
"mcast %2u Mb/s maxretry %u",
4738
modename[mode],
4739
tp->mgmtrate/2,
4740
tp->mcastrate/2, tp->maxretry);
4741
else
4742
LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s "
4743
"mcast %2u Mb/s maxretry %u",
4744
modename[mode],
4745
tp->ucastrate/2, tp->mgmtrate/2,
4746
tp->mcastrate/2, tp->maxretry);
4747
}
4748
}
4749
}
4750
4751
static void
4752
printpolicy(int policy)
4753
{
4754
switch (policy) {
4755
case IEEE80211_MACCMD_POLICY_OPEN:
4756
printf("policy: open\n");
4757
break;
4758
case IEEE80211_MACCMD_POLICY_ALLOW:
4759
printf("policy: allow\n");
4760
break;
4761
case IEEE80211_MACCMD_POLICY_DENY:
4762
printf("policy: deny\n");
4763
break;
4764
case IEEE80211_MACCMD_POLICY_RADIUS:
4765
printf("policy: radius\n");
4766
break;
4767
default:
4768
printf("policy: unknown (%u)\n", policy);
4769
break;
4770
}
4771
}
4772
4773
static void
4774
list_mac(if_ctx *ctx)
4775
{
4776
struct ieee80211req ireq = {};
4777
struct ieee80211req_maclist *acllist;
4778
int i, nacls, policy, len;
4779
uint8_t *data;
4780
char c;
4781
4782
strlcpy(ireq.i_name, ctx->ifname, sizeof(ireq.i_name)); /* XXX ?? */
4783
ireq.i_type = IEEE80211_IOC_MACCMD;
4784
ireq.i_val = IEEE80211_MACCMD_POLICY;
4785
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0) {
4786
if (errno == EINVAL) {
4787
printf("No acl policy loaded\n");
4788
return;
4789
}
4790
err(1, "unable to get mac policy");
4791
}
4792
policy = ireq.i_val;
4793
if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
4794
c = '*';
4795
} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
4796
c = '+';
4797
} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
4798
c = '-';
4799
} else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) {
4800
c = 'r'; /* NB: should never have entries */
4801
} else {
4802
printf("policy: unknown (%u)\n", policy);
4803
c = '?';
4804
}
4805
if (ctx->args->verbose || c == '?')
4806
printpolicy(policy);
4807
4808
ireq.i_val = IEEE80211_MACCMD_LIST;
4809
ireq.i_len = 0;
4810
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0)
4811
err(1, "unable to get mac acl list size");
4812
if (ireq.i_len == 0) { /* NB: no acls */
4813
if (!(ctx->args->verbose || c == '?'))
4814
printpolicy(policy);
4815
return;
4816
}
4817
len = ireq.i_len;
4818
4819
data = malloc(len);
4820
if (data == NULL)
4821
err(1, "out of memory for acl list");
4822
4823
ireq.i_data = data;
4824
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0)
4825
err(1, "unable to get mac acl list");
4826
nacls = len / sizeof(*acllist);
4827
acllist = (struct ieee80211req_maclist *) data;
4828
for (i = 0; i < nacls; i++)
4829
printf("%c%s\n", c, ether_ntoa(
4830
(const struct ether_addr *) acllist[i].ml_macaddr));
4831
free(data);
4832
}
4833
4834
static void
4835
print_regdomain(const struct ieee80211_regdomain *reg, int verb)
4836
{
4837
if ((reg->regdomain != 0 &&
4838
reg->regdomain != reg->country) || verb) {
4839
const struct regdomain *rd =
4840
lib80211_regdomain_findbysku(getregdata(), reg->regdomain);
4841
if (rd == NULL)
4842
LINE_CHECK("regdomain %d", reg->regdomain);
4843
else
4844
LINE_CHECK("regdomain %s", rd->name);
4845
}
4846
if (reg->country != 0 || verb) {
4847
const struct country *cc =
4848
lib80211_country_findbycc(getregdata(), reg->country);
4849
if (cc == NULL)
4850
LINE_CHECK("country %d", reg->country);
4851
else
4852
LINE_CHECK("country %s", cc->isoname);
4853
}
4854
if (reg->location == 'I')
4855
LINE_CHECK("indoor");
4856
else if (reg->location == 'O')
4857
LINE_CHECK("outdoor");
4858
else if (verb)
4859
LINE_CHECK("anywhere");
4860
if (reg->ecm)
4861
LINE_CHECK("ecm");
4862
else if (verb)
4863
LINE_CHECK("-ecm");
4864
}
4865
4866
static void
4867
list_regdomain(if_ctx *ctx, int channelsalso)
4868
{
4869
getregdomain(ctx);
4870
if (channelsalso) {
4871
getchaninfo(ctx);
4872
spacer = ':';
4873
print_regdomain(&regdomain, 1);
4874
LINE_BREAK();
4875
print_channels(ctx, chaninfo, 1/*allchans*/, 1/*verbose*/);
4876
} else
4877
print_regdomain(&regdomain, ctx->args->verbose);
4878
}
4879
4880
static void
4881
list_mesh(if_ctx *ctx)
4882
{
4883
struct ieee80211req ireq = {};
4884
struct ieee80211req_mesh_route routes[128];
4885
struct ieee80211req_mesh_route *rt;
4886
4887
strlcpy(ireq.i_name, ctx->ifname, sizeof(ireq.i_name));
4888
ireq.i_type = IEEE80211_IOC_MESH_RTCMD;
4889
ireq.i_val = IEEE80211_MESH_RTCMD_LIST;
4890
ireq.i_data = &routes;
4891
ireq.i_len = sizeof(routes);
4892
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0)
4893
err(1, "unable to get the Mesh routing table");
4894
4895
printf("%-17.17s %-17.17s %4s %4s %4s %6s %s\n"
4896
, "DEST"
4897
, "NEXT HOP"
4898
, "HOPS"
4899
, "METRIC"
4900
, "LIFETIME"
4901
, "MSEQ"
4902
, "FLAGS");
4903
4904
for (unsigned int i = 0; i < ireq.i_len / sizeof(*rt); i++) {
4905
rt = &routes[i];
4906
printf("%s ",
4907
ether_ntoa((const struct ether_addr *)rt->imr_dest));
4908
printf("%s %4u %4u %6u %6u %c%c\n",
4909
ether_ntoa((const struct ether_addr *)rt->imr_nexthop),
4910
rt->imr_nhops, rt->imr_metric, rt->imr_lifetime,
4911
rt->imr_lastmseq,
4912
(rt->imr_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) ?
4913
'D' :
4914
(rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ?
4915
'V' : '!',
4916
(rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ?
4917
'P' :
4918
(rt->imr_flags & IEEE80211_MESHRT_FLAGS_GATE) ?
4919
'G' :' ');
4920
}
4921
}
4922
4923
static void
4924
set80211list(if_ctx *ctx, const char *arg, int dummy __unused)
4925
{
4926
int s = ctx->io_s;
4927
#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
4928
4929
LINE_INIT('\t');
4930
4931
if (iseq(arg, "sta"))
4932
list_stations(ctx);
4933
else if (iseq(arg, "scan") || iseq(arg, "ap"))
4934
list_scan(ctx);
4935
else if (iseq(arg, "chan") || iseq(arg, "freq"))
4936
list_channels(ctx, 1);
4937
else if (iseq(arg, "active"))
4938
list_channels(ctx, 0);
4939
else if (iseq(arg, "keys"))
4940
list_keys(s);
4941
else if (iseq(arg, "caps"))
4942
list_capabilities(ctx);
4943
else if (iseq(arg, "wme") || iseq(arg, "wmm"))
4944
list_wme(ctx);
4945
else if (iseq(arg, "mac"))
4946
list_mac(ctx);
4947
else if (iseq(arg, "txpow"))
4948
list_txpow(ctx);
4949
else if (iseq(arg, "roam"))
4950
list_roam(ctx);
4951
else if (iseq(arg, "txparam") || iseq(arg, "txparm"))
4952
list_txparams(ctx);
4953
else if (iseq(arg, "regdomain"))
4954
list_regdomain(ctx, 1);
4955
else if (iseq(arg, "countries"))
4956
list_countries();
4957
else if (iseq(arg, "mesh"))
4958
list_mesh(ctx);
4959
else
4960
errx(1, "Don't know how to list %s for %s", arg, ctx->ifname);
4961
LINE_BREAK();
4962
#undef iseq
4963
}
4964
4965
static enum ieee80211_opmode
4966
get80211opmode(if_ctx *ctx)
4967
{
4968
struct ifmediareq ifmr = {};
4969
4970
strlcpy(ifmr.ifm_name, ctx->ifname, sizeof(ifmr.ifm_name));
4971
4972
if (ioctl_ctx(ctx, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
4973
if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
4974
if (ifmr.ifm_current & IFM_FLAG0)
4975
return IEEE80211_M_AHDEMO;
4976
else
4977
return IEEE80211_M_IBSS;
4978
}
4979
if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
4980
return IEEE80211_M_HOSTAP;
4981
if (ifmr.ifm_current & IFM_IEEE80211_IBSS)
4982
return IEEE80211_M_IBSS;
4983
if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
4984
return IEEE80211_M_MONITOR;
4985
if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
4986
return IEEE80211_M_MBSS;
4987
}
4988
return IEEE80211_M_STA;
4989
}
4990
4991
#if 0
4992
static void
4993
printcipher(int s, struct ieee80211req *ireq, int keylenop)
4994
{
4995
switch (ireq->i_val) {
4996
case IEEE80211_CIPHER_WEP:
4997
ireq->i_type = keylenop;
4998
if (ioctl(s, SIOCG80211, ireq) != -1)
4999
printf("WEP-%s",
5000
ireq->i_len <= 5 ? "40" :
5001
ireq->i_len <= 13 ? "104" : "128");
5002
else
5003
printf("WEP");
5004
break;
5005
case IEEE80211_CIPHER_TKIP:
5006
printf("TKIP");
5007
break;
5008
case IEEE80211_CIPHER_AES_OCB:
5009
printf("AES-OCB");
5010
break;
5011
case IEEE80211_CIPHER_AES_CCM:
5012
printf("AES-CCM");
5013
break;
5014
case IEEE80211_CIPHER_AES_GCM_128:
5015
printf("AES-GCM");
5016
break;
5017
case IEEE80211_CIPHER_CKIP:
5018
printf("CKIP");
5019
break;
5020
case IEEE80211_CIPHER_NONE:
5021
printf("NONE");
5022
break;
5023
default:
5024
printf("UNKNOWN (0x%x)", ireq->i_val);
5025
break;
5026
}
5027
}
5028
#endif
5029
5030
static void
5031
printkey_index(uint16_t keyix, char *buf, size_t buflen)
5032
{
5033
buf[0] = '\0';
5034
if (keyix == IEEE80211_KEYIX_NONE) {
5035
snprintf(buf, buflen, "ucast");
5036
} else {
5037
snprintf(buf, buflen, "%u", keyix+1);
5038
}
5039
}
5040
5041
static void
5042
printkey(if_ctx *ctx, const struct ieee80211req_key *ik)
5043
{
5044
static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
5045
u_int keylen = ik->ik_keylen;
5046
int printcontents;
5047
const int verbose = ctx->args->verbose;
5048
const bool printkeys = ctx->args->printkeys;
5049
char keyix[16];
5050
5051
printcontents = printkeys &&
5052
(memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
5053
if (printcontents)
5054
LINE_BREAK();
5055
printkey_index(ik->ik_keyix, keyix, sizeof(keyix));
5056
switch (ik->ik_type) {
5057
case IEEE80211_CIPHER_WEP:
5058
/* compatibility */
5059
LINE_CHECK("wepkey %s:%s", keyix,
5060
keylen <= 5 ? "40-bit" :
5061
keylen <= 13 ? "104-bit" : "128-bit");
5062
break;
5063
case IEEE80211_CIPHER_TKIP:
5064
if (keylen > 128/8)
5065
keylen -= 128/8; /* ignore MIC for now */
5066
LINE_CHECK("TKIP %s:%u-bit", keyix, 8*keylen);
5067
break;
5068
case IEEE80211_CIPHER_AES_OCB:
5069
LINE_CHECK("AES-OCB %s:%u-bit", keyix, 8*keylen);
5070
break;
5071
case IEEE80211_CIPHER_AES_CCM:
5072
LINE_CHECK("AES-CCM %s:%u-bit", keyix, 8*keylen);
5073
break;
5074
case IEEE80211_CIPHER_AES_GCM_128:
5075
LINE_CHECK("AES-GCM %s:%u-bit", keyix, 8*keylen);
5076
break;
5077
case IEEE80211_CIPHER_CKIP:
5078
LINE_CHECK("CKIP %s:%u-bit", keyix, 8*keylen);
5079
break;
5080
case IEEE80211_CIPHER_NONE:
5081
LINE_CHECK("NULL %s:%u-bit", keyix, 8*keylen);
5082
break;
5083
default:
5084
LINE_CHECK("UNKNOWN (0x%x) %s:%u-bit",
5085
ik->ik_type, keyix, 8*keylen);
5086
break;
5087
}
5088
if (printcontents) {
5089
u_int i;
5090
5091
printf(" <");
5092
for (i = 0; i < keylen; i++)
5093
printf("%02x", ik->ik_keydata[i]);
5094
printf(">");
5095
if (ik->ik_type != IEEE80211_CIPHER_WEP &&
5096
(ik->ik_keyrsc != 0 || verbose))
5097
printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
5098
if (ik->ik_type != IEEE80211_CIPHER_WEP &&
5099
(ik->ik_keytsc != 0 || verbose))
5100
printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
5101
if (ik->ik_flags != 0 && verbose) {
5102
const char *sep = " ";
5103
5104
if (ik->ik_flags & IEEE80211_KEY_XMIT)
5105
printf("%stx", sep), sep = "+";
5106
if (ik->ik_flags & IEEE80211_KEY_RECV)
5107
printf("%srx", sep), sep = "+";
5108
if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
5109
printf("%sdef", sep), sep = "+";
5110
}
5111
LINE_BREAK();
5112
}
5113
}
5114
5115
static void
5116
printrate(const char *tag, int v, int defrate, int defmcs)
5117
{
5118
if ((v & IEEE80211_RATE_MCS) == 0) {
5119
if (v != defrate) {
5120
if (v & 1)
5121
LINE_CHECK("%s %d.5", tag, v/2);
5122
else
5123
LINE_CHECK("%s %d", tag, v/2);
5124
}
5125
} else {
5126
if (v != defmcs)
5127
LINE_CHECK("%s %d", tag, v &~ 0x80);
5128
}
5129
}
5130
5131
static int
5132
getid(if_ctx *ctx, int ix, void *data, size_t len, int *plen, int mesh)
5133
{
5134
struct ieee80211req ireq = {};
5135
5136
strlcpy(ireq.i_name, ctx->ifname, sizeof(ireq.i_name));
5137
ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID;
5138
ireq.i_val = ix;
5139
ireq.i_data = data;
5140
ireq.i_len = len;
5141
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0)
5142
return -1;
5143
*plen = ireq.i_len;
5144
return 0;
5145
}
5146
5147
static int
5148
getdevicename(if_ctx *ctx, void *data, size_t len, int *plen)
5149
{
5150
struct ieee80211req ireq = {};
5151
5152
strlcpy(ireq.i_name, ctx->ifname, sizeof(ireq.i_name));
5153
ireq.i_type = IEEE80211_IOC_IC_NAME;
5154
ireq.i_val = -1;
5155
ireq.i_data = data;
5156
ireq.i_len = len;
5157
if (ioctl_ctx(ctx, SIOCG80211, &ireq) < 0)
5158
return (-1);
5159
*plen = ireq.i_len;
5160
return (0);
5161
}
5162
5163
static void
5164
ieee80211_status(if_ctx *ctx)
5165
{
5166
int s = ctx->io_s;
5167
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
5168
uint8_t bssid[IEEE80211_ADDR_LEN];
5169
enum ieee80211_opmode opmode = get80211opmode(ctx);
5170
int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode;
5171
uint8_t data[32];
5172
const struct ieee80211_channel *c;
5173
const struct ieee80211_roamparam *rp;
5174
const struct ieee80211_txparam *tp;
5175
const int verbose = ctx->args->verbose;
5176
5177
if (getid(ctx, -1, data, sizeof(data), &len, 0) < 0) {
5178
/* If we can't get the SSID, this isn't an 802.11 device. */
5179
return;
5180
}
5181
5182
/*
5183
* Invalidate cached state so printing status for multiple
5184
* if's doesn't reuse the first interfaces' cached state.
5185
*/
5186
gotcurchan = 0;
5187
gotroam = 0;
5188
gottxparams = 0;
5189
gothtconf = 0;
5190
gotregdomain = 0;
5191
5192
printf("\t");
5193
if (opmode == IEEE80211_M_MBSS) {
5194
printf("meshid ");
5195
getid(ctx, 0, data, sizeof(data), &len, 1);
5196
print_string(data, len);
5197
} else {
5198
if (get80211val(ctx, IEEE80211_IOC_NUMSSIDS, &num) < 0)
5199
num = 0;
5200
printf("ssid ");
5201
if (num > 1) {
5202
for (i = 0; i < num; i++) {
5203
if (getid(ctx, i, data, sizeof(data), &len, 0) >= 0 && len > 0) {
5204
printf(" %d:", i + 1);
5205
print_string(data, len);
5206
}
5207
}
5208
} else
5209
print_string(data, len);
5210
}
5211
c = getcurchan(ctx);
5212
if (c->ic_freq != IEEE80211_CHAN_ANY) {
5213
char buf[14];
5214
printf(" channel %d (%u MHz%s)", c->ic_ieee, c->ic_freq,
5215
get_chaninfo(c, 1, buf, sizeof(buf)));
5216
} else if (verbose)
5217
printf(" channel UNDEF");
5218
5219
if (get80211(ctx, IEEE80211_IOC_BSSID, bssid, IEEE80211_ADDR_LEN) >= 0 &&
5220
(memcmp(bssid, zerobssid, sizeof(zerobssid)) != 0 || verbose)) {
5221
printf(" bssid %s", ether_ntoa((struct ether_addr *)bssid));
5222
printbssidname((struct ether_addr *)bssid);
5223
}
5224
5225
if (get80211len(ctx, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) {
5226
printf("\n\tstationname ");
5227
print_string(data, len);
5228
}
5229
5230
spacer = ' '; /* force first break */
5231
LINE_BREAK();
5232
5233
list_regdomain(ctx, 0);
5234
5235
wpa = 0;
5236
if (get80211val(ctx, IEEE80211_IOC_AUTHMODE, &val) != -1) {
5237
switch (val) {
5238
case IEEE80211_AUTH_NONE:
5239
LINE_CHECK("authmode NONE");
5240
break;
5241
case IEEE80211_AUTH_OPEN:
5242
LINE_CHECK("authmode OPEN");
5243
break;
5244
case IEEE80211_AUTH_SHARED:
5245
LINE_CHECK("authmode SHARED");
5246
break;
5247
case IEEE80211_AUTH_8021X:
5248
LINE_CHECK("authmode 802.1x");
5249
break;
5250
case IEEE80211_AUTH_WPA:
5251
if (get80211val(ctx, IEEE80211_IOC_WPA, &wpa) < 0)
5252
wpa = 1; /* default to WPA1 */
5253
switch (wpa) {
5254
case 2:
5255
LINE_CHECK("authmode WPA2/802.11i");
5256
break;
5257
case 3:
5258
LINE_CHECK("authmode WPA1+WPA2/802.11i");
5259
break;
5260
default:
5261
LINE_CHECK("authmode WPA");
5262
break;
5263
}
5264
break;
5265
case IEEE80211_AUTH_AUTO:
5266
LINE_CHECK("authmode AUTO");
5267
break;
5268
default:
5269
LINE_CHECK("authmode UNKNOWN (0x%x)", val);
5270
break;
5271
}
5272
}
5273
5274
if (wpa || verbose) {
5275
if (get80211val(ctx, IEEE80211_IOC_WPS, &val) != -1) {
5276
if (val)
5277
LINE_CHECK("wps");
5278
else if (verbose)
5279
LINE_CHECK("-wps");
5280
}
5281
if (get80211val(ctx, IEEE80211_IOC_TSN, &val) != -1) {
5282
if (val)
5283
LINE_CHECK("tsn");
5284
else if (verbose)
5285
LINE_CHECK("-tsn");
5286
}
5287
if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) {
5288
if (val)
5289
LINE_CHECK("countermeasures");
5290
else if (verbose)
5291
LINE_CHECK("-countermeasures");
5292
}
5293
#if 0
5294
/* XXX not interesting with WPA done in user space */
5295
ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
5296
if (ioctl(s, SIOCG80211, &ireq) != -1) {
5297
}
5298
5299
ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
5300
if (ioctl(s, SIOCG80211, &ireq) != -1) {
5301
LINE_CHECK("mcastcipher ");
5302
printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
5303
spacer = ' ';
5304
}
5305
5306
ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
5307
if (ioctl(s, SIOCG80211, &ireq) != -1) {
5308
LINE_CHECK("ucastcipher ");
5309
printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
5310
}
5311
5312
if (wpa & 2) {
5313
ireq.i_type = IEEE80211_IOC_RSNCAPS;
5314
if (ioctl(s, SIOCG80211, &ireq) != -1) {
5315
LINE_CHECK("RSN caps 0x%x", ireq.i_val);
5316
spacer = ' ';
5317
}
5318
}
5319
5320
ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
5321
if (ioctl(s, SIOCG80211, &ireq) != -1) {
5322
}
5323
#endif
5324
}
5325
5326
if (get80211val(ctx, IEEE80211_IOC_WEP, &wepmode) != -1 &&
5327
wepmode != IEEE80211_WEP_NOSUP) {
5328
5329
switch (wepmode) {
5330
case IEEE80211_WEP_OFF:
5331
LINE_CHECK("privacy OFF");
5332
break;
5333
case IEEE80211_WEP_ON:
5334
LINE_CHECK("privacy ON");
5335
break;
5336
case IEEE80211_WEP_MIXED:
5337
LINE_CHECK("privacy MIXED");
5338
break;
5339
default:
5340
LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
5341
break;
5342
}
5343
5344
/*
5345
* If we get here then we've got WEP support so we need
5346
* to print WEP status.
5347
*/
5348
5349
if (get80211val(ctx, IEEE80211_IOC_WEPTXKEY, &val) < 0) {
5350
warn("WEP support, but no tx key!");
5351
goto end;
5352
}
5353
if (val != -1)
5354
LINE_CHECK("deftxkey %d", val+1);
5355
else if (wepmode != IEEE80211_WEP_OFF || verbose)
5356
LINE_CHECK("deftxkey UNDEF");
5357
5358
if (get80211val(ctx, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) {
5359
warn("WEP support, but no NUMWEPKEYS support!");
5360
goto end;
5361
}
5362
5363
for (i = 0; i < num; i++) {
5364
struct ieee80211req_key ik;
5365
5366
memset(&ik, 0, sizeof(ik));
5367
ik.ik_keyix = i;
5368
if (get80211(ctx, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) {
5369
warn("WEP support, but cannot get keys!");
5370
goto end;
5371
}
5372
if (ik.ik_keylen != 0) {
5373
if (verbose)
5374
LINE_BREAK();
5375
printkey(ctx, &ik);
5376
}
5377
}
5378
if (opmode == IEEE80211_M_STA && wpa >= 2) {
5379
struct ieee80211req_key ik;
5380
int error;
5381
5382
memset(&ik, 0, sizeof(ik));
5383
ik.ik_keyix = IEEE80211_KEYIX_NONE;
5384
memcpy(ik.ik_macaddr, bssid, sizeof(ik.ik_macaddr));
5385
error = get80211(ctx, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik));
5386
if (error == 0 && ik.ik_keylen != 0) {
5387
if (verbose)
5388
LINE_BREAK();
5389
printkey(ctx, &ik);
5390
i++;
5391
}
5392
}
5393
if (i > 0 && verbose)
5394
LINE_BREAK();
5395
end:
5396
;
5397
}
5398
5399
if (get80211val(ctx, IEEE80211_IOC_POWERSAVE, &val) != -1 &&
5400
val != IEEE80211_POWERSAVE_NOSUP ) {
5401
if (val != IEEE80211_POWERSAVE_OFF || verbose) {
5402
switch (val) {
5403
case IEEE80211_POWERSAVE_OFF:
5404
LINE_CHECK("powersavemode OFF");
5405
break;
5406
case IEEE80211_POWERSAVE_CAM:
5407
LINE_CHECK("powersavemode CAM");
5408
break;
5409
case IEEE80211_POWERSAVE_PSP:
5410
LINE_CHECK("powersavemode PSP");
5411
break;
5412
case IEEE80211_POWERSAVE_PSP_CAM:
5413
LINE_CHECK("powersavemode PSP-CAM");
5414
break;
5415
}
5416
if (get80211val(ctx, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1)
5417
LINE_CHECK("powersavesleep %d", val);
5418
}
5419
}
5420
5421
if (get80211val(ctx, IEEE80211_IOC_TXPOWER, &val) != -1) {
5422
if (val & 1)
5423
LINE_CHECK("txpower %d.5", val/2);
5424
else
5425
LINE_CHECK("txpower %d", val/2);
5426
}
5427
if (verbose) {
5428
if (get80211val(ctx, IEEE80211_IOC_TXPOWMAX, &val) != -1)
5429
LINE_CHECK("txpowmax %.1f", val/2.);
5430
}
5431
5432
if (get80211val(ctx, IEEE80211_IOC_DOTD, &val) != -1) {
5433
if (val)
5434
LINE_CHECK("dotd");
5435
else if (verbose)
5436
LINE_CHECK("-dotd");
5437
}
5438
5439
if (get80211val(ctx, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) {
5440
if (val != IEEE80211_RTS_MAX || verbose)
5441
LINE_CHECK("rtsthreshold %d", val);
5442
}
5443
5444
if (get80211val(ctx, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) {
5445
if (val != IEEE80211_FRAG_MAX || verbose)
5446
LINE_CHECK("fragthreshold %d", val);
5447
}
5448
if (opmode == IEEE80211_M_STA || verbose) {
5449
if (get80211val(ctx, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) {
5450
if (val != IEEE80211_HWBMISS_MAX || verbose)
5451
LINE_CHECK("bmiss %d", val);
5452
}
5453
}
5454
5455
if (!verbose) {
5456
gettxparams(ctx);
5457
tp = &txparams.params[chan2mode(c)];
5458
printrate("ucastrate", tp->ucastrate,
5459
IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE);
5460
printrate("mcastrate", tp->mcastrate, 2*1,
5461
IEEE80211_RATE_MCS|0);
5462
printrate("mgmtrate", tp->mgmtrate, 2*1,
5463
IEEE80211_RATE_MCS|0);
5464
if (tp->maxretry != 6) /* XXX */
5465
LINE_CHECK("maxretry %d", tp->maxretry);
5466
} else {
5467
LINE_BREAK();
5468
list_txparams(ctx);
5469
}
5470
5471
bgscaninterval = -1;
5472
(void) get80211val(ctx, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval);
5473
5474
if (get80211val(ctx, IEEE80211_IOC_SCANVALID, &val) != -1) {
5475
if (val != bgscaninterval || verbose)
5476
LINE_CHECK("scanvalid %u", val);
5477
}
5478
5479
bgscan = 0;
5480
if (get80211val(ctx, IEEE80211_IOC_BGSCAN, &bgscan) != -1) {
5481
if (bgscan)
5482
LINE_CHECK("bgscan");
5483
else if (verbose)
5484
LINE_CHECK("-bgscan");
5485
}
5486
if (bgscan || verbose) {
5487
if (bgscaninterval != -1)
5488
LINE_CHECK("bgscanintvl %u", bgscaninterval);
5489
if (get80211val(ctx, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1)
5490
LINE_CHECK("bgscanidle %u", val);
5491
if (!verbose) {
5492
getroam(ctx);
5493
rp = &roamparams.params[chan2mode(c)];
5494
if (rp->rssi & 1)
5495
LINE_CHECK("roam:rssi %u.5", rp->rssi/2);
5496
else
5497
LINE_CHECK("roam:rssi %u", rp->rssi/2);
5498
LINE_CHECK("roam:rate %s%u",
5499
(rp->rate & IEEE80211_RATE_MCS) ? "MCS " : "",
5500
get_rate_value(rp->rate));
5501
} else {
5502
LINE_BREAK();
5503
list_roam(ctx);
5504
LINE_BREAK();
5505
}
5506
}
5507
5508
if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
5509
if (get80211val(ctx, IEEE80211_IOC_PUREG, &val) != -1) {
5510
if (val)
5511
LINE_CHECK("pureg");
5512
else if (verbose)
5513
LINE_CHECK("-pureg");
5514
}
5515
if (get80211val(ctx, IEEE80211_IOC_PROTMODE, &val) != -1) {
5516
switch (val) {
5517
case IEEE80211_PROTMODE_OFF:
5518
LINE_CHECK("protmode OFF");
5519
break;
5520
case IEEE80211_PROTMODE_CTS:
5521
LINE_CHECK("protmode CTS");
5522
break;
5523
case IEEE80211_PROTMODE_RTSCTS:
5524
LINE_CHECK("protmode RTSCTS");
5525
break;
5526
default:
5527
LINE_CHECK("protmode UNKNOWN (0x%x)", val);
5528
break;
5529
}
5530
}
5531
}
5532
5533
if (IEEE80211_IS_CHAN_HT(c) || verbose) {
5534
gethtconf(ctx);
5535
switch (htconf & 3) {
5536
case 0:
5537
case 2:
5538
LINE_CHECK("-ht");
5539
break;
5540
case 1:
5541
LINE_CHECK("ht20");
5542
break;
5543
case 3:
5544
if (verbose)
5545
LINE_CHECK("ht");
5546
break;
5547
}
5548
if (get80211val(ctx, IEEE80211_IOC_HTCOMPAT, &val) != -1) {
5549
if (!val)
5550
LINE_CHECK("-htcompat");
5551
else if (verbose)
5552
LINE_CHECK("htcompat");
5553
}
5554
if (get80211val(ctx, IEEE80211_IOC_AMPDU, &val) != -1) {
5555
switch (val) {
5556
case 0:
5557
LINE_CHECK("-ampdu");
5558
break;
5559
case 1:
5560
LINE_CHECK("ampdutx -ampdurx");
5561
break;
5562
case 2:
5563
LINE_CHECK("-ampdutx ampdurx");
5564
break;
5565
case 3:
5566
if (verbose)
5567
LINE_CHECK("ampdu");
5568
break;
5569
}
5570
}
5571
/* XXX 11ac density/size is different */
5572
if (get80211val(ctx, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) {
5573
switch (val) {
5574
case IEEE80211_HTCAP_MAXRXAMPDU_8K:
5575
LINE_CHECK("ampdulimit 8k");
5576
break;
5577
case IEEE80211_HTCAP_MAXRXAMPDU_16K:
5578
LINE_CHECK("ampdulimit 16k");
5579
break;
5580
case IEEE80211_HTCAP_MAXRXAMPDU_32K:
5581
LINE_CHECK("ampdulimit 32k");
5582
break;
5583
case IEEE80211_HTCAP_MAXRXAMPDU_64K:
5584
LINE_CHECK("ampdulimit 64k");
5585
break;
5586
}
5587
}
5588
/* XXX 11ac density/size is different */
5589
if (get80211val(ctx, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) {
5590
switch (val) {
5591
case IEEE80211_HTCAP_MPDUDENSITY_NA:
5592
if (verbose)
5593
LINE_CHECK("ampdudensity NA");
5594
break;
5595
case IEEE80211_HTCAP_MPDUDENSITY_025:
5596
LINE_CHECK("ampdudensity .25");
5597
break;
5598
case IEEE80211_HTCAP_MPDUDENSITY_05:
5599
LINE_CHECK("ampdudensity .5");
5600
break;
5601
case IEEE80211_HTCAP_MPDUDENSITY_1:
5602
LINE_CHECK("ampdudensity 1");
5603
break;
5604
case IEEE80211_HTCAP_MPDUDENSITY_2:
5605
LINE_CHECK("ampdudensity 2");
5606
break;
5607
case IEEE80211_HTCAP_MPDUDENSITY_4:
5608
LINE_CHECK("ampdudensity 4");
5609
break;
5610
case IEEE80211_HTCAP_MPDUDENSITY_8:
5611
LINE_CHECK("ampdudensity 8");
5612
break;
5613
case IEEE80211_HTCAP_MPDUDENSITY_16:
5614
LINE_CHECK("ampdudensity 16");
5615
break;
5616
}
5617
}
5618
if (get80211val(ctx, IEEE80211_IOC_AMSDU, &val) != -1) {
5619
switch (val) {
5620
case 0:
5621
LINE_CHECK("-amsdu");
5622
break;
5623
case 1:
5624
LINE_CHECK("amsdutx -amsdurx");
5625
break;
5626
case 2:
5627
LINE_CHECK("-amsdutx amsdurx");
5628
break;
5629
case 3:
5630
if (verbose)
5631
LINE_CHECK("amsdu");
5632
break;
5633
}
5634
}
5635
/* XXX amsdu limit */
5636
if (get80211val(ctx, IEEE80211_IOC_SHORTGI, &val) != -1) {
5637
if (val)
5638
LINE_CHECK("shortgi");
5639
else if (verbose)
5640
LINE_CHECK("-shortgi");
5641
}
5642
if (get80211val(ctx, IEEE80211_IOC_HTPROTMODE, &val) != -1) {
5643
if (val == IEEE80211_PROTMODE_OFF)
5644
LINE_CHECK("htprotmode OFF");
5645
else if (val != IEEE80211_PROTMODE_RTSCTS)
5646
LINE_CHECK("htprotmode UNKNOWN (0x%x)", val);
5647
else if (verbose)
5648
LINE_CHECK("htprotmode RTSCTS");
5649
}
5650
if (get80211val(ctx, IEEE80211_IOC_PUREN, &val) != -1) {
5651
if (val)
5652
LINE_CHECK("puren");
5653
else if (verbose)
5654
LINE_CHECK("-puren");
5655
}
5656
if (get80211val(ctx, IEEE80211_IOC_SMPS, &val) != -1) {
5657
if (val == IEEE80211_HTCAP_SMPS_DYNAMIC)
5658
LINE_CHECK("smpsdyn");
5659
else if (val == IEEE80211_HTCAP_SMPS_ENA)
5660
LINE_CHECK("smps");
5661
else if (verbose)
5662
LINE_CHECK("-smps");
5663
}
5664
if (get80211val(ctx, IEEE80211_IOC_RIFS, &val) != -1) {
5665
if (val)
5666
LINE_CHECK("rifs");
5667
else if (verbose)
5668
LINE_CHECK("-rifs");
5669
}
5670
5671
/* XXX VHT STBC? */
5672
if (get80211val(ctx, IEEE80211_IOC_STBC, &val) != -1) {
5673
switch (val) {
5674
case 0:
5675
LINE_CHECK("-stbc");
5676
break;
5677
case 1:
5678
LINE_CHECK("stbctx -stbcrx");
5679
break;
5680
case 2:
5681
LINE_CHECK("-stbctx stbcrx");
5682
break;
5683
case 3:
5684
if (verbose)
5685
LINE_CHECK("stbc");
5686
break;
5687
}
5688
}
5689
if (get80211val(ctx, IEEE80211_IOC_LDPC, &val) != -1) {
5690
switch (val) {
5691
case 0:
5692
LINE_CHECK("-ldpc");
5693
break;
5694
case 1:
5695
LINE_CHECK("ldpctx -ldpcrx");
5696
break;
5697
case 2:
5698
LINE_CHECK("-ldpctx ldpcrx");
5699
break;
5700
case 3:
5701
if (verbose)
5702
LINE_CHECK("ldpc");
5703
break;
5704
}
5705
}
5706
if (get80211val(ctx, IEEE80211_IOC_UAPSD, &val) != -1) {
5707
switch (val) {
5708
case 0:
5709
LINE_CHECK("-uapsd");
5710
break;
5711
case 1:
5712
LINE_CHECK("uapsd");
5713
break;
5714
}
5715
}
5716
}
5717
5718
if (IEEE80211_IS_CHAN_VHT(c) || verbose) {
5719
getvhtconf(ctx);
5720
if (vhtconf & IEEE80211_FVHT_VHT) {
5721
LINE_CHECK("vht");
5722
5723
if (vhtconf & IEEE80211_FVHT_USEVHT40)
5724
LINE_CHECK("vht40");
5725
else
5726
LINE_CHECK("-vht40");
5727
if (vhtconf & IEEE80211_FVHT_USEVHT80)
5728
LINE_CHECK("vht80");
5729
else
5730
LINE_CHECK("-vht80");
5731
if (vhtconf & IEEE80211_FVHT_USEVHT160)
5732
LINE_CHECK("vht160");
5733
else
5734
LINE_CHECK("-vht160");
5735
if (vhtconf & IEEE80211_FVHT_USEVHT80P80)
5736
LINE_CHECK("vht80p80");
5737
else
5738
LINE_CHECK("-vht80p80");
5739
} else if (verbose)
5740
LINE_CHECK("-vht");
5741
}
5742
5743
if (get80211val(ctx, IEEE80211_IOC_WME, &wme) != -1) {
5744
if (wme)
5745
LINE_CHECK("wme");
5746
else if (verbose)
5747
LINE_CHECK("-wme");
5748
} else
5749
wme = 0;
5750
5751
if (get80211val(ctx, IEEE80211_IOC_BURST, &val) != -1) {
5752
if (val)
5753
LINE_CHECK("burst");
5754
else if (verbose)
5755
LINE_CHECK("-burst");
5756
}
5757
5758
if (get80211val(ctx, IEEE80211_IOC_FF, &val) != -1) {
5759
if (val)
5760
LINE_CHECK("ff");
5761
else if (verbose)
5762
LINE_CHECK("-ff");
5763
}
5764
if (get80211val(ctx, IEEE80211_IOC_TURBOP, &val) != -1) {
5765
if (val)
5766
LINE_CHECK("dturbo");
5767
else if (verbose)
5768
LINE_CHECK("-dturbo");
5769
}
5770
if (get80211val(ctx, IEEE80211_IOC_DWDS, &val) != -1) {
5771
if (val)
5772
LINE_CHECK("dwds");
5773
else if (verbose)
5774
LINE_CHECK("-dwds");
5775
}
5776
5777
if (opmode == IEEE80211_M_HOSTAP) {
5778
if (get80211val(ctx, IEEE80211_IOC_HIDESSID, &val) != -1) {
5779
if (val)
5780
LINE_CHECK("hidessid");
5781
else if (verbose)
5782
LINE_CHECK("-hidessid");
5783
}
5784
if (get80211val(ctx, IEEE80211_IOC_APBRIDGE, &val) != -1) {
5785
if (!val)
5786
LINE_CHECK("-apbridge");
5787
else if (verbose)
5788
LINE_CHECK("apbridge");
5789
}
5790
if (get80211val(ctx, IEEE80211_IOC_DTIM_PERIOD, &val) != -1)
5791
LINE_CHECK("dtimperiod %u", val);
5792
5793
if (get80211val(ctx, IEEE80211_IOC_DOTH, &val) != -1) {
5794
if (!val)
5795
LINE_CHECK("-doth");
5796
else if (verbose)
5797
LINE_CHECK("doth");
5798
}
5799
if (get80211val(ctx, IEEE80211_IOC_DFS, &val) != -1) {
5800
if (!val)
5801
LINE_CHECK("-dfs");
5802
else if (verbose)
5803
LINE_CHECK("dfs");
5804
}
5805
if (get80211val(ctx, IEEE80211_IOC_INACTIVITY, &val) != -1) {
5806
if (!val)
5807
LINE_CHECK("-inact");
5808
else if (verbose)
5809
LINE_CHECK("inact");
5810
}
5811
} else {
5812
if (get80211val(ctx, IEEE80211_IOC_ROAMING, &val) != -1) {
5813
if (val != IEEE80211_ROAMING_AUTO || verbose) {
5814
switch (val) {
5815
case IEEE80211_ROAMING_DEVICE:
5816
LINE_CHECK("roaming DEVICE");
5817
break;
5818
case IEEE80211_ROAMING_AUTO:
5819
LINE_CHECK("roaming AUTO");
5820
break;
5821
case IEEE80211_ROAMING_MANUAL:
5822
LINE_CHECK("roaming MANUAL");
5823
break;
5824
default:
5825
LINE_CHECK("roaming UNKNOWN (0x%x)",
5826
val);
5827
break;
5828
}
5829
}
5830
}
5831
}
5832
5833
if (opmode == IEEE80211_M_AHDEMO) {
5834
if (get80211val(ctx, IEEE80211_IOC_TDMA_SLOT, &val) != -1)
5835
LINE_CHECK("tdmaslot %u", val);
5836
if (get80211val(ctx, IEEE80211_IOC_TDMA_SLOTCNT, &val) != -1)
5837
LINE_CHECK("tdmaslotcnt %u", val);
5838
if (get80211val(ctx, IEEE80211_IOC_TDMA_SLOTLEN, &val) != -1)
5839
LINE_CHECK("tdmaslotlen %u", val);
5840
if (get80211val(ctx, IEEE80211_IOC_TDMA_BINTERVAL, &val) != -1)
5841
LINE_CHECK("tdmabintval %u", val);
5842
} else if (get80211val(ctx, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
5843
/* XXX default define not visible */
5844
if (val != 100 || verbose)
5845
LINE_CHECK("bintval %u", val);
5846
}
5847
5848
if (wme && verbose) {
5849
LINE_BREAK();
5850
list_wme(ctx);
5851
}
5852
5853
if (opmode == IEEE80211_M_MBSS) {
5854
if (get80211val(ctx, IEEE80211_IOC_MESH_TTL, &val) != -1) {
5855
LINE_CHECK("meshttl %u", val);
5856
}
5857
if (get80211val(ctx, IEEE80211_IOC_MESH_AP, &val) != -1) {
5858
if (val)
5859
LINE_CHECK("meshpeering");
5860
else
5861
LINE_CHECK("-meshpeering");
5862
}
5863
if (get80211val(ctx, IEEE80211_IOC_MESH_FWRD, &val) != -1) {
5864
if (val)
5865
LINE_CHECK("meshforward");
5866
else
5867
LINE_CHECK("-meshforward");
5868
}
5869
if (get80211val(ctx, IEEE80211_IOC_MESH_GATE, &val) != -1) {
5870
if (val)
5871
LINE_CHECK("meshgate");
5872
else
5873
LINE_CHECK("-meshgate");
5874
}
5875
if (get80211len(ctx, IEEE80211_IOC_MESH_PR_METRIC, data, 12,
5876
&len) != -1) {
5877
data[len] = '\0';
5878
LINE_CHECK("meshmetric %s", data);
5879
}
5880
if (get80211len(ctx, IEEE80211_IOC_MESH_PR_PATH, data, 12,
5881
&len) != -1) {
5882
data[len] = '\0';
5883
LINE_CHECK("meshpath %s", data);
5884
}
5885
if (get80211val(ctx, IEEE80211_IOC_HWMP_ROOTMODE, &val) != -1) {
5886
switch (val) {
5887
case IEEE80211_HWMP_ROOTMODE_DISABLED:
5888
LINE_CHECK("hwmprootmode DISABLED");
5889
break;
5890
case IEEE80211_HWMP_ROOTMODE_NORMAL:
5891
LINE_CHECK("hwmprootmode NORMAL");
5892
break;
5893
case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
5894
LINE_CHECK("hwmprootmode PROACTIVE");
5895
break;
5896
case IEEE80211_HWMP_ROOTMODE_RANN:
5897
LINE_CHECK("hwmprootmode RANN");
5898
break;
5899
default:
5900
LINE_CHECK("hwmprootmode UNKNOWN(%d)", val);
5901
break;
5902
}
5903
}
5904
if (get80211val(ctx, IEEE80211_IOC_HWMP_MAXHOPS, &val) != -1) {
5905
LINE_CHECK("hwmpmaxhops %u", val);
5906
}
5907
}
5908
5909
LINE_BREAK();
5910
5911
if (getdevicename(ctx, data, sizeof(data), &len) < 0)
5912
return;
5913
LINE_CHECK("parent interface: %s", data);
5914
5915
LINE_BREAK();
5916
}
5917
5918
static int
5919
get80211(if_ctx *ctx, int type, void *data, int len)
5920
{
5921
5922
return (lib80211_get80211(ctx->io_s, ctx->ifname, type, data, len));
5923
}
5924
5925
static int
5926
get80211len(if_ctx *ctx, int type, void *data, int len, int *plen)
5927
{
5928
5929
return (lib80211_get80211len(ctx->io_s, ctx->ifname, type, data, len, plen));
5930
}
5931
5932
static int
5933
get80211val(if_ctx *ctx, int type, int *val)
5934
{
5935
5936
return (lib80211_get80211val(ctx->io_s, ctx->ifname, type, val));
5937
}
5938
5939
static void
5940
set80211(if_ctx *ctx, int type, int val, int len, void *data)
5941
{
5942
int ret;
5943
5944
ret = lib80211_set80211(ctx->io_s, ctx->ifname, type, val, len, data);
5945
if (ret < 0)
5946
err(1, "SIOCS80211");
5947
}
5948
5949
static const char *
5950
get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
5951
{
5952
int len;
5953
int hexstr;
5954
u_int8_t *p;
5955
5956
len = *lenp;
5957
p = buf;
5958
hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
5959
if (hexstr)
5960
val += 2;
5961
for (;;) {
5962
if (*val == '\0')
5963
break;
5964
if (sep != NULL && strchr(sep, *val) != NULL) {
5965
val++;
5966
break;
5967
}
5968
if (hexstr) {
5969
if (!isxdigit((u_char)val[0])) {
5970
warnx("bad hexadecimal digits");
5971
return NULL;
5972
}
5973
if (!isxdigit((u_char)val[1])) {
5974
warnx("odd count hexadecimal digits");
5975
return NULL;
5976
}
5977
}
5978
if (p >= buf + len) {
5979
if (hexstr)
5980
warnx("hexadecimal digits too long");
5981
else
5982
warnx("string too long");
5983
return NULL;
5984
}
5985
if (hexstr) {
5986
#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
5987
*p++ = (tohex((u_char)val[0]) << 4) |
5988
tohex((u_char)val[1]);
5989
#undef tohex
5990
val += 2;
5991
} else
5992
*p++ = *val++;
5993
}
5994
len = p - buf;
5995
/* The string "-" is treated as the empty string. */
5996
if (!hexstr && len == 1 && buf[0] == '-') {
5997
len = 0;
5998
memset(buf, 0, *lenp);
5999
} else if (len < *lenp)
6000
memset(p, 0, *lenp - len);
6001
*lenp = len;
6002
return val;
6003
}
6004
6005
static void
6006
print_string(const u_int8_t *buf, int len)
6007
{
6008
int i;
6009
int hasspc;
6010
int utf8;
6011
6012
i = 0;
6013
hasspc = 0;
6014
6015
setlocale(LC_CTYPE, "");
6016
utf8 = strncmp("UTF-8", nl_langinfo(CODESET), 5) == 0;
6017
6018
for (; i < len; i++) {
6019
if (!isprint(buf[i]) && buf[i] != '\0' && !utf8)
6020
break;
6021
if (isspace(buf[i]))
6022
hasspc++;
6023
}
6024
if (i == len || utf8) {
6025
if (hasspc || len == 0 || buf[0] == '\0')
6026
printf("\"%.*s\"", len, buf);
6027
else
6028
printf("%.*s", len, buf);
6029
} else {
6030
printf("0x");
6031
for (i = 0; i < len; i++)
6032
printf("%02x", buf[i]);
6033
}
6034
}
6035
6036
static void
6037
setdefregdomain(if_ctx *ctx)
6038
{
6039
struct regdata *rdp = getregdata();
6040
const struct regdomain *rd;
6041
6042
/* Check if regdomain/country was already set by a previous call. */
6043
/* XXX is it possible? */
6044
if (regdomain.regdomain != 0 ||
6045
regdomain.country != CTRY_DEFAULT)
6046
return;
6047
6048
getregdomain(ctx);
6049
6050
/* Check if it was already set by the driver. */
6051
if (regdomain.regdomain != 0 ||
6052
regdomain.country != CTRY_DEFAULT)
6053
return;
6054
6055
/* Set FCC/US as default. */
6056
rd = lib80211_regdomain_findbysku(rdp, SKU_FCC);
6057
if (rd == NULL)
6058
errx(1, "FCC regdomain was not found");
6059
6060
regdomain.regdomain = rd->sku;
6061
if (rd->cc != NULL)
6062
defaultcountry(rd);
6063
6064
/* Send changes to net80211. */
6065
setregdomain_cb(ctx, &regdomain);
6066
6067
/* Cleanup (so it can be overridden by subsequent parameters). */
6068
regdomain.regdomain = 0;
6069
regdomain.country = CTRY_DEFAULT;
6070
regdomain.isocc[0] = 0;
6071
regdomain.isocc[1] = 0;
6072
}
6073
6074
/*
6075
* Virtual AP cloning support.
6076
*/
6077
static struct ieee80211_clone_params params = {
6078
.icp_opmode = IEEE80211_M_STA, /* default to station mode */
6079
};
6080
6081
static void
6082
wlan_create(if_ctx *ctx, struct ifreq *ifr)
6083
{
6084
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
6085
6086
if (params.icp_parent[0] == '\0')
6087
errx(1, "must specify a parent device (wlandev) when creating "
6088
"a wlan device");
6089
if (params.icp_opmode == IEEE80211_M_WDS &&
6090
memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0)
6091
errx(1, "no bssid specified for WDS (use wlanbssid)");
6092
ifr->ifr_data = (caddr_t) &params;
6093
ifcreate_ioctl(ctx, ifr);
6094
6095
setdefregdomain(ctx);
6096
}
6097
6098
static void
6099
set80211clone_wlandev(if_ctx *ctx __unused, const char *arg, int dummy __unused)
6100
{
6101
strlcpy(params.icp_parent, arg, IFNAMSIZ);
6102
}
6103
6104
static void
6105
set80211clone_wlanbssid(if_ctx *ctx __unused, const char *arg, int dummy __unused)
6106
{
6107
const struct ether_addr *ea;
6108
6109
ea = ether_aton(arg);
6110
if (ea == NULL)
6111
errx(1, "%s: cannot parse bssid", arg);
6112
memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN);
6113
}
6114
6115
static void
6116
set80211clone_wlanaddr(if_ctx *ctx __unused, const char *arg, int dummy __unused)
6117
{
6118
const struct ether_addr *ea;
6119
6120
ea = ether_aton(arg);
6121
if (ea == NULL)
6122
errx(1, "%s: cannot parse address", arg);
6123
memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN);
6124
params.icp_flags |= IEEE80211_CLONE_MACADDR;
6125
}
6126
6127
static void
6128
set80211clone_wlanmode(if_ctx *ctx, const char *arg, int dummy __unused)
6129
{
6130
#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
6131
if (iseq(arg, "sta"))
6132
params.icp_opmode = IEEE80211_M_STA;
6133
else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo"))
6134
params.icp_opmode = IEEE80211_M_AHDEMO;
6135
else if (iseq(arg, "ibss") || iseq(arg, "adhoc"))
6136
params.icp_opmode = IEEE80211_M_IBSS;
6137
else if (iseq(arg, "ap") || iseq(arg, "host"))
6138
params.icp_opmode = IEEE80211_M_HOSTAP;
6139
else if (iseq(arg, "wds"))
6140
params.icp_opmode = IEEE80211_M_WDS;
6141
else if (iseq(arg, "monitor"))
6142
params.icp_opmode = IEEE80211_M_MONITOR;
6143
else if (iseq(arg, "tdma")) {
6144
params.icp_opmode = IEEE80211_M_AHDEMO;
6145
params.icp_flags |= IEEE80211_CLONE_TDMA;
6146
} else if (iseq(arg, "mesh") || iseq(arg, "mp")) /* mesh point */
6147
params.icp_opmode = IEEE80211_M_MBSS;
6148
else
6149
errx(1, "Don't know to create %s for %s", arg, ctx->ifname);
6150
#undef iseq
6151
}
6152
6153
static void
6154
set80211clone_beacons(if_ctx *ctx __unused, const char *val __unused, int d)
6155
{
6156
/* NB: inverted sense */
6157
if (d)
6158
params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS;
6159
else
6160
params.icp_flags |= IEEE80211_CLONE_NOBEACONS;
6161
}
6162
6163
static void
6164
set80211clone_bssid(if_ctx *ctx __unused, const char *val __unused, int d)
6165
{
6166
if (d)
6167
params.icp_flags |= IEEE80211_CLONE_BSSID;
6168
else
6169
params.icp_flags &= ~IEEE80211_CLONE_BSSID;
6170
}
6171
6172
static void
6173
set80211clone_wdslegacy(if_ctx *ctx __unused, const char *val __unused, int d)
6174
{
6175
if (d)
6176
params.icp_flags |= IEEE80211_CLONE_WDSLEGACY;
6177
else
6178
params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY;
6179
}
6180
6181
static struct cmd ieee80211_cmds[] = {
6182
DEF_CMD_ARG("ssid", set80211ssid),
6183
DEF_CMD_ARG("nwid", set80211ssid),
6184
DEF_CMD_ARG("meshid", set80211meshid),
6185
DEF_CMD_ARG("stationname", set80211stationname),
6186
DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
6187
DEF_CMD_ARG("channel", set80211channel),
6188
DEF_CMD_ARG("authmode", set80211authmode),
6189
DEF_CMD_ARG("powersavemode", set80211powersavemode),
6190
DEF_CMD("powersave", 1, set80211powersave),
6191
DEF_CMD("-powersave", 0, set80211powersave),
6192
DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
6193
DEF_CMD_ARG("wepmode", set80211wepmode),
6194
DEF_CMD("wep", 1, set80211wep),
6195
DEF_CMD("-wep", 0, set80211wep),
6196
DEF_CMD_ARG("deftxkey", set80211weptxkey),
6197
DEF_CMD_ARG("weptxkey", set80211weptxkey),
6198
DEF_CMD_ARG("wepkey", set80211wepkey),
6199
DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
6200
DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
6201
DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
6202
DEF_CMD_ARG("protmode", set80211protmode),
6203
DEF_CMD_ARG("txpower", set80211txpower),
6204
DEF_CMD_ARG("roaming", set80211roaming),
6205
DEF_CMD("wme", 1, set80211wme),
6206
DEF_CMD("-wme", 0, set80211wme),
6207
DEF_CMD("wmm", 1, set80211wme),
6208
DEF_CMD("-wmm", 0, set80211wme),
6209
DEF_CMD("hidessid", 1, set80211hidessid),
6210
DEF_CMD("-hidessid", 0, set80211hidessid),
6211
DEF_CMD("apbridge", 1, set80211apbridge),
6212
DEF_CMD("-apbridge", 0, set80211apbridge),
6213
DEF_CMD_ARG("chanlist", set80211chanlist),
6214
DEF_CMD_ARG("bssid", set80211bssid),
6215
DEF_CMD_ARG("ap", set80211bssid),
6216
DEF_CMD("scan", 0, set80211scan),
6217
DEF_CMD_ARG("list", set80211list),
6218
DEF_CMD_ARG2("cwmin", set80211cwmin),
6219
DEF_CMD_ARG2("cwmax", set80211cwmax),
6220
DEF_CMD_ARG2("aifs", set80211aifs),
6221
DEF_CMD_ARG2("txoplimit", set80211txoplimit),
6222
DEF_CMD_ARG("acm", set80211acm),
6223
DEF_CMD_ARG("-acm", set80211noacm),
6224
DEF_CMD_ARG("ack", set80211ackpolicy),
6225
DEF_CMD_ARG("-ack", set80211noackpolicy),
6226
DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
6227
DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
6228
DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
6229
DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
6230
DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
6231
DEF_CMD_ARG("bintval", set80211bintval),
6232
DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
6233
DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
6234
DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
6235
DEF_CMD("mac:radius", IEEE80211_MACCMD_POLICY_RADIUS, set80211maccmd),
6236
DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
6237
DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
6238
DEF_CMD_ARG("mac:add", set80211addmac),
6239
DEF_CMD_ARG("mac:del", set80211delmac),
6240
DEF_CMD_ARG("mac:kick", set80211kickmac),
6241
DEF_CMD("pureg", 1, set80211pureg),
6242
DEF_CMD("-pureg", 0, set80211pureg),
6243
DEF_CMD("ff", 1, set80211fastframes),
6244
DEF_CMD("-ff", 0, set80211fastframes),
6245
DEF_CMD("dturbo", 1, set80211dturbo),
6246
DEF_CMD("-dturbo", 0, set80211dturbo),
6247
DEF_CMD("bgscan", 1, set80211bgscan),
6248
DEF_CMD("-bgscan", 0, set80211bgscan),
6249
DEF_CMD_ARG("bgscanidle", set80211bgscanidle),
6250
DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl),
6251
DEF_CMD_ARG("scanvalid", set80211scanvalid),
6252
DEF_CMD("quiet", 1, set80211quiet),
6253
DEF_CMD("-quiet", 0, set80211quiet),
6254
DEF_CMD_ARG("quiet_count", set80211quietcount),
6255
DEF_CMD_ARG("quiet_period", set80211quietperiod),
6256
DEF_CMD_ARG("quiet_duration", set80211quietduration),
6257
DEF_CMD_ARG("quiet_offset", set80211quietoffset),
6258
DEF_CMD_ARG("roam:rssi", set80211roamrssi),
6259
DEF_CMD_ARG("roam:rate", set80211roamrate),
6260
DEF_CMD_ARG("mcastrate", set80211mcastrate),
6261
DEF_CMD_ARG("ucastrate", set80211ucastrate),
6262
DEF_CMD_ARG("mgtrate", set80211mgtrate),
6263
DEF_CMD_ARG("mgmtrate", set80211mgtrate),
6264
DEF_CMD_ARG("maxretry", set80211maxretry),
6265
DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
6266
DEF_CMD("burst", 1, set80211burst),
6267
DEF_CMD("-burst", 0, set80211burst),
6268
DEF_CMD_ARG("bmiss", set80211bmissthreshold),
6269
DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold),
6270
DEF_CMD("shortgi", 1, set80211shortgi),
6271
DEF_CMD("-shortgi", 0, set80211shortgi),
6272
DEF_CMD("ampdurx", 2, set80211ampdu),
6273
DEF_CMD("-ampdurx", -2, set80211ampdu),
6274
DEF_CMD("ampdutx", 1, set80211ampdu),
6275
DEF_CMD("-ampdutx", -1, set80211ampdu),
6276
DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */
6277
DEF_CMD("-ampdu", -3, set80211ampdu),
6278
DEF_CMD_ARG("ampdulimit", set80211ampdulimit),
6279
DEF_CMD_ARG("ampdudensity", set80211ampdudensity),
6280
DEF_CMD("amsdurx", 2, set80211amsdu),
6281
DEF_CMD("-amsdurx", -2, set80211amsdu),
6282
DEF_CMD("amsdutx", 1, set80211amsdu),
6283
DEF_CMD("-amsdutx", -1, set80211amsdu),
6284
DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */
6285
DEF_CMD("-amsdu", -3, set80211amsdu),
6286
DEF_CMD_ARG("amsdulimit", set80211amsdulimit),
6287
DEF_CMD("stbcrx", 2, set80211stbc),
6288
DEF_CMD("-stbcrx", -2, set80211stbc),
6289
DEF_CMD("stbctx", 1, set80211stbc),
6290
DEF_CMD("-stbctx", -1, set80211stbc),
6291
DEF_CMD("stbc", 3, set80211stbc), /* NB: tx+rx */
6292
DEF_CMD("-stbc", -3, set80211stbc),
6293
DEF_CMD("ldpcrx", 2, set80211ldpc),
6294
DEF_CMD("-ldpcrx", -2, set80211ldpc),
6295
DEF_CMD("ldpctx", 1, set80211ldpc),
6296
DEF_CMD("-ldpctx", -1, set80211ldpc),
6297
DEF_CMD("ldpc", 3, set80211ldpc), /* NB: tx+rx */
6298
DEF_CMD("-ldpc", -3, set80211ldpc),
6299
DEF_CMD("uapsd", 1, set80211uapsd),
6300
DEF_CMD("-uapsd", 0, set80211uapsd),
6301
DEF_CMD("puren", 1, set80211puren),
6302
DEF_CMD("-puren", 0, set80211puren),
6303
DEF_CMD("doth", 1, set80211doth),
6304
DEF_CMD("-doth", 0, set80211doth),
6305
DEF_CMD("dfs", 1, set80211dfs),
6306
DEF_CMD("-dfs", 0, set80211dfs),
6307
DEF_CMD("htcompat", 1, set80211htcompat),
6308
DEF_CMD("-htcompat", 0, set80211htcompat),
6309
DEF_CMD("dwds", 1, set80211dwds),
6310
DEF_CMD("-dwds", 0, set80211dwds),
6311
DEF_CMD("inact", 1, set80211inact),
6312
DEF_CMD("-inact", 0, set80211inact),
6313
DEF_CMD("tsn", 1, set80211tsn),
6314
DEF_CMD("-tsn", 0, set80211tsn),
6315
DEF_CMD_ARG("regdomain", set80211regdomain),
6316
DEF_CMD_ARG("country", set80211country),
6317
DEF_CMD("indoor", 'I', set80211location),
6318
DEF_CMD("-indoor", 'O', set80211location),
6319
DEF_CMD("outdoor", 'O', set80211location),
6320
DEF_CMD("-outdoor", 'I', set80211location),
6321
DEF_CMD("anywhere", ' ', set80211location),
6322
DEF_CMD("ecm", 1, set80211ecm),
6323
DEF_CMD("-ecm", 0, set80211ecm),
6324
DEF_CMD("dotd", 1, set80211dotd),
6325
DEF_CMD("-dotd", 0, set80211dotd),
6326
DEF_CMD_ARG("htprotmode", set80211htprotmode),
6327
DEF_CMD("ht20", 1, set80211htconf),
6328
DEF_CMD("-ht20", 0, set80211htconf),
6329
DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */
6330
DEF_CMD("-ht40", 0, set80211htconf),
6331
DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */
6332
DEF_CMD("-ht", 0, set80211htconf),
6333
DEF_CMD("vht", IEEE80211_FVHT_VHT, set80211vhtconf),
6334
DEF_CMD("-vht", -IEEE80211_FVHT_VHT, set80211vhtconf),
6335
DEF_CMD("vht40", IEEE80211_FVHT_USEVHT40, set80211vhtconf),
6336
DEF_CMD("-vht40", -IEEE80211_FVHT_USEVHT40, set80211vhtconf),
6337
DEF_CMD("vht80", IEEE80211_FVHT_USEVHT80, set80211vhtconf),
6338
DEF_CMD("-vht80", -IEEE80211_FVHT_USEVHT80, set80211vhtconf),
6339
DEF_CMD("vht160", IEEE80211_FVHT_USEVHT160, set80211vhtconf),
6340
DEF_CMD("-vht160", -IEEE80211_FVHT_USEVHT160, set80211vhtconf),
6341
DEF_CMD("vht80p80", IEEE80211_FVHT_USEVHT80P80, set80211vhtconf),
6342
DEF_CMD("-vht80p80", -IEEE80211_FVHT_USEVHT80P80, set80211vhtconf),
6343
DEF_CMD("vhtstbctx", IEEE80211_FVHT_STBC_TX, set80211vhtconf),
6344
DEF_CMD("-vhtstbctx", -IEEE80211_FVHT_STBC_TX, set80211vhtconf),
6345
DEF_CMD("vhtstbcrx", IEEE80211_FVHT_STBC_RX, set80211vhtconf),
6346
DEF_CMD("-vhtstbcrx", -IEEE80211_FVHT_STBC_RX, set80211vhtconf),
6347
DEF_CMD("vhtstbc", (IEEE80211_FVHT_STBC_TX|IEEE80211_FVHT_STBC_RX), set80211vhtconf),
6348
DEF_CMD("-vhtstbc", -(IEEE80211_FVHT_STBC_TX|IEEE80211_FVHT_STBC_RX), set80211vhtconf),
6349
DEF_CMD("rifs", 1, set80211rifs),
6350
DEF_CMD("-rifs", 0, set80211rifs),
6351
DEF_CMD("smps", IEEE80211_HTCAP_SMPS_ENA, set80211smps),
6352
DEF_CMD("smpsdyn", IEEE80211_HTCAP_SMPS_DYNAMIC, set80211smps),
6353
DEF_CMD("-smps", IEEE80211_HTCAP_SMPS_OFF, set80211smps),
6354
/* XXX for testing */
6355
DEF_CMD_ARG("chanswitch", set80211chanswitch),
6356
6357
DEF_CMD_ARG("tdmaslot", set80211tdmaslot),
6358
DEF_CMD_ARG("tdmaslotcnt", set80211tdmaslotcnt),
6359
DEF_CMD_ARG("tdmaslotlen", set80211tdmaslotlen),
6360
DEF_CMD_ARG("tdmabintval", set80211tdmabintval),
6361
6362
DEF_CMD_ARG("meshttl", set80211meshttl),
6363
DEF_CMD("meshforward", 1, set80211meshforward),
6364
DEF_CMD("-meshforward", 0, set80211meshforward),
6365
DEF_CMD("meshgate", 1, set80211meshgate),
6366
DEF_CMD("-meshgate", 0, set80211meshgate),
6367
DEF_CMD("meshpeering", 1, set80211meshpeering),
6368
DEF_CMD("-meshpeering", 0, set80211meshpeering),
6369
DEF_CMD_ARG("meshmetric", set80211meshmetric),
6370
DEF_CMD_ARG("meshpath", set80211meshpath),
6371
DEF_CMD("meshrt:flush", IEEE80211_MESH_RTCMD_FLUSH, set80211meshrtcmd),
6372
DEF_CMD_ARG("meshrt:add", set80211addmeshrt),
6373
DEF_CMD_ARG("meshrt:del", set80211delmeshrt),
6374
DEF_CMD_ARG("hwmprootmode", set80211hwmprootmode),
6375
DEF_CMD_ARG("hwmpmaxhops", set80211hwmpmaxhops),
6376
6377
/* vap cloning support */
6378
DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr),
6379
DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid),
6380
DEF_CLONE_CMD_ARG("wlandev", set80211clone_wlandev),
6381
DEF_CLONE_CMD_ARG("wlanmode", set80211clone_wlanmode),
6382
DEF_CLONE_CMD("beacons", 1, set80211clone_beacons),
6383
DEF_CLONE_CMD("-beacons", 0, set80211clone_beacons),
6384
DEF_CLONE_CMD("bssid", 1, set80211clone_bssid),
6385
DEF_CLONE_CMD("-bssid", 0, set80211clone_bssid),
6386
DEF_CLONE_CMD("wdslegacy", 1, set80211clone_wdslegacy),
6387
DEF_CLONE_CMD("-wdslegacy", 0, set80211clone_wdslegacy),
6388
};
6389
static struct afswtch af_ieee80211 = {
6390
.af_name = "af_ieee80211",
6391
.af_af = AF_UNSPEC,
6392
.af_other_status = ieee80211_status,
6393
};
6394
6395
static __constructor void
6396
ieee80211_ctor(void)
6397
{
6398
for (size_t i = 0; i < nitems(ieee80211_cmds); i++)
6399
cmd_register(&ieee80211_cmds[i]);
6400
af_register(&af_ieee80211);
6401
clone_setdefcallback_prefix("wlan", wlan_create);
6402
}
6403
6404