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