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