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