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