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