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