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