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