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