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