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