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