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