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