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