1 /* 2 * Copyright 2001 The Aerospace Corporation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of The Aerospace Corporation may not be used to endorse or 13 * promote products derived from this software. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 /*- 31 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 32 * All rights reserved. 33 * 34 * This code is derived from software contributed to The NetBSD Foundation 35 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 36 * NASA Ames Research Center. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the NetBSD 49 * Foundation, Inc. and its contributors. 50 * 4. Neither the name of The NetBSD Foundation nor the names of its 51 * contributors may be used to endorse or promote products derived 52 * from this software without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 55 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 * POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 #include <sys/param.h> 68 #include <sys/ioctl.h> 69 #include <sys/socket.h> 70 #include <sys/sysctl.h> 71 #include <sys/time.h> 72 73 #include <net/ethernet.h> 74 #include <net/if.h> 75 #include <net/if_dl.h> 76 #include <net/if_types.h> 77 #include <net/if_media.h> 78 #include <net/route.h> 79 80 #include <net80211/ieee80211.h> 81 #include <net80211/ieee80211_crypto.h> 82 #include <net80211/ieee80211_ioctl.h> 83 84 #include <ctype.h> 85 #include <err.h> 86 #include <errno.h> 87 #include <fcntl.h> 88 #include <inttypes.h> 89 #include <stdio.h> 90 #include <stdlib.h> 91 #include <string.h> 92 #include <unistd.h> 93 94 #include "ifconfig.h" 95 96 static void set80211(int s, int type, int val, int len, u_int8_t *data); 97 static const char *get_string(const char *val, const char *sep, 98 u_int8_t *buf, int *lenp); 99 static void print_string(const u_int8_t *buf, int len); 100 101 static int 102 isanyarg(const char *arg) 103 { 104 return (strcmp(arg, "-") == 0 || 105 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); 106 } 107 108 static void 109 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 110 { 111 int ssid; 112 int len; 113 u_int8_t data[IEEE80211_NWID_LEN]; 114 115 ssid = 0; 116 len = strlen(val); 117 if (len > 2 && isdigit(val[0]) && val[1] == ':') { 118 ssid = atoi(val)-1; 119 val += 2; 120 } 121 122 bzero(data, sizeof(data)); 123 len = sizeof(data); 124 if (get_string(val, NULL, data, &len) == NULL) 125 exit(1); 126 127 set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 128 } 129 130 static void 131 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 132 { 133 int len; 134 u_int8_t data[33]; 135 136 bzero(data, sizeof(data)); 137 len = sizeof(data); 138 get_string(val, NULL, data, &len); 139 140 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 141 } 142 143 /* 144 * Convert IEEE channel number to MHz frequency. 145 */ 146 static u_int 147 ieee80211_ieee2mhz(u_int chan) 148 { 149 if (chan == 14) 150 return 2484; 151 if (chan < 14) /* 0-13 */ 152 return 2407 + chan*5; 153 if (chan < 27) /* 15-26 */ 154 return 2512 + ((chan-15)*20); 155 return 5000 + (chan*5); 156 } 157 158 /* 159 * Convert MHz frequency to IEEE channel number. 160 */ 161 static u_int 162 ieee80211_mhz2ieee(u_int freq) 163 { 164 if (freq == 2484) 165 return 14; 166 if (freq < 2484) 167 return (freq - 2407) / 5; 168 if (freq < 5000) 169 return 15 + ((freq - 2512) / 20); 170 return (freq - 5000) / 5; 171 } 172 173 static void 174 set80211channel(const char *val, int d, int s, const struct afswtch *rafp) 175 { 176 if (!isanyarg(val)) { 177 int v = atoi(val); 178 if (v > 255) /* treat as frequency */ 179 v = ieee80211_mhz2ieee(v); 180 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); 181 } else 182 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 183 } 184 185 static void 186 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 187 { 188 int mode; 189 190 if (strcasecmp(val, "none") == 0) { 191 mode = IEEE80211_AUTH_NONE; 192 } else if (strcasecmp(val, "open") == 0) { 193 mode = IEEE80211_AUTH_OPEN; 194 } else if (strcasecmp(val, "shared") == 0) { 195 mode = IEEE80211_AUTH_SHARED; 196 } else if (strcasecmp(val, "8021x") == 0) { 197 mode = IEEE80211_AUTH_8021X; 198 } else if (strcasecmp(val, "wpa") == 0) { 199 mode = IEEE80211_AUTH_WPA; 200 } else { 201 errx(1, "unknown authmode"); 202 } 203 204 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 205 } 206 207 static void 208 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 209 { 210 int mode; 211 212 if (strcasecmp(val, "off") == 0) { 213 mode = IEEE80211_POWERSAVE_OFF; 214 } else if (strcasecmp(val, "on") == 0) { 215 mode = IEEE80211_POWERSAVE_ON; 216 } else if (strcasecmp(val, "cam") == 0) { 217 mode = IEEE80211_POWERSAVE_CAM; 218 } else if (strcasecmp(val, "psp") == 0) { 219 mode = IEEE80211_POWERSAVE_PSP; 220 } else if (strcasecmp(val, "psp-cam") == 0) { 221 mode = IEEE80211_POWERSAVE_PSP_CAM; 222 } else { 223 errx(1, "unknown powersavemode"); 224 } 225 226 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 227 } 228 229 static void 230 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 231 { 232 if (d == 0) 233 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 234 0, NULL); 235 else 236 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 237 0, NULL); 238 } 239 240 static void 241 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 242 { 243 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 244 } 245 246 static void 247 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 248 { 249 int mode; 250 251 if (strcasecmp(val, "off") == 0) { 252 mode = IEEE80211_WEP_OFF; 253 } else if (strcasecmp(val, "on") == 0) { 254 mode = IEEE80211_WEP_ON; 255 } else if (strcasecmp(val, "mixed") == 0) { 256 mode = IEEE80211_WEP_MIXED; 257 } else { 258 errx(1, "unknown wep mode"); 259 } 260 261 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 262 } 263 264 static void 265 set80211wep(const char *val, int d, int s, const struct afswtch *rafp) 266 { 267 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 268 } 269 270 static int 271 isundefarg(const char *arg) 272 { 273 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 274 } 275 276 static void 277 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 278 { 279 if (isundefarg(val)) 280 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 281 else 282 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 283 } 284 285 static void 286 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 287 { 288 int key = 0; 289 int len; 290 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 291 292 if (isdigit(val[0]) && val[1] == ':') { 293 key = atoi(val)-1; 294 val += 2; 295 } 296 297 bzero(data, sizeof(data)); 298 len = sizeof(data); 299 get_string(val, NULL, data, &len); 300 301 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 302 } 303 304 /* 305 * This function is purely a NetBSD compatability interface. The NetBSD 306 * interface is too inflexible, but it's there so we'll support it since 307 * it's not all that hard. 308 */ 309 static void 310 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 311 { 312 int txkey; 313 int i, len; 314 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 315 316 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 317 318 if (isdigit(val[0]) && val[1] == ':') { 319 txkey = val[0]-'0'-1; 320 val += 2; 321 322 for (i = 0; i < 4; i++) { 323 bzero(data, sizeof(data)); 324 len = sizeof(data); 325 val = get_string(val, ",", data, &len); 326 if (val == NULL) 327 exit(1); 328 329 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 330 } 331 } else { 332 bzero(data, sizeof(data)); 333 len = sizeof(data); 334 get_string(val, NULL, data, &len); 335 txkey = 0; 336 337 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 338 339 bzero(data, sizeof(data)); 340 for (i = 1; i < 4; i++) 341 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 342 } 343 344 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 345 } 346 347 static void 348 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 349 { 350 set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 351 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 352 } 353 354 static void 355 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 356 { 357 int mode; 358 359 if (strcasecmp(val, "off") == 0) { 360 mode = IEEE80211_PROTMODE_OFF; 361 } else if (strcasecmp(val, "cts") == 0) { 362 mode = IEEE80211_PROTMODE_CTS; 363 } else if (strcasecmp(val, "rtscts") == 0) { 364 mode = IEEE80211_PROTMODE_RTSCTS; 365 } else { 366 errx(1, "unknown protection mode"); 367 } 368 369 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 370 } 371 372 static void 373 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 374 { 375 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 376 } 377 378 #define IEEE80211_ROAMING_DEVICE 0 379 #define IEEE80211_ROAMING_AUTO 1 380 #define IEEE80211_ROAMING_MANUAL 2 381 382 static void 383 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 384 { 385 int mode; 386 387 if (strcasecmp(val, "device") == 0) { 388 mode = IEEE80211_ROAMING_DEVICE; 389 } else if (strcasecmp(val, "auto") == 0) { 390 mode = IEEE80211_ROAMING_AUTO; 391 } else if (strcasecmp(val, "manual") == 0) { 392 mode = IEEE80211_ROAMING_MANUAL; 393 } else { 394 errx(1, "unknown roaming mode"); 395 } 396 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 397 } 398 399 static void 400 set80211wme(const char *val, int d, int s, const struct afswtch *rafp) 401 { 402 set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 403 } 404 405 static void 406 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 407 { 408 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 409 } 410 411 static void 412 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 413 { 414 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 415 } 416 417 static void 418 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 419 { 420 struct ieee80211req_chanlist chanlist; 421 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 422 char *temp, *cp, *tp; 423 424 temp = malloc(strlen(val) + 1); 425 if (temp == NULL) 426 errx(1, "malloc failed"); 427 strcpy(temp, val); 428 memset(&chanlist, 0, sizeof(chanlist)); 429 cp = temp; 430 for (;;) { 431 int first, last, f; 432 433 tp = strchr(cp, ','); 434 if (tp != NULL) 435 *tp++ = '\0'; 436 switch (sscanf(cp, "%u-%u", &first, &last)) { 437 case 1: 438 if (first > MAXCHAN) 439 errx(-1, "channel %u out of range, max %zu", 440 first, MAXCHAN); 441 setbit(chanlist.ic_channels, first); 442 break; 443 case 2: 444 if (first > MAXCHAN) 445 errx(-1, "channel %u out of range, max %zu", 446 first, MAXCHAN); 447 if (last > MAXCHAN) 448 errx(-1, "channel %u out of range, max %zu", 449 last, MAXCHAN); 450 if (first > last) 451 errx(-1, "void channel range, %u > %u", 452 first, last); 453 for (f = first; f <= last; f++) 454 setbit(chanlist.ic_channels, f); 455 break; 456 } 457 if (tp == NULL) 458 break; 459 while (isspace(*tp)) 460 tp++; 461 if (!isdigit(*tp)) 462 break; 463 cp = tp; 464 } 465 set80211(s, IEEE80211_IOC_CHANLIST, 0, 466 sizeof(chanlist), (uint8_t *) &chanlist); 467 #undef MAXCHAN 468 } 469 470 static void 471 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 472 { 473 474 if (!isanyarg(val)) { 475 char *temp; 476 struct sockaddr_dl sdl; 477 478 temp = malloc(strlen(val) + 1); 479 if (temp == NULL) 480 errx(1, "malloc failed"); 481 temp[0] = ':'; 482 strcpy(temp + 1, val); 483 sdl.sdl_len = sizeof(sdl); 484 link_addr(temp, &sdl); 485 free(temp); 486 if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 487 errx(1, "malformed link-level address"); 488 set80211(s, IEEE80211_IOC_BSSID, 0, 489 IEEE80211_ADDR_LEN, LLADDR(&sdl)); 490 } else { 491 uint8_t zerobssid[IEEE80211_ADDR_LEN]; 492 memset(zerobssid, 0, sizeof(zerobssid)); 493 set80211(s, IEEE80211_IOC_BSSID, 0, 494 IEEE80211_ADDR_LEN, zerobssid); 495 } 496 } 497 498 static int 499 getac(const char *ac) 500 { 501 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 502 return WME_AC_BE; 503 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 504 return WME_AC_BK; 505 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 506 return WME_AC_VI; 507 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 508 return WME_AC_VO; 509 errx(1, "unknown wme access class %s", ac); 510 } 511 512 static 513 DECL_CMD_FUNC2(set80211cwmin, ac, val) 514 { 515 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 516 } 517 518 static 519 DECL_CMD_FUNC2(set80211cwmax, ac, val) 520 { 521 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 522 } 523 524 static 525 DECL_CMD_FUNC2(set80211aifs, ac, val) 526 { 527 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 528 } 529 530 static 531 DECL_CMD_FUNC2(set80211txoplimit, ac, val) 532 { 533 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 534 } 535 536 static 537 DECL_CMD_FUNC(set80211acm, ac, d) 538 { 539 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 540 } 541 static 542 DECL_CMD_FUNC(set80211noacm, ac, d) 543 { 544 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 545 } 546 547 static 548 DECL_CMD_FUNC(set80211ackpolicy, ac, d) 549 { 550 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 551 } 552 static 553 DECL_CMD_FUNC(set80211noackpolicy, ac, d) 554 { 555 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 556 } 557 558 static 559 DECL_CMD_FUNC2(set80211bsscwmin, ac, val) 560 { 561 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 562 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 563 } 564 565 static 566 DECL_CMD_FUNC2(set80211bsscwmax, ac, val) 567 { 568 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 569 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 570 } 571 572 static 573 DECL_CMD_FUNC2(set80211bssaifs, ac, val) 574 { 575 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 576 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 577 } 578 579 static 580 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 581 { 582 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 583 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 584 } 585 586 static 587 DECL_CMD_FUNC(set80211dtimperiod, val, d) 588 { 589 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 590 } 591 592 static 593 DECL_CMD_FUNC(set80211bintval, val, d) 594 { 595 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 596 } 597 598 static void 599 set80211macmac(int s, int op, const char *val) 600 { 601 char *temp; 602 struct sockaddr_dl sdl; 603 604 temp = malloc(strlen(val) + 1); 605 if (temp == NULL) 606 errx(1, "malloc failed"); 607 temp[0] = ':'; 608 strcpy(temp + 1, val); 609 sdl.sdl_len = sizeof(sdl); 610 link_addr(temp, &sdl); 611 free(temp); 612 if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 613 errx(1, "malformed link-level address"); 614 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 615 } 616 617 static 618 DECL_CMD_FUNC(set80211addmac, val, d) 619 { 620 set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 621 } 622 623 static 624 DECL_CMD_FUNC(set80211delmac, val, d) 625 { 626 set80211macmac(s, IEEE80211_IOC_DELMAC, val); 627 } 628 629 static 630 DECL_CMD_FUNC(set80211kickmac, val, d) 631 { 632 char *temp; 633 struct sockaddr_dl sdl; 634 struct ieee80211req_mlme mlme; 635 636 temp = malloc(strlen(val) + 1); 637 if (temp == NULL) 638 errx(1, "malloc failed"); 639 temp[0] = ':'; 640 strcpy(temp + 1, val); 641 sdl.sdl_len = sizeof(sdl); 642 link_addr(temp, &sdl); 643 free(temp); 644 if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 645 errx(1, "malformed link-level address"); 646 memset(&mlme, 0, sizeof(mlme)); 647 mlme.im_op = IEEE80211_MLME_DEAUTH; 648 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 649 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 650 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme); 651 } 652 653 static 654 DECL_CMD_FUNC(set80211maccmd, val, d) 655 { 656 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 657 } 658 659 static void 660 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 661 { 662 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 663 } 664 665 static 666 DECL_CMD_FUNC(set80211fragthreshold, val, d) 667 { 668 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 669 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 670 } 671 672 static int 673 getmaxrate(uint8_t rates[15], uint8_t nrates) 674 { 675 int i, maxrate = -1; 676 677 for (i = 0; i < nrates; i++) { 678 int rate = rates[i] & IEEE80211_RATE_VAL; 679 if (rate > maxrate) 680 maxrate = rate; 681 } 682 return maxrate / 2; 683 } 684 685 static const char * 686 getcaps(int capinfo) 687 { 688 static char capstring[32]; 689 char *cp = capstring; 690 691 if (capinfo & IEEE80211_CAPINFO_ESS) 692 *cp++ = 'E'; 693 if (capinfo & IEEE80211_CAPINFO_IBSS) 694 *cp++ = 'I'; 695 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 696 *cp++ = 'c'; 697 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 698 *cp++ = 'C'; 699 if (capinfo & IEEE80211_CAPINFO_PRIVACY) 700 *cp++ = 'P'; 701 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 702 *cp++ = 'S'; 703 if (capinfo & IEEE80211_CAPINFO_PBCC) 704 *cp++ = 'B'; 705 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 706 *cp++ = 'A'; 707 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 708 *cp++ = 's'; 709 if (capinfo & IEEE80211_CAPINFO_RSN) 710 *cp++ = 'R'; 711 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 712 *cp++ = 'D'; 713 *cp = '\0'; 714 return capstring; 715 } 716 717 static void 718 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 719 { 720 printf("%s", tag); 721 if (verbose) { 722 maxlen -= strlen(tag)+2; 723 if (2*ielen > maxlen) 724 maxlen--; 725 printf("<"); 726 for (; ielen > 0; ie++, ielen--) { 727 if (maxlen-- <= 0) 728 break; 729 printf("%02x", *ie); 730 } 731 if (ielen != 0) 732 printf("-"); 733 printf(">"); 734 } 735 } 736 737 /* 738 * Copy the ssid string contents into buf, truncating to fit. If the 739 * ssid is entirely printable then just copy intact. Otherwise convert 740 * to hexadecimal. If the result is truncated then replace the last 741 * three characters with "...". 742 */ 743 static int 744 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 745 { 746 const u_int8_t *p; 747 size_t maxlen; 748 int i; 749 750 if (essid_len > bufsize) 751 maxlen = bufsize; 752 else 753 maxlen = essid_len; 754 /* determine printable or not */ 755 for (i = 0, p = essid; i < maxlen; i++, p++) { 756 if (*p < ' ' || *p > 0x7e) 757 break; 758 } 759 if (i != maxlen) { /* not printable, print as hex */ 760 if (bufsize < 3) 761 return 0; 762 strlcpy(buf, "0x", bufsize); 763 bufsize -= 2; 764 p = essid; 765 for (i = 0; i < maxlen && bufsize >= 2; i++) { 766 sprintf(&buf[2+2*i], "%02x", p[i]); 767 bufsize -= 2; 768 } 769 if (i != essid_len) 770 memcpy(&buf[2+2*i-3], "...", 3); 771 } else { /* printable, truncate as needed */ 772 memcpy(buf, essid, maxlen); 773 if (maxlen != essid_len) 774 memcpy(&buf[maxlen-3], "...", 3); 775 } 776 return maxlen; 777 } 778 779 /* unaligned little endian access */ 780 #define LE_READ_4(p) \ 781 ((u_int32_t) \ 782 ((((const u_int8_t *)(p))[0] ) | \ 783 (((const u_int8_t *)(p))[1] << 8) | \ 784 (((const u_int8_t *)(p))[2] << 16) | \ 785 (((const u_int8_t *)(p))[3] << 24))) 786 787 static int __inline 788 iswpaoui(const u_int8_t *frm) 789 { 790 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 791 } 792 793 static int __inline 794 iswmeoui(const u_int8_t *frm) 795 { 796 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); 797 } 798 799 static int __inline 800 isatherosoui(const u_int8_t *frm) 801 { 802 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 803 } 804 805 static void 806 printies(const u_int8_t *vp, int ielen, int maxcols) 807 { 808 while (ielen > 0) { 809 switch (vp[0]) { 810 case IEEE80211_ELEMID_VENDOR: 811 if (iswpaoui(vp)) 812 printie(" WPA", vp, 2+vp[1], maxcols); 813 else if (iswmeoui(vp)) 814 printie(" WME", vp, 2+vp[1], maxcols); 815 else if (isatherosoui(vp)) 816 printie(" ATH", vp, 2+vp[1], maxcols); 817 else 818 printie(" VEN", vp, 2+vp[1], maxcols); 819 break; 820 case IEEE80211_ELEMID_RSN: 821 printie(" RSN", vp, 2+vp[1], maxcols); 822 break; 823 default: 824 printie(" ???", vp, 2+vp[1], maxcols); 825 break; 826 } 827 ielen -= 2+vp[1]; 828 vp += 2+vp[1]; 829 } 830 } 831 832 static void 833 list_scan(int s) 834 { 835 uint8_t buf[24*1024]; 836 struct ieee80211req ireq; 837 char ssid[14]; 838 uint8_t *cp; 839 int len; 840 841 (void) memset(&ireq, 0, sizeof(ireq)); 842 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 843 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 844 ireq.i_data = buf; 845 ireq.i_len = sizeof(buf); 846 if (ioctl(s, SIOCG80211, &ireq) < 0) 847 errx(1, "unable to get scan results"); 848 len = ireq.i_len; 849 if (len < sizeof(struct ieee80211req_scan_result)) 850 return; 851 852 printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n" 853 , "SSID" 854 , "BSSID" 855 , "CHAN" 856 , "RATE" 857 , "S:N" 858 , "INT" 859 , "CAPS" 860 ); 861 cp = buf; 862 do { 863 struct ieee80211req_scan_result *sr; 864 uint8_t *vp; 865 866 sr = (struct ieee80211req_scan_result *) cp; 867 vp = (u_int8_t *)(sr+1); 868 printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" 869 , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len) 870 , ssid 871 , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 872 , ieee80211_mhz2ieee(sr->isr_freq) 873 , getmaxrate(sr->isr_rates, sr->isr_nrates) 874 , sr->isr_rssi, sr->isr_noise 875 , sr->isr_intval 876 , getcaps(sr->isr_capinfo) 877 ); 878 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 879 printf("\n"); 880 cp += sr->isr_len, len -= sr->isr_len; 881 } while (len >= sizeof(struct ieee80211req_scan_result)); 882 } 883 884 #include <net80211/ieee80211_freebsd.h> 885 886 static void 887 scan_and_wait(int s) 888 { 889 struct ieee80211req ireq; 890 int sroute; 891 892 sroute = socket(PF_ROUTE, SOCK_RAW, 0); 893 if (sroute < 0) { 894 perror("socket(PF_ROUTE,SOCK_RAW)"); 895 return; 896 } 897 (void) memset(&ireq, 0, sizeof(ireq)); 898 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 899 ireq.i_type = IEEE80211_IOC_SCAN_REQ; 900 /* NB: only root can trigger a scan so ignore errors */ 901 if (ioctl(s, SIOCS80211, &ireq) >= 0) { 902 char buf[2048]; 903 struct if_announcemsghdr *ifan; 904 struct rt_msghdr *rtm; 905 906 do { 907 if (read(sroute, buf, sizeof(buf)) < 0) { 908 perror("read(PF_ROUTE)"); 909 break; 910 } 911 rtm = (struct rt_msghdr *) buf; 912 if (rtm->rtm_version != RTM_VERSION) 913 break; 914 ifan = (struct if_announcemsghdr *) rtm; 915 } while (rtm->rtm_type != RTM_IEEE80211 || 916 ifan->ifan_what != RTM_IEEE80211_SCAN); 917 } 918 close(sroute); 919 } 920 921 static 922 DECL_CMD_FUNC(set80211scan, val, d) 923 { 924 scan_and_wait(s); 925 list_scan(s); 926 } 927 928 static void 929 list_stations(int s) 930 { 931 uint8_t buf[24*1024]; 932 struct ieee80211req ireq; 933 uint8_t *cp; 934 int len; 935 936 (void) memset(&ireq, 0, sizeof(ireq)); 937 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 938 ireq.i_type = IEEE80211_IOC_STA_INFO; 939 ireq.i_data = buf; 940 ireq.i_len = sizeof(buf); 941 if (ioctl(s, SIOCG80211, &ireq) < 0) 942 errx(1, "unable to get station information"); 943 len = ireq.i_len; 944 if (len < sizeof(struct ieee80211req_sta_info)) 945 return; 946 947 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n" 948 , "ADDR" 949 , "AID" 950 , "CHAN" 951 , "RATE" 952 , "RSSI" 953 , "IDLE" 954 , "TXSEQ" 955 , "RXSEQ" 956 , "CAPS" 957 , "ERP" 958 ); 959 cp = buf; 960 do { 961 struct ieee80211req_sta_info *si; 962 uint8_t *vp; 963 964 si = (struct ieee80211req_sta_info *) cp; 965 vp = (u_int8_t *)(si+1); 966 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x" 967 , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 968 , IEEE80211_AID(si->isi_associd) 969 , ieee80211_mhz2ieee(si->isi_freq) 970 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 971 , si->isi_rssi 972 , si->isi_inact 973 , si->isi_txseqs[0] 974 , si->isi_rxseqs[0] 975 , getcaps(si->isi_capinfo) 976 , si->isi_erp 977 ); 978 printies(vp, si->isi_ie_len, 24); 979 printf("\n"); 980 cp += si->isi_len, len -= si->isi_len; 981 } while (len >= sizeof(struct ieee80211req_sta_info)); 982 } 983 984 static void 985 print_chaninfo(const struct ieee80211_channel *c) 986 { 987 #define IEEE80211_IS_CHAN_PASSIVE(_c) \ 988 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) 989 char buf[14]; 990 991 buf[0] = '\0'; 992 if (IEEE80211_IS_CHAN_FHSS(c)) 993 strlcat(buf, " FHSS", sizeof(buf)); 994 if (IEEE80211_IS_CHAN_A(c)) 995 strlcat(buf, " 11a", sizeof(buf)); 996 /* XXX 11g schizophrenia */ 997 if (IEEE80211_IS_CHAN_G(c) || 998 IEEE80211_IS_CHAN_PUREG(c)) 999 strlcat(buf, " 11g", sizeof(buf)); 1000 else if (IEEE80211_IS_CHAN_B(c)) 1001 strlcat(buf, " 11b", sizeof(buf)); 1002 if (IEEE80211_IS_CHAN_T(c)) 1003 strlcat(buf, " Turbo", sizeof(buf)); 1004 printf("Channel %3u : %u%c Mhz%-14.14s", 1005 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq, 1006 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); 1007 #undef IEEE80211_IS_CHAN_PASSIVE 1008 } 1009 1010 static void 1011 list_channels(int s, int allchans) 1012 { 1013 struct ieee80211req ireq; 1014 struct ieee80211req_chaninfo chans; 1015 struct ieee80211req_chaninfo achans; 1016 const struct ieee80211_channel *c; 1017 int i, half; 1018 1019 (void) memset(&ireq, 0, sizeof(ireq)); 1020 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1021 ireq.i_type = IEEE80211_IOC_CHANINFO; 1022 ireq.i_data = &chans; 1023 ireq.i_len = sizeof(chans); 1024 if (ioctl(s, SIOCG80211, &ireq) < 0) 1025 errx(1, "unable to get channel information"); 1026 if (!allchans) { 1027 struct ieee80211req_chanlist active; 1028 1029 ireq.i_type = IEEE80211_IOC_CHANLIST; 1030 ireq.i_data = &active; 1031 ireq.i_len = sizeof(active); 1032 if (ioctl(s, SIOCG80211, &ireq) < 0) 1033 errx(1, "unable to get active channel list"); 1034 memset(&achans, 0, sizeof(achans)); 1035 for (i = 0; i < chans.ic_nchans; i++) { 1036 c = &chans.ic_chans[i]; 1037 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans) 1038 achans.ic_chans[achans.ic_nchans++] = *c; 1039 } 1040 } else 1041 achans = chans; 1042 half = achans.ic_nchans / 2; 1043 if (achans.ic_nchans % 2) 1044 half++; 1045 for (i = 0; i < achans.ic_nchans / 2; i++) { 1046 print_chaninfo(&achans.ic_chans[i]); 1047 print_chaninfo(&achans.ic_chans[half+i]); 1048 printf("\n"); 1049 } 1050 if (achans.ic_nchans % 2) { 1051 print_chaninfo(&achans.ic_chans[i]); 1052 printf("\n"); 1053 } 1054 } 1055 1056 static void 1057 list_keys(int s) 1058 { 1059 } 1060 1061 #define IEEE80211_C_BITS \ 1062 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 1063 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 1064 "\31WPA2\32BURST\33WME" 1065 1066 static void 1067 list_capabilities(int s) 1068 { 1069 struct ieee80211req ireq; 1070 u_int32_t caps; 1071 1072 (void) memset(&ireq, 0, sizeof(ireq)); 1073 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1074 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 1075 if (ioctl(s, SIOCG80211, &ireq) < 0) 1076 errx(1, "unable to get driver capabilities"); 1077 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 1078 printb(name, caps, IEEE80211_C_BITS); 1079 putchar('\n'); 1080 } 1081 1082 static void 1083 list_wme(int s) 1084 { 1085 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 1086 struct ieee80211req ireq; 1087 int ac; 1088 1089 (void) memset(&ireq, 0, sizeof(ireq)); 1090 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1091 ireq.i_len = 0; 1092 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 1093 again: 1094 if (ireq.i_len & IEEE80211_WMEPARAM_BSS) 1095 printf("\t%s", " "); 1096 else 1097 printf("\t%s", acnames[ac]); 1098 1099 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; 1100 1101 /* show WME BSS parameters */ 1102 ireq.i_type = IEEE80211_IOC_WME_CWMIN; 1103 if (ioctl(s, SIOCG80211, &ireq) != -1) 1104 printf(" cwmin %2u", ireq.i_val); 1105 ireq.i_type = IEEE80211_IOC_WME_CWMAX; 1106 if (ioctl(s, SIOCG80211, &ireq) != -1) 1107 printf(" cwmax %2u", ireq.i_val); 1108 ireq.i_type = IEEE80211_IOC_WME_AIFS; 1109 if (ioctl(s, SIOCG80211, &ireq) != -1) 1110 printf(" aifs %2u", ireq.i_val); 1111 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; 1112 if (ioctl(s, SIOCG80211, &ireq) != -1) 1113 printf(" txopLimit %3u", ireq.i_val); 1114 ireq.i_type = IEEE80211_IOC_WME_ACM; 1115 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1116 if (ireq.i_val) 1117 printf(" acm"); 1118 else if (verbose) 1119 printf(" -acm"); 1120 } 1121 /* !BSS only */ 1122 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1123 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; 1124 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1125 if (!ireq.i_val) 1126 printf(" -ack"); 1127 else if (verbose) 1128 printf(" ack"); 1129 } 1130 } 1131 printf("\n"); 1132 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1133 ireq.i_len |= IEEE80211_WMEPARAM_BSS; 1134 goto again; 1135 } else 1136 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; 1137 } 1138 } 1139 1140 static void 1141 list_mac(int s) 1142 { 1143 struct ieee80211req ireq; 1144 struct ieee80211req_maclist *acllist; 1145 int i, nacls, policy; 1146 char c; 1147 1148 (void) memset(&ireq, 0, sizeof(ireq)); 1149 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 1150 ireq.i_type = IEEE80211_IOC_MACCMD; 1151 ireq.i_val = IEEE80211_MACCMD_POLICY; 1152 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1153 if (errno == EINVAL) { 1154 printf("No acl policy loaded\n"); 1155 return; 1156 } 1157 err(1, "unable to get mac policy"); 1158 } 1159 policy = ireq.i_val; 1160 1161 ireq.i_val = IEEE80211_MACCMD_LIST; 1162 ireq.i_len = 0; 1163 if (ioctl(s, SIOCG80211, &ireq) < 0) 1164 err(1, "unable to get mac acl list size"); 1165 if (ireq.i_len == 0) /* NB: no acls */ 1166 return; 1167 1168 ireq.i_data = malloc(ireq.i_len); 1169 if (ireq.i_data == NULL) 1170 err(1, "out of memory for acl list"); 1171 1172 if (ioctl(s, SIOCG80211, &ireq) < 0) 1173 err(1, "unable to get mac acl list"); 1174 if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 1175 if (verbose) 1176 printf("policy: open\n"); 1177 c = '*'; 1178 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 1179 if (verbose) 1180 printf("policy: allow\n"); 1181 c = '+'; 1182 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 1183 if (verbose) 1184 printf("policy: deny\n"); 1185 c = '-'; 1186 } else { 1187 printf("policy: unknown (%u)\n", policy); 1188 c = '?'; 1189 } 1190 nacls = ireq.i_len / sizeof(*acllist); 1191 acllist = (struct ieee80211req_maclist *) ireq.i_data; 1192 for (i = 0; i < nacls; i++) 1193 printf("%c%s\n", c, ether_ntoa( 1194 (const struct ether_addr *) acllist[i].ml_macaddr)); 1195 } 1196 1197 static 1198 DECL_CMD_FUNC(set80211list, arg, d) 1199 { 1200 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 1201 1202 if (iseq(arg, "sta")) 1203 list_stations(s); 1204 else if (iseq(arg, "scan") || iseq(arg, "ap")) 1205 list_scan(s); 1206 else if (iseq(arg, "chan") || iseq(arg, "freq")) 1207 list_channels(s, 1); 1208 else if (iseq(arg, "active")) 1209 list_channels(s, 0); 1210 else if (iseq(arg, "keys")) 1211 list_keys(s); 1212 else if (iseq(arg, "caps")) 1213 list_capabilities(s); 1214 else if (iseq(arg, "wme")) 1215 list_wme(s); 1216 else if (iseq(arg, "mac")) 1217 list_mac(s); 1218 else 1219 errx(1, "Don't know how to list %s for %s", arg, name); 1220 #undef iseq 1221 } 1222 1223 static enum ieee80211_opmode 1224 get80211opmode(int s) 1225 { 1226 struct ifmediareq ifmr; 1227 1228 (void) memset(&ifmr, 0, sizeof(ifmr)); 1229 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1230 1231 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1232 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 1233 return IEEE80211_M_IBSS; /* XXX ahdemo */ 1234 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1235 return IEEE80211_M_HOSTAP; 1236 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1237 return IEEE80211_M_MONITOR; 1238 } 1239 return IEEE80211_M_STA; 1240 } 1241 1242 static const struct ieee80211_channel * 1243 getchaninfo(int s, int chan) 1244 { 1245 struct ieee80211req ireq; 1246 static struct ieee80211req_chaninfo chans; 1247 static struct ieee80211_channel undef; 1248 const struct ieee80211_channel *c; 1249 int i, freq; 1250 1251 (void) memset(&ireq, 0, sizeof(ireq)); 1252 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1253 ireq.i_type = IEEE80211_IOC_CHANINFO; 1254 ireq.i_data = &chans; 1255 ireq.i_len = sizeof(chans); 1256 if (ioctl(s, SIOCG80211, &ireq) < 0) 1257 errx(1, "unable to get channel information"); 1258 freq = ieee80211_ieee2mhz(chan); 1259 for (i = 0; i < chans.ic_nchans; i++) { 1260 c = &chans.ic_chans[i]; 1261 if (c->ic_freq == freq) 1262 return c; 1263 } 1264 return &undef; 1265 } 1266 1267 #if 0 1268 static void 1269 printcipher(int s, struct ieee80211req *ireq, int keylenop) 1270 { 1271 switch (ireq->i_val) { 1272 case IEEE80211_CIPHER_WEP: 1273 ireq->i_type = keylenop; 1274 if (ioctl(s, SIOCG80211, ireq) != -1) 1275 printf("WEP-%s", 1276 ireq->i_len <= 5 ? "40" : 1277 ireq->i_len <= 13 ? "104" : "128"); 1278 else 1279 printf("WEP"); 1280 break; 1281 case IEEE80211_CIPHER_TKIP: 1282 printf("TKIP"); 1283 break; 1284 case IEEE80211_CIPHER_AES_OCB: 1285 printf("AES-OCB"); 1286 break; 1287 case IEEE80211_CIPHER_AES_CCM: 1288 printf("AES-CCM"); 1289 break; 1290 case IEEE80211_CIPHER_CKIP: 1291 printf("CKIP"); 1292 break; 1293 case IEEE80211_CIPHER_NONE: 1294 printf("NONE"); 1295 break; 1296 default: 1297 printf("UNKNOWN (0x%x)", ireq->i_val); 1298 break; 1299 } 1300 } 1301 #endif 1302 1303 #define MAXCOL 78 1304 int col; 1305 char spacer; 1306 1307 #define LINE_BREAK() do { \ 1308 if (spacer != '\t') { \ 1309 printf("\n"); \ 1310 spacer = '\t'; \ 1311 } \ 1312 col = 8; /* 8-col tab */ \ 1313 } while (0) 1314 #define LINE_CHECK(fmt, ...) do { \ 1315 col += sizeof(fmt)-2; \ 1316 if (col > MAXCOL) { \ 1317 LINE_BREAK(); \ 1318 col += sizeof(fmt)-2; \ 1319 } \ 1320 printf(fmt, __VA_ARGS__); \ 1321 spacer = ' '; \ 1322 } while (0) 1323 1324 static void 1325 printkey(const struct ieee80211req_key *ik) 1326 { 1327 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 1328 int keylen = ik->ik_keylen; 1329 int printcontents; 1330 1331 printcontents = printkeys && 1332 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 1333 if (printcontents) 1334 LINE_BREAK(); 1335 switch (ik->ik_type) { 1336 case IEEE80211_CIPHER_WEP: 1337 /* compatibility */ 1338 LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1, 1339 keylen <= 5 ? "40-bit" : 1340 keylen <= 13 ? "104-bit" : "128-bit"); 1341 break; 1342 case IEEE80211_CIPHER_TKIP: 1343 if (keylen > 128/8) 1344 keylen -= 128/8; /* ignore MIC for now */ 1345 LINE_CHECK("%cTKIP %u:%u-bit", 1346 spacer, ik->ik_keyix+1, 8*keylen); 1347 break; 1348 case IEEE80211_CIPHER_AES_OCB: 1349 LINE_CHECK("%cAES-OCB %u:%u-bit", 1350 spacer, ik->ik_keyix+1, 8*keylen); 1351 break; 1352 case IEEE80211_CIPHER_AES_CCM: 1353 LINE_CHECK("%cAES-CCM %u:%u-bit", 1354 spacer, ik->ik_keyix+1, 8*keylen); 1355 break; 1356 case IEEE80211_CIPHER_CKIP: 1357 LINE_CHECK("%cCKIP %u:%u-bit", 1358 spacer, ik->ik_keyix+1, 8*keylen); 1359 break; 1360 case IEEE80211_CIPHER_NONE: 1361 LINE_CHECK("%cNULL %u:%u-bit", 1362 spacer, ik->ik_keyix+1, 8*keylen); 1363 break; 1364 default: 1365 LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer, 1366 ik->ik_type, ik->ik_keyix+1, 8*keylen); 1367 break; 1368 } 1369 if (printcontents) { 1370 int i; 1371 1372 printf(" <"); 1373 for (i = 0; i < keylen; i++) 1374 printf("%02x", ik->ik_keydata[i]); 1375 printf(">"); 1376 if (ik->ik_type != IEEE80211_CIPHER_WEP && 1377 (ik->ik_keyrsc != 0 || verbose)) 1378 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 1379 if (ik->ik_type != IEEE80211_CIPHER_WEP && 1380 (ik->ik_keytsc != 0 || verbose)) 1381 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 1382 if (ik->ik_flags != 0 && verbose) { 1383 const char *sep = " "; 1384 1385 if (ik->ik_flags & IEEE80211_KEY_XMIT) 1386 printf("%stx", sep), sep = "+"; 1387 if (ik->ik_flags & IEEE80211_KEY_RECV) 1388 printf("%srx", sep), sep = "+"; 1389 if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 1390 printf("%sdef", sep), sep = "+"; 1391 } 1392 LINE_BREAK(); 1393 } 1394 } 1395 1396 static void 1397 ieee80211_status(int s) 1398 { 1399 static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1400 enum ieee80211_opmode opmode = get80211opmode(s); 1401 int i, num, wpa, wme; 1402 struct ieee80211req ireq; 1403 u_int8_t data[32]; 1404 const struct ieee80211_channel *c; 1405 1406 (void) memset(&ireq, 0, sizeof(ireq)); 1407 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1408 ireq.i_data = &data; 1409 1410 wpa = 0; /* unknown/not set */ 1411 1412 ireq.i_type = IEEE80211_IOC_SSID; 1413 ireq.i_val = -1; 1414 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1415 /* If we can't get the SSID, this isn't an 802.11 device. */ 1416 return; 1417 } 1418 num = 0; 1419 ireq.i_type = IEEE80211_IOC_NUMSSIDS; 1420 if (ioctl(s, SIOCG80211, &ireq) >= 0) 1421 num = ireq.i_val; 1422 printf("\tssid "); 1423 if (num > 1) { 1424 ireq.i_type = IEEE80211_IOC_SSID; 1425 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 1426 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 1427 printf(" %d:", ireq.i_val + 1); 1428 print_string(data, ireq.i_len); 1429 } 1430 } 1431 } else 1432 print_string(data, ireq.i_len); 1433 1434 ireq.i_type = IEEE80211_IOC_CHANNEL; 1435 if (ioctl(s, SIOCG80211, &ireq) < 0) 1436 goto end; 1437 c = getchaninfo(s, ireq.i_val); 1438 if (ireq.i_val != -1) { 1439 printf(" channel %d", ireq.i_val); 1440 if (verbose) 1441 printf(" (%u)", c->ic_freq); 1442 } else if (verbose) 1443 printf(" channel UNDEF"); 1444 1445 ireq.i_type = IEEE80211_IOC_BSSID; 1446 ireq.i_len = IEEE80211_ADDR_LEN; 1447 if (ioctl(s, SIOCG80211, &ireq) >= 0 && 1448 memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0) 1449 printf(" bssid %s", ether_ntoa(ireq.i_data)); 1450 1451 ireq.i_type = IEEE80211_IOC_STATIONNAME; 1452 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1453 printf("\n\tstationname "); 1454 print_string(data, ireq.i_len); 1455 } 1456 1457 spacer = ' '; /* force first break */ 1458 LINE_BREAK(); 1459 1460 ireq.i_type = IEEE80211_IOC_AUTHMODE; 1461 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1462 switch (ireq.i_val) { 1463 case IEEE80211_AUTH_NONE: 1464 LINE_CHECK("%cauthmode NONE", spacer); 1465 break; 1466 case IEEE80211_AUTH_OPEN: 1467 LINE_CHECK("%cauthmode OPEN", spacer); 1468 break; 1469 case IEEE80211_AUTH_SHARED: 1470 LINE_CHECK("%cauthmode SHARED", spacer); 1471 break; 1472 case IEEE80211_AUTH_8021X: 1473 LINE_CHECK("%cauthmode 802.1x", spacer); 1474 break; 1475 case IEEE80211_AUTH_WPA: 1476 ireq.i_type = IEEE80211_IOC_WPA; 1477 if (ioctl(s, SIOCG80211, &ireq) != -1) 1478 wpa = ireq.i_val; 1479 if (!wpa) 1480 wpa = 1; /* default to WPA1 */ 1481 switch (wpa) { 1482 case 2: 1483 LINE_CHECK("%cauthmode WPA2/802.11i", 1484 spacer); 1485 break; 1486 case 3: 1487 LINE_CHECK("%cauthmode WPA1+WPA2/802.11i", 1488 spacer); 1489 break; 1490 default: 1491 LINE_CHECK("%cauthmode WPA", spacer); 1492 break; 1493 } 1494 break; 1495 case IEEE80211_AUTH_AUTO: 1496 LINE_CHECK("%cauthmode AUTO", spacer); 1497 break; 1498 default: 1499 LINE_CHECK("%cauthmode UNKNOWN (0x%x)", 1500 spacer, ireq.i_val); 1501 break; 1502 } 1503 } 1504 1505 ireq.i_type = IEEE80211_IOC_WEP; 1506 if (ioctl(s, SIOCG80211, &ireq) != -1 && 1507 ireq.i_val != IEEE80211_WEP_NOSUP) { 1508 int firstkey, wepmode; 1509 1510 wepmode = ireq.i_val; 1511 switch (wepmode) { 1512 case IEEE80211_WEP_OFF: 1513 LINE_CHECK("%cprivacy OFF", spacer); 1514 break; 1515 case IEEE80211_WEP_ON: 1516 LINE_CHECK("%cprivacy ON", spacer); 1517 break; 1518 case IEEE80211_WEP_MIXED: 1519 LINE_CHECK("%cprivacy MIXED", spacer); 1520 break; 1521 default: 1522 LINE_CHECK("%cprivacy UNKNOWN (0x%x)", 1523 spacer, wepmode); 1524 break; 1525 } 1526 1527 /* 1528 * If we get here then we've got WEP support so we need 1529 * to print WEP status. 1530 */ 1531 1532 ireq.i_type = IEEE80211_IOC_WEPTXKEY; 1533 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1534 warn("WEP support, but no tx key!"); 1535 goto end; 1536 } 1537 if (ireq.i_val != -1) 1538 LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1); 1539 else if (wepmode != IEEE80211_WEP_OFF || verbose) 1540 LINE_CHECK("%cdeftxkey UNDEF", spacer); 1541 1542 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 1543 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1544 warn("WEP support, but no NUMWEPKEYS support!"); 1545 goto end; 1546 } 1547 num = ireq.i_val; 1548 1549 firstkey = 1; 1550 for (i = 0; i < num; i++) { 1551 struct ieee80211req_key ik; 1552 1553 memset(&ik, 0, sizeof(ik)); 1554 ik.ik_keyix = i; 1555 ireq.i_type = IEEE80211_IOC_WPAKEY; 1556 ireq.i_data = &ik; 1557 ireq.i_len = sizeof(ik); 1558 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1559 warn("WEP support, but can get keys!"); 1560 goto end; 1561 } 1562 if (ik.ik_keylen != 0) { 1563 if (verbose) 1564 LINE_BREAK(); 1565 printkey(&ik); 1566 firstkey = 0; 1567 } 1568 } 1569 } 1570 1571 ireq.i_type = IEEE80211_IOC_POWERSAVE; 1572 if (ioctl(s, SIOCG80211, &ireq) != -1 && 1573 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 1574 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { 1575 switch (ireq.i_val) { 1576 case IEEE80211_POWERSAVE_OFF: 1577 LINE_CHECK("%cpowersavemode OFF", 1578 spacer); 1579 break; 1580 case IEEE80211_POWERSAVE_CAM: 1581 LINE_CHECK("%cpowersavemode CAM", 1582 spacer); 1583 break; 1584 case IEEE80211_POWERSAVE_PSP: 1585 LINE_CHECK("%cpowersavemode PSP", 1586 spacer); 1587 break; 1588 case IEEE80211_POWERSAVE_PSP_CAM: 1589 LINE_CHECK("%cpowersavemode PSP-CAM", 1590 spacer); 1591 break; 1592 } 1593 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 1594 if (ioctl(s, SIOCG80211, &ireq) != -1) 1595 LINE_CHECK("%cpowersavesleep %d", 1596 spacer, ireq.i_val); 1597 } 1598 } 1599 1600 ireq.i_type = IEEE80211_IOC_TXPOWMAX; 1601 if (ioctl(s, SIOCG80211, &ireq) != -1) 1602 LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val); 1603 1604 if (verbose) { 1605 ireq.i_type = IEEE80211_IOC_TXPOWER; 1606 if (ioctl(s, SIOCG80211, &ireq) != -1) 1607 LINE_CHECK("%ctxpower %d", spacer, ireq.i_val); 1608 } 1609 1610 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 1611 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1612 if (ireq.i_val != IEEE80211_RTS_MAX || verbose) 1613 LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val); 1614 } 1615 1616 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 1617 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1618 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose) 1619 LINE_CHECK("%cfragthreshold %d", spacer, ireq.i_val); 1620 } 1621 1622 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) { 1623 ireq.i_type = IEEE80211_IOC_PUREG; 1624 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1625 if (ireq.i_val) 1626 LINE_CHECK("%cpureg", spacer); 1627 else if (verbose) 1628 LINE_CHECK("%c-pureg", spacer); 1629 } 1630 ireq.i_type = IEEE80211_IOC_PROTMODE; 1631 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1632 switch (ireq.i_val) { 1633 case IEEE80211_PROTMODE_OFF: 1634 LINE_CHECK("%cprotmode OFF", spacer); 1635 break; 1636 case IEEE80211_PROTMODE_CTS: 1637 LINE_CHECK("%cprotmode CTS", spacer); 1638 break; 1639 case IEEE80211_PROTMODE_RTSCTS: 1640 LINE_CHECK("%cprotmode RTSCTS", spacer); 1641 break; 1642 default: 1643 LINE_CHECK("%cprotmode UNKNOWN (0x%x)", 1644 spacer, ireq.i_val); 1645 break; 1646 } 1647 } 1648 } 1649 1650 ireq.i_type = IEEE80211_IOC_WME; 1651 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1652 wme = ireq.i_val; 1653 if (wme) 1654 LINE_CHECK("%cwme", spacer); 1655 else if (verbose) 1656 LINE_CHECK("%c-wme", spacer); 1657 } else 1658 wme = 0; 1659 1660 if (opmode == IEEE80211_M_HOSTAP) { 1661 ireq.i_type = IEEE80211_IOC_HIDESSID; 1662 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1663 if (ireq.i_val) 1664 LINE_CHECK("%cssid HIDE", spacer); 1665 else if (verbose) 1666 LINE_CHECK("%cssid SHOW", spacer); 1667 } 1668 1669 ireq.i_type = IEEE80211_IOC_APBRIDGE; 1670 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1671 if (!ireq.i_val) 1672 LINE_CHECK("%c-apbridge", spacer); 1673 else if (verbose) 1674 LINE_CHECK("%capbridge", spacer); 1675 } 1676 1677 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; 1678 if (ioctl(s, SIOCG80211, &ireq) != -1) 1679 LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val); 1680 } else { 1681 ireq.i_type = IEEE80211_IOC_ROAMING; 1682 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1683 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { 1684 switch (ireq.i_val) { 1685 case IEEE80211_ROAMING_DEVICE: 1686 LINE_CHECK("%croaming DEVICE", spacer); 1687 break; 1688 case IEEE80211_ROAMING_AUTO: 1689 LINE_CHECK("%croaming AUTO", spacer); 1690 break; 1691 case IEEE80211_ROAMING_MANUAL: 1692 LINE_CHECK("%croaming MANUAL", spacer); 1693 break; 1694 default: 1695 LINE_CHECK("%croaming UNKNOWN (0x%x)", 1696 spacer, ireq.i_val); 1697 break; 1698 } 1699 } 1700 } 1701 } 1702 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; 1703 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1704 if (ireq.i_val) 1705 LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1706 else if (verbose) 1707 LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1708 } 1709 1710 if (wme && verbose) { 1711 LINE_BREAK(); 1712 list_wme(s); 1713 } 1714 1715 if (wpa) { 1716 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; 1717 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1718 if (ireq.i_val) 1719 LINE_CHECK("%ccountermeasures", spacer); 1720 else if (verbose) 1721 LINE_CHECK("%c-countermeasures", spacer); 1722 } 1723 #if 0 1724 /* XXX not interesting with WPA done in user space */ 1725 ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 1726 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1727 } 1728 1729 ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 1730 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1731 printf("%cmcastcipher ", spacer); 1732 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 1733 spacer = ' '; 1734 } 1735 1736 ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 1737 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1738 printf("%cucastcipher ", spacer); 1739 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 1740 } 1741 1742 if (wpa & 2) { 1743 ireq.i_type = IEEE80211_IOC_RSNCAPS; 1744 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1745 printf("%cRSN caps 0x%x", spacer, ireq.i_val); 1746 spacer = ' '; 1747 } 1748 } 1749 1750 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 1751 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1752 } 1753 #endif 1754 LINE_BREAK(); 1755 } 1756 LINE_BREAK(); 1757 1758 end: 1759 return; 1760 } 1761 1762 static void 1763 set80211(int s, int type, int val, int len, u_int8_t *data) 1764 { 1765 struct ieee80211req ireq; 1766 1767 (void) memset(&ireq, 0, sizeof(ireq)); 1768 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1769 ireq.i_type = type; 1770 ireq.i_val = val; 1771 ireq.i_len = len; 1772 ireq.i_data = data; 1773 if (ioctl(s, SIOCS80211, &ireq) < 0) 1774 err(1, "SIOCS80211"); 1775 } 1776 1777 static const char * 1778 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 1779 { 1780 int len; 1781 int hexstr; 1782 u_int8_t *p; 1783 1784 len = *lenp; 1785 p = buf; 1786 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 1787 if (hexstr) 1788 val += 2; 1789 for (;;) { 1790 if (*val == '\0') 1791 break; 1792 if (sep != NULL && strchr(sep, *val) != NULL) { 1793 val++; 1794 break; 1795 } 1796 if (hexstr) { 1797 if (!isxdigit((u_char)val[0])) { 1798 warnx("bad hexadecimal digits"); 1799 return NULL; 1800 } 1801 if (!isxdigit((u_char)val[1])) { 1802 warnx("odd count hexadecimal digits"); 1803 return NULL; 1804 } 1805 } 1806 if (p >= buf + len) { 1807 if (hexstr) 1808 warnx("hexadecimal digits too long"); 1809 else 1810 warnx("string too long"); 1811 return NULL; 1812 } 1813 if (hexstr) { 1814 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 1815 *p++ = (tohex((u_char)val[0]) << 4) | 1816 tohex((u_char)val[1]); 1817 #undef tohex 1818 val += 2; 1819 } else 1820 *p++ = *val++; 1821 } 1822 len = p - buf; 1823 /* The string "-" is treated as the empty string. */ 1824 if (!hexstr && len == 1 && buf[0] == '-') 1825 len = 0; 1826 if (len < *lenp) 1827 memset(p, 0, *lenp - len); 1828 *lenp = len; 1829 return val; 1830 } 1831 1832 static void 1833 print_string(const u_int8_t *buf, int len) 1834 { 1835 int i; 1836 int hasspc; 1837 1838 i = 0; 1839 hasspc = 0; 1840 for (; i < len; i++) { 1841 if (!isprint(buf[i]) && buf[i] != '\0') 1842 break; 1843 if (isspace(buf[i])) 1844 hasspc++; 1845 } 1846 if (i == len) { 1847 if (hasspc || len == 0 || buf[0] == '\0') 1848 printf("\"%.*s\"", len, buf); 1849 else 1850 printf("%.*s", len, buf); 1851 } else { 1852 printf("0x"); 1853 for (i = 0; i < len; i++) 1854 printf("%02x", buf[i]); 1855 } 1856 } 1857 1858 static struct cmd ieee80211_cmds[] = { 1859 DEF_CMD_ARG("ssid", set80211ssid), 1860 DEF_CMD_ARG("nwid", set80211ssid), 1861 DEF_CMD_ARG("stationname", set80211stationname), 1862 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 1863 DEF_CMD_ARG("channel", set80211channel), 1864 DEF_CMD_ARG("authmode", set80211authmode), 1865 DEF_CMD_ARG("powersavemode", set80211powersavemode), 1866 DEF_CMD("powersave", 1, set80211powersave), 1867 DEF_CMD("-powersave", 0, set80211powersave), 1868 DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 1869 DEF_CMD_ARG("wepmode", set80211wepmode), 1870 DEF_CMD("wep", 1, set80211wep), 1871 DEF_CMD("-wep", 0, set80211wep), 1872 DEF_CMD_ARG("deftxkey", set80211weptxkey), 1873 DEF_CMD_ARG("weptxkey", set80211weptxkey), 1874 DEF_CMD_ARG("wepkey", set80211wepkey), 1875 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 1876 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 1877 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 1878 DEF_CMD_ARG("protmode", set80211protmode), 1879 DEF_CMD_ARG("txpower", set80211txpower), 1880 DEF_CMD_ARG("roaming", set80211roaming), 1881 DEF_CMD("wme", 1, set80211wme), 1882 DEF_CMD("-wme", 0, set80211wme), 1883 DEF_CMD("hidessid", 1, set80211hidessid), 1884 DEF_CMD("-hidessid", 0, set80211hidessid), 1885 DEF_CMD("apbridge", 1, set80211apbridge), 1886 DEF_CMD("-apbridge", 0, set80211apbridge), 1887 DEF_CMD_ARG("chanlist", set80211chanlist), 1888 DEF_CMD_ARG("bssid", set80211bssid), 1889 DEF_CMD_ARG("ap", set80211bssid), 1890 DEF_CMD("scan", 0, set80211scan), 1891 DEF_CMD_ARG("list", set80211list), 1892 DEF_CMD_ARG2("cwmin", set80211cwmin), 1893 DEF_CMD_ARG2("cwmax", set80211cwmax), 1894 DEF_CMD_ARG2("aifs", set80211aifs), 1895 DEF_CMD_ARG2("txoplimit", set80211txoplimit), 1896 DEF_CMD_ARG("acm", set80211acm), 1897 DEF_CMD_ARG("-acm", set80211noacm), 1898 DEF_CMD_ARG("ack", set80211ackpolicy), 1899 DEF_CMD_ARG("-ack", set80211noackpolicy), 1900 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 1901 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 1902 DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 1903 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 1904 DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 1905 DEF_CMD_ARG("bintval", set80211bintval), 1906 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 1907 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 1908 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 1909 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 1910 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 1911 DEF_CMD_ARG("mac:add", set80211addmac), 1912 DEF_CMD_ARG("mac:del", set80211delmac), 1913 DEF_CMD_ARG("mac:kick", set80211kickmac), 1914 DEF_CMD("pureg", 1, set80211pureg), 1915 DEF_CMD("-pureg", 0, set80211pureg), 1916 DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 1917 }; 1918 static struct afswtch af_ieee80211 = { 1919 .af_name = "af_ieee80211", 1920 .af_af = AF_UNSPEC, 1921 .af_other_status = ieee80211_status, 1922 }; 1923 1924 static __constructor void 1925 ieee80211_ctor(void) 1926 { 1927 #define N(a) (sizeof(a) / sizeof(a[0])) 1928 int i; 1929 1930 for (i = 0; i < N(ieee80211_cmds); i++) 1931 cmd_register(&ieee80211_cmds[i]); 1932 af_register(&af_ieee80211); 1933 #undef N 1934 } 1935