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