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