ifieee80211.c revision 181454
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 181454 2008-08-09 05:37:22Z 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/* XXX move to a public include file */ 2445#define IEEE80211_WPS_DEV_PASS_ID 0x1012 2446#define IEEE80211_WPS_SELECTED_REG 0x1041 2447#define IEEE80211_WPS_SETUP_STATE 0x1044 2448#define IEEE80211_WPS_UUID_E 0x1047 2449#define IEEE80211_WPS_VERSION 0x104a 2450 2451#define BE_READ_2(p) \ 2452 ((u_int16_t) \ 2453 ((((const u_int8_t *)(p))[1] ) | \ 2454 (((const u_int8_t *)(p))[0] << 8))) 2455 2456static void 2457printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2458{ 2459#define N(a) (sizeof(a) / sizeof(a[0])) 2460 u_int8_t len = ie[1]; 2461 2462 printf("%s", tag); 2463 if (verbose) { 2464 static const char *dev_pass_id[] = { 2465 "D", /* Default (PIN) */ 2466 "U", /* User-specified */ 2467 "M", /* Machine-specified */ 2468 "K", /* Rekey */ 2469 "P", /* PushButton */ 2470 "R" /* Registrar-specified */ 2471 }; 2472 int n; 2473 2474 ie +=6, len -= 4; /* NB: len is payload only */ 2475 2476 /* WPS IE in Beacon and Probe Resp frames have different fields */ 2477 printf("<"); 2478 while (len) { 2479 uint16_t tlv_type = BE_READ_2(ie); 2480 uint16_t tlv_len = BE_READ_2(ie + 2); 2481 2482 ie += 4, len -= 4; 2483 2484 switch (tlv_type) { 2485 case IEEE80211_WPS_VERSION: 2486 printf("v:%d.%d", *ie >> 4, *ie & 0xf); 2487 break; 2488 case IEEE80211_WPS_SETUP_STATE: 2489 /* Only 1 and 2 are valid */ 2490 if (*ie == 0 || *ie >= 3) 2491 printf(" state:B"); 2492 else 2493 printf(" st:%s", *ie == 1 ? "N" : "C"); 2494 break; 2495 case IEEE80211_WPS_SELECTED_REG: 2496 printf(" sel:%s", *ie ? "T" : "F"); 2497 break; 2498 case IEEE80211_WPS_DEV_PASS_ID: 2499 n = LE_READ_2(ie); 2500 if (n < N(dev_pass_id)) 2501 printf(" dpi:%s", dev_pass_id[n]); 2502 break; 2503 case IEEE80211_WPS_UUID_E: 2504 printf(" uuid-e:"); 2505 for (n = 0; n < (tlv_len - 1); n++) 2506 printf("%02x-", ie[n]); 2507 printf("%02x", ie[n]); 2508 break; 2509 } 2510 ie += tlv_len, len -= tlv_len; 2511 } 2512 printf(">"); 2513 } 2514#undef N 2515} 2516 2517/* 2518 * Copy the ssid string contents into buf, truncating to fit. If the 2519 * ssid is entirely printable then just copy intact. Otherwise convert 2520 * to hexadecimal. If the result is truncated then replace the last 2521 * three characters with "...". 2522 */ 2523static int 2524copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 2525{ 2526 const u_int8_t *p; 2527 size_t maxlen; 2528 int i; 2529 2530 if (essid_len > bufsize) 2531 maxlen = bufsize; 2532 else 2533 maxlen = essid_len; 2534 /* determine printable or not */ 2535 for (i = 0, p = essid; i < maxlen; i++, p++) { 2536 if (*p < ' ' || *p > 0x7e) 2537 break; 2538 } 2539 if (i != maxlen) { /* not printable, print as hex */ 2540 if (bufsize < 3) 2541 return 0; 2542 strlcpy(buf, "0x", bufsize); 2543 bufsize -= 2; 2544 p = essid; 2545 for (i = 0; i < maxlen && bufsize >= 2; i++) { 2546 sprintf(&buf[2+2*i], "%02x", p[i]); 2547 bufsize -= 2; 2548 } 2549 if (i != essid_len) 2550 memcpy(&buf[2+2*i-3], "...", 3); 2551 } else { /* printable, truncate as needed */ 2552 memcpy(buf, essid, maxlen); 2553 if (maxlen != essid_len) 2554 memcpy(&buf[maxlen-3], "...", 3); 2555 } 2556 return maxlen; 2557} 2558 2559static void 2560printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2561{ 2562 char ssid[2*IEEE80211_NWID_LEN+1]; 2563 2564 printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); 2565} 2566 2567static void 2568printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2569{ 2570 const char *sep; 2571 int i; 2572 2573 printf("%s", tag); 2574 sep = "<"; 2575 for (i = 2; i < ielen; i++) { 2576 printf("%s%s%d", sep, 2577 ie[i] & IEEE80211_RATE_BASIC ? "B" : "", 2578 ie[i] & IEEE80211_RATE_VAL); 2579 sep = ","; 2580 } 2581 printf(">"); 2582} 2583 2584static void 2585printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2586{ 2587 const struct ieee80211_country_ie *cie = 2588 (const struct ieee80211_country_ie *) ie; 2589 int i, nbands, schan, nchan; 2590 2591 printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); 2592 nbands = (cie->len - 3) / sizeof(cie->band[0]); 2593 for (i = 0; i < nbands; i++) { 2594 schan = cie->band[i].schan; 2595 nchan = cie->band[i].nchan; 2596 if (nchan != 1) 2597 printf(" %u-%u,%u", schan, schan + nchan-1, 2598 cie->band[i].maxtxpwr); 2599 else 2600 printf(" %u,%u", schan, cie->band[i].maxtxpwr); 2601 } 2602 printf(">"); 2603} 2604 2605/* unaligned little endian access */ 2606#define LE_READ_4(p) \ 2607 ((u_int32_t) \ 2608 ((((const u_int8_t *)(p))[0] ) | \ 2609 (((const u_int8_t *)(p))[1] << 8) | \ 2610 (((const u_int8_t *)(p))[2] << 16) | \ 2611 (((const u_int8_t *)(p))[3] << 24))) 2612 2613static __inline int 2614iswpaoui(const u_int8_t *frm) 2615{ 2616 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 2617} 2618 2619static __inline int 2620iswmeinfo(const u_int8_t *frm) 2621{ 2622 return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 2623 frm[6] == WME_INFO_OUI_SUBTYPE; 2624} 2625 2626static __inline int 2627iswmeparam(const u_int8_t *frm) 2628{ 2629 return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 2630 frm[6] == WME_PARAM_OUI_SUBTYPE; 2631} 2632 2633static __inline int 2634isatherosoui(const u_int8_t *frm) 2635{ 2636 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 2637} 2638 2639static __inline int 2640iswpsoui(const uint8_t *frm) 2641{ 2642 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI); 2643} 2644 2645static const char * 2646iename(int elemid) 2647{ 2648 switch (elemid) { 2649 case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; 2650 case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; 2651 case IEEE80211_ELEMID_TIM: return " TIM"; 2652 case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; 2653 case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; 2654 case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; 2655 case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; 2656 case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; 2657 case IEEE80211_ELEMID_TPCREP: return " TPCREP"; 2658 case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; 2659 case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA"; 2660 case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; 2661 case IEEE80211_ELEMID_MEASREP: return " MEASREP"; 2662 case IEEE80211_ELEMID_QUIET: return " QUIET"; 2663 case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; 2664 case IEEE80211_ELEMID_TPC: return " TPC"; 2665 case IEEE80211_ELEMID_CCKM: return " CCKM"; 2666 } 2667 return " ???"; 2668} 2669 2670static void 2671printies(const u_int8_t *vp, int ielen, int maxcols) 2672{ 2673 while (ielen > 0) { 2674 switch (vp[0]) { 2675 case IEEE80211_ELEMID_SSID: 2676 if (verbose) 2677 printssid(" SSID", vp, 2+vp[1], maxcols); 2678 break; 2679 case IEEE80211_ELEMID_RATES: 2680 case IEEE80211_ELEMID_XRATES: 2681 if (verbose) 2682 printrates(vp[0] == IEEE80211_ELEMID_RATES ? 2683 " RATES" : " XRATES", vp, 2+vp[1], maxcols); 2684 break; 2685 case IEEE80211_ELEMID_DSPARMS: 2686 if (verbose) 2687 printf(" DSPARMS<%u>", vp[2]); 2688 break; 2689 case IEEE80211_ELEMID_COUNTRY: 2690 if (verbose) 2691 printcountry(" COUNTRY", vp, 2+vp[1], maxcols); 2692 break; 2693 case IEEE80211_ELEMID_ERP: 2694 if (verbose) 2695 printf(" ERP<0x%x>", vp[2]); 2696 break; 2697 case IEEE80211_ELEMID_VENDOR: 2698 if (iswpaoui(vp)) 2699 printwpaie(" WPA", vp, 2+vp[1], maxcols); 2700 else if (iswmeinfo(vp)) 2701 printwmeinfo(" WME", vp, 2+vp[1], maxcols); 2702 else if (iswmeparam(vp)) 2703 printwmeparam(" WME", vp, 2+vp[1], maxcols); 2704 else if (isatherosoui(vp)) 2705 printathie(" ATH", vp, 2+vp[1], maxcols); 2706 else if (iswpsoui(vp)) 2707 printwpsie(" WPS", vp, 2+vp[1], maxcols); 2708 else if (verbose) 2709 printie(" VEN", vp, 2+vp[1], maxcols); 2710 break; 2711 case IEEE80211_ELEMID_RSN: 2712 printrsnie(" RSN", vp, 2+vp[1], maxcols); 2713 break; 2714 case IEEE80211_ELEMID_HTCAP: 2715 printhtcap(" HTCAP", vp, 2+vp[1], maxcols); 2716 break; 2717 case IEEE80211_ELEMID_HTINFO: 2718 if (verbose) 2719 printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); 2720 break; 2721 default: 2722 if (verbose) 2723 printie(iename(vp[0]), vp, 2+vp[1], maxcols); 2724 break; 2725 } 2726 ielen -= 2+vp[1]; 2727 vp += 2+vp[1]; 2728 } 2729} 2730 2731static void 2732printmimo(const struct ieee80211_mimo_info *mi) 2733{ 2734 /* NB: don't muddy display unless there's something to show */ 2735 if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) { 2736 /* XXX ignore EVM for now */ 2737 printf(" (rssi %d:%d:%d nf %d:%d:%d)", 2738 mi->rssi[0], mi->rssi[1], mi->rssi[2], 2739 mi->noise[0], mi->noise[1], mi->noise[2]); 2740 } 2741} 2742 2743static void 2744list_scan(int s) 2745{ 2746 uint8_t buf[24*1024]; 2747 char ssid[IEEE80211_NWID_LEN+1]; 2748 const uint8_t *cp; 2749 int len, ssidmax; 2750 2751 if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) 2752 errx(1, "unable to get scan results"); 2753 if (len < sizeof(struct ieee80211req_scan_result)) 2754 return; 2755 2756 getchaninfo(s); 2757 2758 ssidmax = verbose ? IEEE80211_NWID_LEN : 14; 2759 printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" 2760 , ssidmax, ssidmax, "SSID" 2761 , "BSSID" 2762 , "CHAN" 2763 , "RATE" 2764 , " S:N" 2765 , "INT" 2766 , "CAPS" 2767 ); 2768 cp = buf; 2769 do { 2770 const struct ieee80211req_scan_result *sr; 2771 const uint8_t *vp; 2772 2773 sr = (const struct ieee80211req_scan_result *) cp; 2774 vp = cp + sr->isr_ie_off; 2775 printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" 2776 , ssidmax 2777 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 2778 , ssid 2779 , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 2780 , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 2781 , getmaxrate(sr->isr_rates, sr->isr_nrates) 2782 , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise 2783 , sr->isr_intval 2784 , getcaps(sr->isr_capinfo) 2785 ); 2786 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24); 2787 printf("\n"); 2788 cp += sr->isr_len, len -= sr->isr_len; 2789 } while (len >= sizeof(struct ieee80211req_scan_result)); 2790} 2791 2792#ifdef __FreeBSD__ 2793#include <net80211/ieee80211_freebsd.h> 2794#endif 2795#ifdef __NetBSD__ 2796#include <net80211/ieee80211_netbsd.h> 2797#endif 2798 2799static void 2800scan_and_wait(int s) 2801{ 2802 struct ieee80211_scan_req sr; 2803 struct ieee80211req ireq; 2804 int sroute; 2805 2806 sroute = socket(PF_ROUTE, SOCK_RAW, 0); 2807 if (sroute < 0) { 2808 perror("socket(PF_ROUTE,SOCK_RAW)"); 2809 return; 2810 } 2811 (void) memset(&ireq, 0, sizeof(ireq)); 2812 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 2813 ireq.i_type = IEEE80211_IOC_SCAN_REQ; 2814 2815 memset(&sr, 0, sizeof(sr)); 2816 sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE 2817 | IEEE80211_IOC_SCAN_NOPICK 2818 | IEEE80211_IOC_SCAN_ONCE; 2819 sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 2820 sr.sr_nssid = 0; 2821 2822 ireq.i_data = &sr; 2823 ireq.i_len = sizeof(sr); 2824 /* NB: only root can trigger a scan so ignore errors */ 2825 if (ioctl(s, SIOCS80211, &ireq) >= 0) { 2826 char buf[2048]; 2827 struct if_announcemsghdr *ifan; 2828 struct rt_msghdr *rtm; 2829 2830 do { 2831 if (read(sroute, buf, sizeof(buf)) < 0) { 2832 perror("read(PF_ROUTE)"); 2833 break; 2834 } 2835 rtm = (struct rt_msghdr *) buf; 2836 if (rtm->rtm_version != RTM_VERSION) 2837 break; 2838 ifan = (struct if_announcemsghdr *) rtm; 2839 } while (rtm->rtm_type != RTM_IEEE80211 || 2840 ifan->ifan_what != RTM_IEEE80211_SCAN); 2841 } 2842 close(sroute); 2843} 2844 2845static 2846DECL_CMD_FUNC(set80211scan, val, d) 2847{ 2848 scan_and_wait(s); 2849 list_scan(s); 2850} 2851 2852static enum ieee80211_opmode get80211opmode(int s); 2853 2854static int 2855gettxseq(const struct ieee80211req_sta_info *si) 2856{ 2857#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2858 2859 int i, txseq; 2860 2861 if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2862 return si->isi_txseqs[0]; 2863 /* XXX not right but usually what folks want */ 2864 txseq = 0; 2865 for (i = 0; i < IEEE80211_TID_SIZE; i++) 2866 if (si->isi_txseqs[i] > txseq) 2867 txseq = si->isi_txseqs[i]; 2868 return txseq; 2869#undef IEEE80211_NODE_QOS 2870} 2871 2872static int 2873getrxseq(const struct ieee80211req_sta_info *si) 2874{ 2875#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2876 2877 int i, rxseq; 2878 2879 if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2880 return si->isi_rxseqs[0]; 2881 /* XXX not right but usually what folks want */ 2882 rxseq = 0; 2883 for (i = 0; i < IEEE80211_TID_SIZE; i++) 2884 if (si->isi_rxseqs[i] > rxseq) 2885 rxseq = si->isi_rxseqs[i]; 2886 return rxseq; 2887#undef IEEE80211_NODE_QOS 2888} 2889 2890static void 2891list_stations(int s) 2892{ 2893 union { 2894 struct ieee80211req_sta_req req; 2895 uint8_t buf[24*1024]; 2896 } u; 2897 enum ieee80211_opmode opmode = get80211opmode(s); 2898 const uint8_t *cp; 2899 int len; 2900 2901 /* broadcast address =>'s get all stations */ 2902 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 2903 if (opmode == IEEE80211_M_STA) { 2904 /* 2905 * Get information about the associated AP. 2906 */ 2907 (void) get80211(s, IEEE80211_IOC_BSSID, 2908 u.req.is_u.macaddr, IEEE80211_ADDR_LEN); 2909 } 2910 if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) 2911 errx(1, "unable to get station information"); 2912 if (len < sizeof(struct ieee80211req_sta_info)) 2913 return; 2914 2915 getchaninfo(s); 2916 2917 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n" 2918 , "ADDR" 2919 , "AID" 2920 , "CHAN" 2921 , "RATE" 2922 , "RSSI" 2923 , "IDLE" 2924 , "TXSEQ" 2925 , "RXSEQ" 2926 , "CAPS" 2927 , "FLAG" 2928 ); 2929 cp = (const uint8_t *) u.req.info; 2930 do { 2931 const struct ieee80211req_sta_info *si; 2932 2933 si = (const struct ieee80211req_sta_info *) cp; 2934 if (si->isi_len < sizeof(*si)) 2935 break; 2936 printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s" 2937 , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 2938 , IEEE80211_AID(si->isi_associd) 2939 , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) 2940 , si->isi_txmbps/2 2941 , si->isi_rssi/2. 2942 , si->isi_inact 2943 , gettxseq(si) 2944 , getrxseq(si) 2945 , getcaps(si->isi_capinfo) 2946 , getflags(si->isi_state) 2947 ); 2948 printies(cp + si->isi_ie_off, si->isi_ie_len, 24); 2949 printmimo(&si->isi_mimo); 2950 printf("\n"); 2951 cp += si->isi_len, len -= si->isi_len; 2952 } while (len >= sizeof(struct ieee80211req_sta_info)); 2953} 2954 2955static const char * 2956get_chaninfo(const struct ieee80211_channel *c, int precise, 2957 char buf[], size_t bsize) 2958{ 2959 buf[0] = '\0'; 2960 if (IEEE80211_IS_CHAN_FHSS(c)) 2961 strlcat(buf, " FHSS", bsize); 2962 if (IEEE80211_IS_CHAN_A(c)) { 2963 if (IEEE80211_IS_CHAN_HALF(c)) 2964 strlcat(buf, " 11a/10Mhz", bsize); 2965 else if (IEEE80211_IS_CHAN_QUARTER(c)) 2966 strlcat(buf, " 11a/5Mhz", bsize); 2967 else 2968 strlcat(buf, " 11a", bsize); 2969 } 2970 if (IEEE80211_IS_CHAN_ANYG(c)) { 2971 if (IEEE80211_IS_CHAN_HALF(c)) 2972 strlcat(buf, " 11g/10Mhz", bsize); 2973 else if (IEEE80211_IS_CHAN_QUARTER(c)) 2974 strlcat(buf, " 11g/5Mhz", bsize); 2975 else 2976 strlcat(buf, " 11g", bsize); 2977 } else if (IEEE80211_IS_CHAN_B(c)) 2978 strlcat(buf, " 11b", bsize); 2979 if (IEEE80211_IS_CHAN_TURBO(c)) 2980 strlcat(buf, " Turbo", bsize); 2981 if (precise) { 2982 if (IEEE80211_IS_CHAN_HT20(c)) 2983 strlcat(buf, " ht/20", bsize); 2984 else if (IEEE80211_IS_CHAN_HT40D(c)) 2985 strlcat(buf, " ht/40-", bsize); 2986 else if (IEEE80211_IS_CHAN_HT40U(c)) 2987 strlcat(buf, " ht/40+", bsize); 2988 } else { 2989 if (IEEE80211_IS_CHAN_HT(c)) 2990 strlcat(buf, " ht", bsize); 2991 } 2992 return buf; 2993} 2994 2995static void 2996print_chaninfo(const struct ieee80211_channel *c, int verb) 2997{ 2998 char buf[14]; 2999 3000 printf("Channel %3u : %u%c Mhz%-14.14s", 3001 ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 3002 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', 3003 get_chaninfo(c, verb, buf, sizeof(buf))); 3004} 3005 3006static void 3007print_channels(int s, const struct ieee80211req_chaninfo *chans, 3008 int allchans, int verb) 3009{ 3010 struct ieee80211req_chaninfo achans; 3011 uint8_t reported[IEEE80211_CHAN_BYTES]; 3012 const struct ieee80211_channel *c; 3013 int i, half; 3014 3015 memset(&achans, 0, sizeof(achans)); 3016 memset(reported, 0, sizeof(reported)); 3017 if (!allchans) { 3018 struct ieee80211req_chanlist active; 3019 3020 if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0) 3021 errx(1, "unable to get active channel list"); 3022 memset(&achans, 0, sizeof(achans)); 3023 for (i = 0; i < chans->ic_nchans; i++) { 3024 c = &chans->ic_chans[i]; 3025 if (!isset(active.ic_channels, c->ic_ieee)) 3026 continue; 3027 /* 3028 * Suppress compatible duplicates unless 3029 * verbose. The kernel gives us it's 3030 * complete channel list which has separate 3031 * entries for 11g/11b and 11a/turbo. 3032 */ 3033 if (isset(reported, c->ic_ieee) && !verb) { 3034 /* XXX we assume duplicates are adjacent */ 3035 achans.ic_chans[achans.ic_nchans-1] = *c; 3036 } else { 3037 achans.ic_chans[achans.ic_nchans++] = *c; 3038 setbit(reported, c->ic_ieee); 3039 } 3040 } 3041 } else { 3042 for (i = 0; i < chans->ic_nchans; i++) { 3043 c = &chans->ic_chans[i]; 3044 /* suppress duplicates as above */ 3045 if (isset(reported, c->ic_ieee) && !verb) { 3046 /* XXX we assume duplicates are adjacent */ 3047 achans.ic_chans[achans.ic_nchans-1] = *c; 3048 } else { 3049 achans.ic_chans[achans.ic_nchans++] = *c; 3050 setbit(reported, c->ic_ieee); 3051 } 3052 } 3053 } 3054 half = achans.ic_nchans / 2; 3055 if (achans.ic_nchans % 2) 3056 half++; 3057 3058 for (i = 0; i < achans.ic_nchans / 2; i++) { 3059 print_chaninfo(&achans.ic_chans[i], verb); 3060 print_chaninfo(&achans.ic_chans[half+i], verb); 3061 printf("\n"); 3062 } 3063 if (achans.ic_nchans % 2) { 3064 print_chaninfo(&achans.ic_chans[i], verb); 3065 printf("\n"); 3066 } 3067} 3068 3069static void 3070list_channels(int s, int allchans) 3071{ 3072 getchaninfo(s); 3073 print_channels(s, &chaninfo, allchans, verbose); 3074} 3075 3076static void 3077print_txpow(const struct ieee80211_channel *c) 3078{ 3079 printf("Channel %3u : %u Mhz %3.1f reg %2d ", 3080 c->ic_ieee, c->ic_freq, 3081 c->ic_maxpower/2., c->ic_maxregpower); 3082} 3083 3084static void 3085print_txpow_verbose(const struct ieee80211_channel *c) 3086{ 3087 print_chaninfo(c, 1); 3088 printf("min %4.1f dBm max %3.1f dBm reg %2d dBm", 3089 c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower); 3090 /* indicate where regulatory cap limits power use */ 3091 if (c->ic_maxpower > 2*c->ic_maxregpower) 3092 printf(" <"); 3093} 3094 3095static void 3096list_txpow(int s) 3097{ 3098 struct ieee80211req_chaninfo achans; 3099 uint8_t reported[IEEE80211_CHAN_BYTES]; 3100 struct ieee80211_channel *c, *prev; 3101 int i, half; 3102 3103 getchaninfo(s); 3104 memset(&achans, 0, sizeof(achans)); 3105 memset(reported, 0, sizeof(reported)); 3106 for (i = 0; i < chaninfo.ic_nchans; i++) { 3107 c = &chaninfo.ic_chans[i]; 3108 /* suppress duplicates as above */ 3109 if (isset(reported, c->ic_ieee) && !verbose) { 3110 /* XXX we assume duplicates are adjacent */ 3111 prev = &achans.ic_chans[achans.ic_nchans-1]; 3112 /* display highest power on channel */ 3113 if (c->ic_maxpower > prev->ic_maxpower) 3114 *prev = *c; 3115 } else { 3116 achans.ic_chans[achans.ic_nchans++] = *c; 3117 setbit(reported, c->ic_ieee); 3118 } 3119 } 3120 if (!verbose) { 3121 half = achans.ic_nchans / 2; 3122 if (achans.ic_nchans % 2) 3123 half++; 3124 3125 for (i = 0; i < achans.ic_nchans / 2; i++) { 3126 print_txpow(&achans.ic_chans[i]); 3127 print_txpow(&achans.ic_chans[half+i]); 3128 printf("\n"); 3129 } 3130 if (achans.ic_nchans % 2) { 3131 print_txpow(&achans.ic_chans[i]); 3132 printf("\n"); 3133 } 3134 } else { 3135 for (i = 0; i < achans.ic_nchans; i++) { 3136 print_txpow_verbose(&achans.ic_chans[i]); 3137 printf("\n"); 3138 } 3139 } 3140} 3141 3142static void 3143list_keys(int s) 3144{ 3145} 3146 3147#define IEEE80211_C_BITS \ 3148 "\20\1STA\7FF\10TURBOP\11IBSS\12PMGT" \ 3149 "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \ 3150 "\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \ 3151 "\37TXFRAG" 3152 3153#define IEEE80211_CRYPTO_BITS \ 3154 "\20\1WEP\2TKIP\3AES\4AES_CCM\5TKIPMIC\6CKIP\12PMGT" 3155 3156#define IEEE80211_HTCAP_BITS \ 3157 "\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \ 3158 "\21AMPDU\22AMSDU\23HT" 3159 3160static void 3161list_capabilities(int s) 3162{ 3163 struct ieee80211_devcaps_req dc; 3164 3165 getdevcaps(s, &dc); 3166 printb("drivercaps", dc.dc_drivercaps, IEEE80211_C_BITS); 3167 if (dc.dc_cryptocaps != 0 || verbose) { 3168 putchar('\n'); 3169 printb("cryptocaps", dc.dc_cryptocaps, IEEE80211_CRYPTO_BITS); 3170 } 3171 if (dc.dc_htcaps != 0 || verbose) { 3172 putchar('\n'); 3173 printb("htcaps", dc.dc_htcaps, IEEE80211_HTCAP_BITS); 3174 } 3175 putchar('\n'); 3176} 3177 3178static int 3179get80211wme(int s, int param, int ac, int *val) 3180{ 3181 struct ieee80211req ireq; 3182 3183 (void) memset(&ireq, 0, sizeof(ireq)); 3184 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3185 ireq.i_type = param; 3186 ireq.i_len = ac; 3187 if (ioctl(s, SIOCG80211, &ireq) < 0) { 3188 warn("cannot get WME parameter %d, ac %d%s", 3189 param, ac & IEEE80211_WMEPARAM_VAL, 3190 ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); 3191 return -1; 3192 } 3193 *val = ireq.i_val; 3194 return 0; 3195} 3196 3197static void 3198list_wme_aci(int s, const char *tag, int ac) 3199{ 3200 int val; 3201 3202 printf("\t%s", tag); 3203 3204 /* show WME BSS parameters */ 3205 if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) 3206 printf(" cwmin %2u", val); 3207 if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) 3208 printf(" cwmax %2u", val); 3209 if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) 3210 printf(" aifs %2u", val); 3211 if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) 3212 printf(" txopLimit %3u", val); 3213 if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { 3214 if (val) 3215 printf(" acm"); 3216 else if (verbose) 3217 printf(" -acm"); 3218 } 3219 /* !BSS only */ 3220 if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3221 if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { 3222 if (!val) 3223 printf(" -ack"); 3224 else if (verbose) 3225 printf(" ack"); 3226 } 3227 } 3228 printf("\n"); 3229} 3230 3231static void 3232list_wme(int s) 3233{ 3234 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 3235 int ac; 3236 3237 if (verbose) { 3238 /* display both BSS and local settings */ 3239 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 3240 again: 3241 if (ac & IEEE80211_WMEPARAM_BSS) 3242 list_wme_aci(s, " ", ac); 3243 else 3244 list_wme_aci(s, acnames[ac], ac); 3245 if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3246 ac |= IEEE80211_WMEPARAM_BSS; 3247 goto again; 3248 } else 3249 ac &= ~IEEE80211_WMEPARAM_BSS; 3250 } 3251 } else { 3252 /* display only channel settings */ 3253 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) 3254 list_wme_aci(s, acnames[ac], ac); 3255 } 3256} 3257 3258static void 3259list_roam(int s) 3260{ 3261 const struct ieee80211_roamparam *rp; 3262 int mode; 3263 3264 getroam(s); 3265 for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_11NA; mode++) { 3266 rp = &roamparams.params[mode]; 3267 if (rp->rssi == 0 && rp->rate == 0) 3268 continue; 3269 if (rp->rssi & 1) 3270 LINE_CHECK("roam:%-6.6s rssi %2u.5dBm rate %2u Mb/s", 3271 modename[mode], rp->rssi/2, rp->rate/2); 3272 else 3273 LINE_CHECK("roam:%-6.6s rssi %4udBm rate %2u Mb/s", 3274 modename[mode], rp->rssi/2, rp->rate/2); 3275 } 3276 for (; mode < IEEE80211_MODE_MAX; mode++) { 3277 rp = &roamparams.params[mode]; 3278 if (rp->rssi == 0 && rp->rate == 0) 3279 continue; 3280 if (rp->rssi & 1) 3281 LINE_CHECK("roam:%-6.6s rssi %2u.5dBm MCS %2u ", 3282 modename[mode], rp->rssi/2, rp->rate &~ 0x80); 3283 else 3284 LINE_CHECK("roam:%-6.6s rssi %4udBm MCS %2u ", 3285 modename[mode], rp->rssi/2, rp->rate &~ 0x80); 3286 } 3287} 3288 3289static void 3290list_txparams(int s) 3291{ 3292 const struct ieee80211_txparam *tp; 3293 int mode; 3294 3295 gettxparams(s); 3296 for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_11NA; mode++) { 3297 tp = &txparams.params[mode]; 3298 if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3299 continue; 3300 if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3301 LINE_CHECK("%-6.6s ucast NONE mgmt %2u Mb/s " 3302 "mcast %2u Mb/s maxretry %u", 3303 modename[mode], tp->mgmtrate/2, 3304 tp->mcastrate/2, tp->maxretry); 3305 else 3306 LINE_CHECK("%-6.6s ucast %2u Mb/s mgmt %2u Mb/s " 3307 "mcast %2u Mb/s maxretry %u", 3308 modename[mode], tp->ucastrate/2, tp->mgmtrate/2, 3309 tp->mcastrate/2, tp->maxretry); 3310 } 3311 for (; mode < IEEE80211_MODE_MAX; mode++) { 3312 tp = &txparams.params[mode]; 3313 if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3314 continue; 3315 if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3316 LINE_CHECK("%-6.6s ucast NONE mgmt %2u MCS " 3317 "mcast %2u MCS maxretry %u", 3318 modename[mode], tp->mgmtrate &~ 0x80, 3319 tp->mcastrate &~ 0x80, tp->maxretry); 3320 else 3321 LINE_CHECK("%-6.6s ucast %2u MCS mgmt %2u MCS " 3322 "mcast %2u MCS maxretry %u", 3323 modename[mode], tp->ucastrate &~ 0x80, 3324 tp->mgmtrate &~ 0x80, 3325 tp->mcastrate &~ 0x80, tp->maxretry); 3326 } 3327} 3328 3329static void 3330printpolicy(int policy) 3331{ 3332 switch (policy) { 3333 case IEEE80211_MACCMD_POLICY_OPEN: 3334 printf("policy: open\n"); 3335 break; 3336 case IEEE80211_MACCMD_POLICY_ALLOW: 3337 printf("policy: allow\n"); 3338 break; 3339 case IEEE80211_MACCMD_POLICY_DENY: 3340 printf("policy: deny\n"); 3341 break; 3342 case IEEE80211_MACCMD_POLICY_RADIUS: 3343 printf("policy: radius\n"); 3344 break; 3345 default: 3346 printf("policy: unknown (%u)\n", policy); 3347 break; 3348 } 3349} 3350 3351static void 3352list_mac(int s) 3353{ 3354 struct ieee80211req ireq; 3355 struct ieee80211req_maclist *acllist; 3356 int i, nacls, policy, len; 3357 uint8_t *data; 3358 char c; 3359 3360 (void) memset(&ireq, 0, sizeof(ireq)); 3361 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 3362 ireq.i_type = IEEE80211_IOC_MACCMD; 3363 ireq.i_val = IEEE80211_MACCMD_POLICY; 3364 if (ioctl(s, SIOCG80211, &ireq) < 0) { 3365 if (errno == EINVAL) { 3366 printf("No acl policy loaded\n"); 3367 return; 3368 } 3369 err(1, "unable to get mac policy"); 3370 } 3371 policy = ireq.i_val; 3372 if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 3373 c = '*'; 3374 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 3375 c = '+'; 3376 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 3377 c = '-'; 3378 } else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) { 3379 c = 'r'; /* NB: should never have entries */ 3380 } else { 3381 printf("policy: unknown (%u)\n", policy); 3382 c = '?'; 3383 } 3384 if (verbose || c == '?') 3385 printpolicy(policy); 3386 3387 ireq.i_val = IEEE80211_MACCMD_LIST; 3388 ireq.i_len = 0; 3389 if (ioctl(s, SIOCG80211, &ireq) < 0) 3390 err(1, "unable to get mac acl list size"); 3391 if (ireq.i_len == 0) { /* NB: no acls */ 3392 if (!(verbose || c == '?')) 3393 printpolicy(policy); 3394 return; 3395 } 3396 len = ireq.i_len; 3397 3398 data = malloc(len); 3399 if (data == NULL) 3400 err(1, "out of memory for acl list"); 3401 3402 ireq.i_data = data; 3403 if (ioctl(s, SIOCG80211, &ireq) < 0) 3404 err(1, "unable to get mac acl list"); 3405 nacls = len / sizeof(*acllist); 3406 acllist = (struct ieee80211req_maclist *) data; 3407 for (i = 0; i < nacls; i++) 3408 printf("%c%s\n", c, ether_ntoa( 3409 (const struct ether_addr *) acllist[i].ml_macaddr)); 3410 free(data); 3411} 3412 3413static void 3414print_regdomain(const struct ieee80211_regdomain *reg, int verb) 3415{ 3416 if ((reg->regdomain != 0 && 3417 reg->regdomain != reg->country) || verb) { 3418 const struct regdomain *rd = 3419 lib80211_regdomain_findbysku(getregdata(), reg->regdomain); 3420 if (rd == NULL) 3421 LINE_CHECK("regdomain %d", reg->regdomain); 3422 else 3423 LINE_CHECK("regdomain %s", rd->name); 3424 } 3425 if (reg->country != 0 || verb) { 3426 const struct country *cc = 3427 lib80211_country_findbycc(getregdata(), reg->country); 3428 if (cc == NULL) 3429 LINE_CHECK("country %d", reg->country); 3430 else 3431 LINE_CHECK("country %s", cc->isoname); 3432 } 3433 if (reg->location == 'I') 3434 LINE_CHECK("indoor"); 3435 else if (reg->location == 'O') 3436 LINE_CHECK("outdoor"); 3437 else if (verb) 3438 LINE_CHECK("anywhere"); 3439 if (reg->ecm) 3440 LINE_CHECK("ecm"); 3441 else if (verb) 3442 LINE_CHECK("-ecm"); 3443} 3444 3445static void 3446list_regdomain(int s, int channelsalso) 3447{ 3448 getregdomain(s); 3449 if (channelsalso) { 3450 getchaninfo(s); 3451 spacer = ':'; 3452 print_regdomain(®domain, 1); 3453 LINE_BREAK(); 3454 print_channels(s, &chaninfo, 1/*allchans*/, 1/*verbose*/); 3455 } else 3456 print_regdomain(®domain, verbose); 3457} 3458 3459static 3460DECL_CMD_FUNC(set80211list, arg, d) 3461{ 3462#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 3463 3464 LINE_INIT('\t'); 3465 3466 if (iseq(arg, "sta")) 3467 list_stations(s); 3468 else if (iseq(arg, "scan") || iseq(arg, "ap")) 3469 list_scan(s); 3470 else if (iseq(arg, "chan") || iseq(arg, "freq")) 3471 list_channels(s, 1); 3472 else if (iseq(arg, "active")) 3473 list_channels(s, 0); 3474 else if (iseq(arg, "keys")) 3475 list_keys(s); 3476 else if (iseq(arg, "caps")) 3477 list_capabilities(s); 3478 else if (iseq(arg, "wme") || iseq(arg, "wmm")) 3479 list_wme(s); 3480 else if (iseq(arg, "mac")) 3481 list_mac(s); 3482 else if (iseq(arg, "txpow")) 3483 list_txpow(s); 3484 else if (iseq(arg, "roam")) 3485 list_roam(s); 3486 else if (iseq(arg, "txparam") || iseq(arg, "txparm")) 3487 list_txparams(s); 3488 else if (iseq(arg, "regdomain")) 3489 list_regdomain(s, 1); 3490 else if (iseq(arg, "countries")) 3491 list_countries(); 3492 else 3493 errx(1, "Don't know how to list %s for %s", arg, name); 3494 LINE_BREAK(); 3495#undef iseq 3496} 3497 3498static enum ieee80211_opmode 3499get80211opmode(int s) 3500{ 3501 struct ifmediareq ifmr; 3502 3503 (void) memset(&ifmr, 0, sizeof(ifmr)); 3504 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 3505 3506 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 3507 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 3508 return IEEE80211_M_IBSS; /* XXX ahdemo */ 3509 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 3510 return IEEE80211_M_HOSTAP; 3511 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 3512 return IEEE80211_M_MONITOR; 3513 } 3514 return IEEE80211_M_STA; 3515} 3516 3517#if 0 3518static void 3519printcipher(int s, struct ieee80211req *ireq, int keylenop) 3520{ 3521 switch (ireq->i_val) { 3522 case IEEE80211_CIPHER_WEP: 3523 ireq->i_type = keylenop; 3524 if (ioctl(s, SIOCG80211, ireq) != -1) 3525 printf("WEP-%s", 3526 ireq->i_len <= 5 ? "40" : 3527 ireq->i_len <= 13 ? "104" : "128"); 3528 else 3529 printf("WEP"); 3530 break; 3531 case IEEE80211_CIPHER_TKIP: 3532 printf("TKIP"); 3533 break; 3534 case IEEE80211_CIPHER_AES_OCB: 3535 printf("AES-OCB"); 3536 break; 3537 case IEEE80211_CIPHER_AES_CCM: 3538 printf("AES-CCM"); 3539 break; 3540 case IEEE80211_CIPHER_CKIP: 3541 printf("CKIP"); 3542 break; 3543 case IEEE80211_CIPHER_NONE: 3544 printf("NONE"); 3545 break; 3546 default: 3547 printf("UNKNOWN (0x%x)", ireq->i_val); 3548 break; 3549 } 3550} 3551#endif 3552 3553static void 3554printkey(const struct ieee80211req_key *ik) 3555{ 3556 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 3557 int keylen = ik->ik_keylen; 3558 int printcontents; 3559 3560 printcontents = printkeys && 3561 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 3562 if (printcontents) 3563 LINE_BREAK(); 3564 switch (ik->ik_type) { 3565 case IEEE80211_CIPHER_WEP: 3566 /* compatibility */ 3567 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 3568 keylen <= 5 ? "40-bit" : 3569 keylen <= 13 ? "104-bit" : "128-bit"); 3570 break; 3571 case IEEE80211_CIPHER_TKIP: 3572 if (keylen > 128/8) 3573 keylen -= 128/8; /* ignore MIC for now */ 3574 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3575 break; 3576 case IEEE80211_CIPHER_AES_OCB: 3577 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3578 break; 3579 case IEEE80211_CIPHER_AES_CCM: 3580 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3581 break; 3582 case IEEE80211_CIPHER_CKIP: 3583 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3584 break; 3585 case IEEE80211_CIPHER_NONE: 3586 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3587 break; 3588 default: 3589 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 3590 ik->ik_type, ik->ik_keyix+1, 8*keylen); 3591 break; 3592 } 3593 if (printcontents) { 3594 int i; 3595 3596 printf(" <"); 3597 for (i = 0; i < keylen; i++) 3598 printf("%02x", ik->ik_keydata[i]); 3599 printf(">"); 3600 if (ik->ik_type != IEEE80211_CIPHER_WEP && 3601 (ik->ik_keyrsc != 0 || verbose)) 3602 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 3603 if (ik->ik_type != IEEE80211_CIPHER_WEP && 3604 (ik->ik_keytsc != 0 || verbose)) 3605 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 3606 if (ik->ik_flags != 0 && verbose) { 3607 const char *sep = " "; 3608 3609 if (ik->ik_flags & IEEE80211_KEY_XMIT) 3610 printf("%stx", sep), sep = "+"; 3611 if (ik->ik_flags & IEEE80211_KEY_RECV) 3612 printf("%srx", sep), sep = "+"; 3613 if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 3614 printf("%sdef", sep), sep = "+"; 3615 } 3616 LINE_BREAK(); 3617 } 3618} 3619 3620static void 3621printrate(const char *tag, int v, int defrate, int defmcs) 3622{ 3623 if (v == 11) 3624 LINE_CHECK("%s 5.5", tag); 3625 else if (v & 0x80) { 3626 if (v != defmcs) 3627 LINE_CHECK("%s %d", tag, v &~ 0x80); 3628 } else { 3629 if (v != defrate) 3630 LINE_CHECK("%s %d", tag, v/2); 3631 } 3632} 3633 3634static int 3635getssid(int s, int ix, void *data, size_t len, int *plen) 3636{ 3637 struct ieee80211req ireq; 3638 3639 (void) memset(&ireq, 0, sizeof(ireq)); 3640 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3641 ireq.i_type = IEEE80211_IOC_SSID; 3642 ireq.i_val = ix; 3643 ireq.i_data = data; 3644 ireq.i_len = len; 3645 if (ioctl(s, SIOCG80211, &ireq) < 0) 3646 return -1; 3647 *plen = ireq.i_len; 3648 return 0; 3649} 3650 3651static void 3652ieee80211_status(int s) 3653{ 3654 static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 3655 enum ieee80211_opmode opmode = get80211opmode(s); 3656 int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; 3657 uint8_t data[32]; 3658 const struct ieee80211_channel *c; 3659 const struct ieee80211_roamparam *rp; 3660 const struct ieee80211_txparam *tp; 3661 3662 if (getssid(s, -1, data, sizeof(data), &len) < 0) { 3663 /* If we can't get the SSID, this isn't an 802.11 device. */ 3664 return; 3665 } 3666 3667 /* 3668 * Invalidate cached state so printing status for multiple 3669 * if's doesn't reuse the first interfaces' cached state. 3670 */ 3671 gotcurchan = 0; 3672 gotroam = 0; 3673 gottxparams = 0; 3674 gothtconf = 0; 3675 gotregdomain = 0; 3676 3677 if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) 3678 num = 0; 3679 printf("\tssid "); 3680 if (num > 1) { 3681 for (i = 0; i < num; i++) { 3682 if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) { 3683 printf(" %d:", i + 1); 3684 print_string(data, len); 3685 } 3686 } 3687 } else 3688 print_string(data, len); 3689 3690 c = getcurchan(s); 3691 if (c->ic_freq != IEEE80211_CHAN_ANY) { 3692 char buf[14]; 3693 printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq, 3694 get_chaninfo(c, 1, buf, sizeof(buf))); 3695 } else if (verbose) 3696 printf(" channel UNDEF"); 3697 3698 if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && 3699 (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 3700 printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); 3701 3702 if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { 3703 printf("\n\tstationname "); 3704 print_string(data, len); 3705 } 3706 3707 spacer = ' '; /* force first break */ 3708 LINE_BREAK(); 3709 3710 list_regdomain(s, 0); 3711 3712 wpa = 0; 3713 if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { 3714 switch (val) { 3715 case IEEE80211_AUTH_NONE: 3716 LINE_CHECK("authmode NONE"); 3717 break; 3718 case IEEE80211_AUTH_OPEN: 3719 LINE_CHECK("authmode OPEN"); 3720 break; 3721 case IEEE80211_AUTH_SHARED: 3722 LINE_CHECK("authmode SHARED"); 3723 break; 3724 case IEEE80211_AUTH_8021X: 3725 LINE_CHECK("authmode 802.1x"); 3726 break; 3727 case IEEE80211_AUTH_WPA: 3728 if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) 3729 wpa = 1; /* default to WPA1 */ 3730 switch (wpa) { 3731 case 2: 3732 LINE_CHECK("authmode WPA2/802.11i"); 3733 break; 3734 case 3: 3735 LINE_CHECK("authmode WPA1+WPA2/802.11i"); 3736 break; 3737 default: 3738 LINE_CHECK("authmode WPA"); 3739 break; 3740 } 3741 break; 3742 case IEEE80211_AUTH_AUTO: 3743 LINE_CHECK("authmode AUTO"); 3744 break; 3745 default: 3746 LINE_CHECK("authmode UNKNOWN (0x%x)", val); 3747 break; 3748 } 3749 } 3750 3751 if (wpa || verbose) { 3752 if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) { 3753 if (val) 3754 LINE_CHECK("wps"); 3755 else if (verbose) 3756 LINE_CHECK("-wps"); 3757 } 3758 if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) { 3759 if (val) 3760 LINE_CHECK("tsn"); 3761 else if (verbose) 3762 LINE_CHECK("-tsn"); 3763 } 3764 if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { 3765 if (val) 3766 LINE_CHECK("countermeasures"); 3767 else if (verbose) 3768 LINE_CHECK("-countermeasures"); 3769 } 3770#if 0 3771 /* XXX not interesting with WPA done in user space */ 3772 ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 3773 if (ioctl(s, SIOCG80211, &ireq) != -1) { 3774 } 3775 3776 ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 3777 if (ioctl(s, SIOCG80211, &ireq) != -1) { 3778 LINE_CHECK("mcastcipher "); 3779 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 3780 spacer = ' '; 3781 } 3782 3783 ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 3784 if (ioctl(s, SIOCG80211, &ireq) != -1) { 3785 LINE_CHECK("ucastcipher "); 3786 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 3787 } 3788 3789 if (wpa & 2) { 3790 ireq.i_type = IEEE80211_IOC_RSNCAPS; 3791 if (ioctl(s, SIOCG80211, &ireq) != -1) { 3792 LINE_CHECK("RSN caps 0x%x", ireq.i_val); 3793 spacer = ' '; 3794 } 3795 } 3796 3797 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 3798 if (ioctl(s, SIOCG80211, &ireq) != -1) { 3799 } 3800#endif 3801 } 3802 3803 if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && 3804 wepmode != IEEE80211_WEP_NOSUP) { 3805 int firstkey; 3806 3807 switch (wepmode) { 3808 case IEEE80211_WEP_OFF: 3809 LINE_CHECK("privacy OFF"); 3810 break; 3811 case IEEE80211_WEP_ON: 3812 LINE_CHECK("privacy ON"); 3813 break; 3814 case IEEE80211_WEP_MIXED: 3815 LINE_CHECK("privacy MIXED"); 3816 break; 3817 default: 3818 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 3819 break; 3820 } 3821 3822 /* 3823 * If we get here then we've got WEP support so we need 3824 * to print WEP status. 3825 */ 3826 3827 if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { 3828 warn("WEP support, but no tx key!"); 3829 goto end; 3830 } 3831 if (val != -1) 3832 LINE_CHECK("deftxkey %d", val+1); 3833 else if (wepmode != IEEE80211_WEP_OFF || verbose) 3834 LINE_CHECK("deftxkey UNDEF"); 3835 3836 if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { 3837 warn("WEP support, but no NUMWEPKEYS support!"); 3838 goto end; 3839 } 3840 3841 firstkey = 1; 3842 for (i = 0; i < num; i++) { 3843 struct ieee80211req_key ik; 3844 3845 memset(&ik, 0, sizeof(ik)); 3846 ik.ik_keyix = i; 3847 if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { 3848 warn("WEP support, but can get keys!"); 3849 goto end; 3850 } 3851 if (ik.ik_keylen != 0) { 3852 if (verbose) 3853 LINE_BREAK(); 3854 printkey(&ik); 3855 firstkey = 0; 3856 } 3857 } 3858end: 3859 ; 3860 } 3861 3862 if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && 3863 val != IEEE80211_POWERSAVE_NOSUP ) { 3864 if (val != IEEE80211_POWERSAVE_OFF || verbose) { 3865 switch (val) { 3866 case IEEE80211_POWERSAVE_OFF: 3867 LINE_CHECK("powersavemode OFF"); 3868 break; 3869 case IEEE80211_POWERSAVE_CAM: 3870 LINE_CHECK("powersavemode CAM"); 3871 break; 3872 case IEEE80211_POWERSAVE_PSP: 3873 LINE_CHECK("powersavemode PSP"); 3874 break; 3875 case IEEE80211_POWERSAVE_PSP_CAM: 3876 LINE_CHECK("powersavemode PSP-CAM"); 3877 break; 3878 } 3879 if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) 3880 LINE_CHECK("powersavesleep %d", val); 3881 } 3882 } 3883 3884 if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { 3885 if (val & 1) 3886 LINE_CHECK("txpower %d.5", val/2); 3887 else 3888 LINE_CHECK("txpower %d", val/2); 3889 } 3890 if (verbose) { 3891 if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) 3892 LINE_CHECK("txpowmax %.1f", val/2.); 3893 } 3894 3895 if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) { 3896 if (val) 3897 LINE_CHECK("dotd"); 3898 else if (verbose) 3899 LINE_CHECK("-dotd"); 3900 } 3901 3902 if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { 3903 if (val != IEEE80211_RTS_MAX || verbose) 3904 LINE_CHECK("rtsthreshold %d", val); 3905 } 3906 3907 if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { 3908 if (val != IEEE80211_FRAG_MAX || verbose) 3909 LINE_CHECK("fragthreshold %d", val); 3910 } 3911 if (opmode == IEEE80211_M_STA || verbose) { 3912 if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { 3913 if (val != IEEE80211_HWBMISS_MAX || verbose) 3914 LINE_CHECK("bmiss %d", val); 3915 } 3916 } 3917 3918 if (!verbose) { 3919 gettxparams(s); 3920 tp = &txparams.params[chan2mode(c)]; 3921 printrate("ucastrate", tp->ucastrate, 3922 IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE); 3923 printrate("mcastrate", tp->mcastrate, 2*1, 0x80|0); 3924 printrate("mgmtrate", tp->mgmtrate, 2*1, 0x80|0); 3925 if (tp->maxretry != 6) /* XXX */ 3926 LINE_CHECK("maxretry %d", tp->maxretry); 3927 } else { 3928 LINE_BREAK(); 3929 list_txparams(s); 3930 } 3931 3932 bgscaninterval = -1; 3933 (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); 3934 3935 if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { 3936 if (val != bgscaninterval || verbose) 3937 LINE_CHECK("scanvalid %u", val); 3938 } 3939 3940 bgscan = 0; 3941 if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { 3942 if (bgscan) 3943 LINE_CHECK("bgscan"); 3944 else if (verbose) 3945 LINE_CHECK("-bgscan"); 3946 } 3947 if (bgscan || verbose) { 3948 if (bgscaninterval != -1) 3949 LINE_CHECK("bgscanintvl %u", bgscaninterval); 3950 if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) 3951 LINE_CHECK("bgscanidle %u", val); 3952 if (!verbose) { 3953 getroam(s); 3954 rp = &roamparams.params[chan2mode(c)]; 3955 if (rp->rssi & 1) 3956 LINE_CHECK("roam:rssi %u.5", rp->rssi/2); 3957 else 3958 LINE_CHECK("roam:rssi %u", rp->rssi/2); 3959 LINE_CHECK("roam:rate %u", rp->rate/2); 3960 } else { 3961 LINE_BREAK(); 3962 list_roam(s); 3963 } 3964 } 3965 3966 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 3967 if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { 3968 if (val) 3969 LINE_CHECK("pureg"); 3970 else if (verbose) 3971 LINE_CHECK("-pureg"); 3972 } 3973 if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { 3974 switch (val) { 3975 case IEEE80211_PROTMODE_OFF: 3976 LINE_CHECK("protmode OFF"); 3977 break; 3978 case IEEE80211_PROTMODE_CTS: 3979 LINE_CHECK("protmode CTS"); 3980 break; 3981 case IEEE80211_PROTMODE_RTSCTS: 3982 LINE_CHECK("protmode RTSCTS"); 3983 break; 3984 default: 3985 LINE_CHECK("protmode UNKNOWN (0x%x)", val); 3986 break; 3987 } 3988 } 3989 } 3990 3991 if (IEEE80211_IS_CHAN_HT(c) || verbose) { 3992 gethtconf(s); 3993 switch (htconf & 3) { 3994 case 0: 3995 case 2: 3996 LINE_CHECK("-ht"); 3997 break; 3998 case 1: 3999 LINE_CHECK("ht20"); 4000 break; 4001 case 3: 4002 if (verbose) 4003 LINE_CHECK("ht"); 4004 break; 4005 } 4006 if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { 4007 if (!val) 4008 LINE_CHECK("-htcompat"); 4009 else if (verbose) 4010 LINE_CHECK("htcompat"); 4011 } 4012 if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { 4013 switch (val) { 4014 case 0: 4015 LINE_CHECK("-ampdu"); 4016 break; 4017 case 1: 4018 LINE_CHECK("ampdutx -ampdurx"); 4019 break; 4020 case 2: 4021 LINE_CHECK("-ampdutx ampdurx"); 4022 break; 4023 case 3: 4024 if (verbose) 4025 LINE_CHECK("ampdu"); 4026 break; 4027 } 4028 } 4029 if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { 4030 switch (val) { 4031 case IEEE80211_HTCAP_MAXRXAMPDU_8K: 4032 LINE_CHECK("ampdulimit 8k"); 4033 break; 4034 case IEEE80211_HTCAP_MAXRXAMPDU_16K: 4035 LINE_CHECK("ampdulimit 16k"); 4036 break; 4037 case IEEE80211_HTCAP_MAXRXAMPDU_32K: 4038 LINE_CHECK("ampdulimit 32k"); 4039 break; 4040 case IEEE80211_HTCAP_MAXRXAMPDU_64K: 4041 LINE_CHECK("ampdulimit 64k"); 4042 break; 4043 } 4044 } 4045 if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { 4046 switch (val) { 4047 case IEEE80211_HTCAP_MPDUDENSITY_NA: 4048 if (verbose) 4049 LINE_CHECK("ampdudensity -"); 4050 break; 4051 case IEEE80211_HTCAP_MPDUDENSITY_025: 4052 LINE_CHECK("ampdudensity .25"); 4053 break; 4054 case IEEE80211_HTCAP_MPDUDENSITY_05: 4055 LINE_CHECK("ampdudensity .5"); 4056 break; 4057 case IEEE80211_HTCAP_MPDUDENSITY_1: 4058 LINE_CHECK("ampdudensity 1"); 4059 break; 4060 case IEEE80211_HTCAP_MPDUDENSITY_2: 4061 LINE_CHECK("ampdudensity 2"); 4062 break; 4063 case IEEE80211_HTCAP_MPDUDENSITY_4: 4064 LINE_CHECK("ampdudensity 4"); 4065 break; 4066 case IEEE80211_HTCAP_MPDUDENSITY_8: 4067 LINE_CHECK("ampdudensity 8"); 4068 break; 4069 case IEEE80211_HTCAP_MPDUDENSITY_16: 4070 LINE_CHECK("ampdudensity 16"); 4071 break; 4072 } 4073 } 4074 if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { 4075 switch (val) { 4076 case 0: 4077 LINE_CHECK("-amsdu"); 4078 break; 4079 case 1: 4080 LINE_CHECK("amsdutx -amsdurx"); 4081 break; 4082 case 2: 4083 LINE_CHECK("-amsdutx amsdurx"); 4084 break; 4085 case 3: 4086 if (verbose) 4087 LINE_CHECK("amsdu"); 4088 break; 4089 } 4090 } 4091 /* XXX amsdu limit */ 4092 if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { 4093 if (val) 4094 LINE_CHECK("shortgi"); 4095 else if (verbose) 4096 LINE_CHECK("-shortgi"); 4097 } 4098 if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { 4099 if (val == IEEE80211_PROTMODE_OFF) 4100 LINE_CHECK("htprotmode OFF"); 4101 else if (val != IEEE80211_PROTMODE_RTSCTS) 4102 LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); 4103 else if (verbose) 4104 LINE_CHECK("htprotmode RTSCTS"); 4105 } 4106 if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { 4107 if (val) 4108 LINE_CHECK("puren"); 4109 else if (verbose) 4110 LINE_CHECK("-puren"); 4111 } 4112 } 4113 4114 if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { 4115 if (wme) 4116 LINE_CHECK("wme"); 4117 else if (verbose) 4118 LINE_CHECK("-wme"); 4119 } else 4120 wme = 0; 4121 4122 if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { 4123 if (val) 4124 LINE_CHECK("burst"); 4125 else if (verbose) 4126 LINE_CHECK("-burst"); 4127 } 4128 4129 if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { 4130 if (val) 4131 LINE_CHECK("ff"); 4132 else if (verbose) 4133 LINE_CHECK("-ff"); 4134 } 4135 if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { 4136 if (val) 4137 LINE_CHECK("dturbo"); 4138 else if (verbose) 4139 LINE_CHECK("-dturbo"); 4140 } 4141 if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) { 4142 if (val) 4143 LINE_CHECK("dwds"); 4144 else if (verbose) 4145 LINE_CHECK("-dwds"); 4146 } 4147 4148 if (opmode == IEEE80211_M_HOSTAP) { 4149 if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { 4150 if (val) 4151 LINE_CHECK("hidessid"); 4152 else if (verbose) 4153 LINE_CHECK("-hidessid"); 4154 } 4155 if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { 4156 if (!val) 4157 LINE_CHECK("-apbridge"); 4158 else if (verbose) 4159 LINE_CHECK("apbridge"); 4160 } 4161 if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) 4162 LINE_CHECK("dtimperiod %u", val); 4163 4164 if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { 4165 if (!val) 4166 LINE_CHECK("-doth"); 4167 else if (verbose) 4168 LINE_CHECK("doth"); 4169 } 4170 if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) { 4171 if (!val) 4172 LINE_CHECK("-dfs"); 4173 else if (verbose) 4174 LINE_CHECK("dfs"); 4175 } 4176 if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { 4177 if (!val) 4178 LINE_CHECK("-inact"); 4179 else if (verbose) 4180 LINE_CHECK("inact"); 4181 } 4182 } else { 4183 if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { 4184 if (val != IEEE80211_ROAMING_AUTO || verbose) { 4185 switch (val) { 4186 case IEEE80211_ROAMING_DEVICE: 4187 LINE_CHECK("roaming DEVICE"); 4188 break; 4189 case IEEE80211_ROAMING_AUTO: 4190 LINE_CHECK("roaming AUTO"); 4191 break; 4192 case IEEE80211_ROAMING_MANUAL: 4193 LINE_CHECK("roaming MANUAL"); 4194 break; 4195 default: 4196 LINE_CHECK("roaming UNKNOWN (0x%x)", 4197 val); 4198 break; 4199 } 4200 } 4201 } 4202 } 4203 if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { 4204 /* XXX default define not visible */ 4205 if (val != 100 || verbose) 4206 LINE_CHECK("bintval %u", val); 4207 } 4208 4209 if (wme && verbose) { 4210 LINE_BREAK(); 4211 list_wme(s); 4212 } 4213 LINE_BREAK(); 4214} 4215 4216static int 4217get80211(int s, int type, void *data, int len) 4218{ 4219 struct ieee80211req ireq; 4220 4221 (void) memset(&ireq, 0, sizeof(ireq)); 4222 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4223 ireq.i_type = type; 4224 ireq.i_data = data; 4225 ireq.i_len = len; 4226 return ioctl(s, SIOCG80211, &ireq); 4227} 4228 4229static int 4230get80211len(int s, int type, void *data, int len, int *plen) 4231{ 4232 struct ieee80211req ireq; 4233 4234 (void) memset(&ireq, 0, sizeof(ireq)); 4235 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4236 ireq.i_type = type; 4237 ireq.i_len = len; 4238 ireq.i_data = data; 4239 if (ioctl(s, SIOCG80211, &ireq) < 0) 4240 return -1; 4241 *plen = ireq.i_len; 4242 return 0; 4243} 4244 4245static int 4246get80211val(int s, int type, int *val) 4247{ 4248 struct ieee80211req ireq; 4249 4250 (void) memset(&ireq, 0, sizeof(ireq)); 4251 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4252 ireq.i_type = type; 4253 if (ioctl(s, SIOCG80211, &ireq) < 0) 4254 return -1; 4255 *val = ireq.i_val; 4256 return 0; 4257} 4258 4259static void 4260set80211(int s, int type, int val, int len, void *data) 4261{ 4262 struct ieee80211req ireq; 4263 4264 (void) memset(&ireq, 0, sizeof(ireq)); 4265 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4266 ireq.i_type = type; 4267 ireq.i_val = val; 4268 ireq.i_len = len; 4269 ireq.i_data = data; 4270 if (ioctl(s, SIOCS80211, &ireq) < 0) 4271 err(1, "SIOCS80211"); 4272} 4273 4274static const char * 4275get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 4276{ 4277 int len; 4278 int hexstr; 4279 u_int8_t *p; 4280 4281 len = *lenp; 4282 p = buf; 4283 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 4284 if (hexstr) 4285 val += 2; 4286 for (;;) { 4287 if (*val == '\0') 4288 break; 4289 if (sep != NULL && strchr(sep, *val) != NULL) { 4290 val++; 4291 break; 4292 } 4293 if (hexstr) { 4294 if (!isxdigit((u_char)val[0])) { 4295 warnx("bad hexadecimal digits"); 4296 return NULL; 4297 } 4298 if (!isxdigit((u_char)val[1])) { 4299 warnx("odd count hexadecimal digits"); 4300 return NULL; 4301 } 4302 } 4303 if (p >= buf + len) { 4304 if (hexstr) 4305 warnx("hexadecimal digits too long"); 4306 else 4307 warnx("string too long"); 4308 return NULL; 4309 } 4310 if (hexstr) { 4311#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 4312 *p++ = (tohex((u_char)val[0]) << 4) | 4313 tohex((u_char)val[1]); 4314#undef tohex 4315 val += 2; 4316 } else 4317 *p++ = *val++; 4318 } 4319 len = p - buf; 4320 /* The string "-" is treated as the empty string. */ 4321 if (!hexstr && len == 1 && buf[0] == '-') { 4322 len = 0; 4323 memset(buf, 0, *lenp); 4324 } else if (len < *lenp) 4325 memset(p, 0, *lenp - len); 4326 *lenp = len; 4327 return val; 4328} 4329 4330static void 4331print_string(const u_int8_t *buf, int len) 4332{ 4333 int i; 4334 int hasspc; 4335 4336 i = 0; 4337 hasspc = 0; 4338 for (; i < len; i++) { 4339 if (!isprint(buf[i]) && buf[i] != '\0') 4340 break; 4341 if (isspace(buf[i])) 4342 hasspc++; 4343 } 4344 if (i == len) { 4345 if (hasspc || len == 0 || buf[0] == '\0') 4346 printf("\"%.*s\"", len, buf); 4347 else 4348 printf("%.*s", len, buf); 4349 } else { 4350 printf("0x"); 4351 for (i = 0; i < len; i++) 4352 printf("%02x", buf[i]); 4353 } 4354} 4355 4356/* 4357 * Virtual AP cloning support. 4358 */ 4359static struct ieee80211_clone_params params = { 4360 .icp_opmode = IEEE80211_M_STA, /* default to station mode */ 4361}; 4362 4363static void 4364wlan_create(int s, struct ifreq *ifr) 4365{ 4366 static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 4367 4368 if (params.icp_parent[0] == '\0') 4369 errx(1, "must specify a parent when creating a wlan device"); 4370 if (params.icp_opmode == IEEE80211_M_WDS && 4371 memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0) 4372 errx(1, "no bssid specified for WDS (use wlanbssid)"); 4373 ifr->ifr_data = (caddr_t) ¶ms; 4374 if (ioctl(s, SIOCIFCREATE2, ifr) < 0) 4375 err(1, "SIOCIFCREATE2"); 4376} 4377 4378static 4379DECL_CMD_FUNC(set80211clone_wlandev, arg, d) 4380{ 4381 strlcpy(params.icp_parent, arg, IFNAMSIZ); 4382 clone_setcallback(wlan_create); 4383} 4384 4385static 4386DECL_CMD_FUNC(set80211clone_wlanbssid, arg, d) 4387{ 4388 const struct ether_addr *ea; 4389 4390 ea = ether_aton(arg); 4391 if (ea == NULL) 4392 errx(1, "%s: cannot parse bssid", arg); 4393 memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN); 4394 clone_setcallback(wlan_create); 4395} 4396 4397static 4398DECL_CMD_FUNC(set80211clone_wlanaddr, arg, d) 4399{ 4400 const struct ether_addr *ea; 4401 4402 ea = ether_aton(arg); 4403 if (ea == NULL) 4404 errx(1, "%s: cannot parse addres", arg); 4405 memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN); 4406 params.icp_flags |= IEEE80211_CLONE_MACADDR; 4407 clone_setcallback(wlan_create); 4408} 4409 4410static 4411DECL_CMD_FUNC(set80211clone_wlanmode, arg, d) 4412{ 4413#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 4414 if (iseq(arg, "sta")) 4415 params.icp_opmode = IEEE80211_M_STA; 4416 else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo")) 4417 params.icp_opmode = IEEE80211_M_AHDEMO; 4418 else if (iseq(arg, "ibss") || iseq(arg, "adhoc")) 4419 params.icp_opmode = IEEE80211_M_IBSS; 4420 else if (iseq(arg, "ap") || iseq(arg, "host")) 4421 params.icp_opmode = IEEE80211_M_HOSTAP; 4422 else if (iseq(arg, "wds")) 4423 params.icp_opmode = IEEE80211_M_WDS; 4424 else if (iseq(arg, "monitor")) 4425 params.icp_opmode = IEEE80211_M_MONITOR; 4426 else 4427 errx(1, "Don't know to create %s for %s", arg, name); 4428 clone_setcallback(wlan_create); 4429#undef iseq 4430} 4431 4432static void 4433set80211clone_beacons(const char *val, int d, int s, const struct afswtch *rafp) 4434{ 4435 /* NB: inverted sense */ 4436 if (d) 4437 params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS; 4438 else 4439 params.icp_flags |= IEEE80211_CLONE_NOBEACONS; 4440 clone_setcallback(wlan_create); 4441} 4442 4443static void 4444set80211clone_bssid(const char *val, int d, int s, const struct afswtch *rafp) 4445{ 4446 if (d) 4447 params.icp_flags |= IEEE80211_CLONE_BSSID; 4448 else 4449 params.icp_flags &= ~IEEE80211_CLONE_BSSID; 4450 clone_setcallback(wlan_create); 4451} 4452 4453static void 4454set80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *rafp) 4455{ 4456 if (d) 4457 params.icp_flags |= IEEE80211_CLONE_WDSLEGACY; 4458 else 4459 params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY; 4460 clone_setcallback(wlan_create); 4461} 4462 4463static struct cmd ieee80211_cmds[] = { 4464 DEF_CMD_ARG("ssid", set80211ssid), 4465 DEF_CMD_ARG("nwid", set80211ssid), 4466 DEF_CMD_ARG("stationname", set80211stationname), 4467 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 4468 DEF_CMD_ARG("channel", set80211channel), 4469 DEF_CMD_ARG("authmode", set80211authmode), 4470 DEF_CMD_ARG("powersavemode", set80211powersavemode), 4471 DEF_CMD("powersave", 1, set80211powersave), 4472 DEF_CMD("-powersave", 0, set80211powersave), 4473 DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 4474 DEF_CMD_ARG("wepmode", set80211wepmode), 4475 DEF_CMD("wep", 1, set80211wep), 4476 DEF_CMD("-wep", 0, set80211wep), 4477 DEF_CMD_ARG("deftxkey", set80211weptxkey), 4478 DEF_CMD_ARG("weptxkey", set80211weptxkey), 4479 DEF_CMD_ARG("wepkey", set80211wepkey), 4480 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 4481 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 4482 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 4483 DEF_CMD_ARG("protmode", set80211protmode), 4484 DEF_CMD_ARG("txpower", set80211txpower), 4485 DEF_CMD_ARG("roaming", set80211roaming), 4486 DEF_CMD("wme", 1, set80211wme), 4487 DEF_CMD("-wme", 0, set80211wme), 4488 DEF_CMD("wmm", 1, set80211wme), 4489 DEF_CMD("-wmm", 0, set80211wme), 4490 DEF_CMD("hidessid", 1, set80211hidessid), 4491 DEF_CMD("-hidessid", 0, set80211hidessid), 4492 DEF_CMD("apbridge", 1, set80211apbridge), 4493 DEF_CMD("-apbridge", 0, set80211apbridge), 4494 DEF_CMD_ARG("chanlist", set80211chanlist), 4495 DEF_CMD_ARG("bssid", set80211bssid), 4496 DEF_CMD_ARG("ap", set80211bssid), 4497 DEF_CMD("scan", 0, set80211scan), 4498 DEF_CMD_ARG("list", set80211list), 4499 DEF_CMD_ARG2("cwmin", set80211cwmin), 4500 DEF_CMD_ARG2("cwmax", set80211cwmax), 4501 DEF_CMD_ARG2("aifs", set80211aifs), 4502 DEF_CMD_ARG2("txoplimit", set80211txoplimit), 4503 DEF_CMD_ARG("acm", set80211acm), 4504 DEF_CMD_ARG("-acm", set80211noacm), 4505 DEF_CMD_ARG("ack", set80211ackpolicy), 4506 DEF_CMD_ARG("-ack", set80211noackpolicy), 4507 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 4508 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 4509 DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 4510 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 4511 DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 4512 DEF_CMD_ARG("bintval", set80211bintval), 4513 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 4514 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 4515 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 4516 DEF_CMD("mac:radius", IEEE80211_MACCMD_POLICY_RADIUS, set80211maccmd), 4517 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 4518 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 4519 DEF_CMD_ARG("mac:add", set80211addmac), 4520 DEF_CMD_ARG("mac:del", set80211delmac), 4521 DEF_CMD_ARG("mac:kick", set80211kickmac), 4522 DEF_CMD("pureg", 1, set80211pureg), 4523 DEF_CMD("-pureg", 0, set80211pureg), 4524 DEF_CMD("ff", 1, set80211fastframes), 4525 DEF_CMD("-ff", 0, set80211fastframes), 4526 DEF_CMD("dturbo", 1, set80211dturbo), 4527 DEF_CMD("-dturbo", 0, set80211dturbo), 4528 DEF_CMD("bgscan", 1, set80211bgscan), 4529 DEF_CMD("-bgscan", 0, set80211bgscan), 4530 DEF_CMD_ARG("bgscanidle", set80211bgscanidle), 4531 DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl), 4532 DEF_CMD_ARG("scanvalid", set80211scanvalid), 4533 DEF_CMD_ARG("roam:rssi", set80211roamrssi), 4534 DEF_CMD_ARG("roam:rate", set80211roamrate), 4535 DEF_CMD_ARG("mcastrate", set80211mcastrate), 4536 DEF_CMD_ARG("ucastrate", set80211ucastrate), 4537 DEF_CMD_ARG("mgtrate", set80211mgtrate), 4538 DEF_CMD_ARG("mgmtrate", set80211mgtrate), 4539 DEF_CMD_ARG("maxretry", set80211maxretry), 4540 DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 4541 DEF_CMD("burst", 1, set80211burst), 4542 DEF_CMD("-burst", 0, set80211burst), 4543 DEF_CMD_ARG("bmiss", set80211bmissthreshold), 4544 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 4545 DEF_CMD("shortgi", 1, set80211shortgi), 4546 DEF_CMD("-shortgi", 0, set80211shortgi), 4547 DEF_CMD("ampdurx", 2, set80211ampdu), 4548 DEF_CMD("-ampdurx", -2, set80211ampdu), 4549 DEF_CMD("ampdutx", 1, set80211ampdu), 4550 DEF_CMD("-ampdutx", -1, set80211ampdu), 4551 DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ 4552 DEF_CMD("-ampdu", -3, set80211ampdu), 4553 DEF_CMD_ARG("ampdulimit", set80211ampdulimit), 4554 DEF_CMD_ARG("ampdudensity", set80211ampdudensity), 4555 DEF_CMD("amsdurx", 2, set80211amsdu), 4556 DEF_CMD("-amsdurx", -2, set80211amsdu), 4557 DEF_CMD("amsdutx", 1, set80211amsdu), 4558 DEF_CMD("-amsdutx", -1, set80211amsdu), 4559 DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ 4560 DEF_CMD("-amsdu", -3, set80211amsdu), 4561 DEF_CMD_ARG("amsdulimit", set80211amsdulimit), 4562 DEF_CMD("puren", 1, set80211puren), 4563 DEF_CMD("-puren", 0, set80211puren), 4564 DEF_CMD("doth", 1, set80211doth), 4565 DEF_CMD("-doth", 0, set80211doth), 4566 DEF_CMD("dfs", 1, set80211dfs), 4567 DEF_CMD("-dfs", 0, set80211dfs), 4568 DEF_CMD("htcompat", 1, set80211htcompat), 4569 DEF_CMD("-htcompat", 0, set80211htcompat), 4570 DEF_CMD("dwds", 1, set80211dwds), 4571 DEF_CMD("-dwds", 0, set80211dwds), 4572 DEF_CMD("inact", 1, set80211inact), 4573 DEF_CMD("-inact", 0, set80211inact), 4574 DEF_CMD("tsn", 1, set80211tsn), 4575 DEF_CMD("-tsn", 0, set80211tsn), 4576 DEF_CMD_ARG("regdomain", set80211regdomain), 4577 DEF_CMD_ARG("country", set80211country), 4578 DEF_CMD("indoor", 'I', set80211location), 4579 DEF_CMD("-indoor", 'O', set80211location), 4580 DEF_CMD("outdoor", 'O', set80211location), 4581 DEF_CMD("-outdoor", 'I', set80211location), 4582 DEF_CMD("anywhere", ' ', set80211location), 4583 DEF_CMD("ecm", 1, set80211ecm), 4584 DEF_CMD("-ecm", 0, set80211ecm), 4585 DEF_CMD("dotd", 1, set80211dotd), 4586 DEF_CMD("-dotd", 0, set80211dotd), 4587 DEF_CMD_ARG("htprotmode", set80211htprotmode), 4588 DEF_CMD("ht20", 1, set80211htconf), 4589 DEF_CMD("-ht20", 0, set80211htconf), 4590 DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ 4591 DEF_CMD("-ht40", 0, set80211htconf), 4592 DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ 4593 DEF_CMD("-ht", 0, set80211htconf), 4594 /* XXX for testing */ 4595 DEF_CMD_ARG("chanswitch", set80211chanswitch), 4596 4597 /* vap cloning support */ 4598 DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr), 4599 DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid), 4600 DEF_CLONE_CMD_ARG("wlandev", set80211clone_wlandev), 4601 DEF_CLONE_CMD_ARG("wlanmode", set80211clone_wlanmode), 4602 DEF_CLONE_CMD("beacons", 1, set80211clone_beacons), 4603 DEF_CLONE_CMD("-beacons", 0, set80211clone_beacons), 4604 DEF_CLONE_CMD("bssid", 1, set80211clone_bssid), 4605 DEF_CLONE_CMD("-bssid", 0, set80211clone_bssid), 4606 DEF_CLONE_CMD("wdslegacy", 1, set80211clone_wdslegacy), 4607 DEF_CLONE_CMD("-wdslegacy", 0, set80211clone_wdslegacy), 4608}; 4609static struct afswtch af_ieee80211 = { 4610 .af_name = "af_ieee80211", 4611 .af_af = AF_UNSPEC, 4612 .af_other_status = ieee80211_status, 4613}; 4614 4615static __constructor void 4616ieee80211_ctor(void) 4617{ 4618#define N(a) (sizeof(a) / sizeof(a[0])) 4619 int i; 4620 4621 for (i = 0; i < N(ieee80211_cmds); i++) 4622 cmd_register(&ieee80211_cmds[i]); 4623 af_register(&af_ieee80211); 4624#undef N 4625} 4626