1 /* 2 * Copyright 2001 The Aerospace Corporation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of The Aerospace Corporation may not be used to endorse or 13 * promote products derived from this software. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.1.2.3 2002/02/07 15:12:37 ambrisko Exp $ 28 * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.8 2005/03/06 05:01:59 dillon Exp $ 29 */ 30 31 /*- 32 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 33 * All rights reserved. 34 * 35 * This code is derived from software contributed to The NetBSD Foundation 36 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 37 * NASA Ames Research Center. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the NetBSD 50 * Foundation, Inc. and its contributors. 51 * 4. Neither the name of The NetBSD Foundation nor the names of its 52 * contributors may be used to endorse or promote products derived 53 * from this software without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 * POSSIBILITY OF SUCH DAMAGE. 66 */ 67 68 #include <sys/param.h> 69 #include <sys/ioctl.h> 70 #include <sys/socket.h> 71 #include <sys/sysctl.h> 72 #include <sys/time.h> 73 74 #include <net/ethernet.h> 75 #include <net/if.h> 76 #include <net/if_dl.h> 77 #include <net/if_types.h> 78 #include <net/route.h> 79 #include <netproto/802_11/ieee80211.h> 80 #include <netproto/802_11/ieee80211_crypto.h> 81 #include <netproto/802_11/ieee80211_ioctl.h> 82 83 #include <ctype.h> 84 #include <err.h> 85 #include <errno.h> 86 #include <fcntl.h> 87 #include <stdio.h> 88 #include <stdlib.h> 89 #include <string.h> 90 #include <unistd.h> 91 92 #include "ifconfig.h" 93 94 static void set80211(int s, int type, int val, int len, u_int8_t *data); 95 static const char *get_string(const char *val, const char *sep, 96 u_int8_t *buf, int *lenp); 97 static void print_string(const u_int8_t *buf, int len); 98 99 void 100 set80211ssid(const char *val, int d __unused, int s, 101 const struct afswtch *rafp __unused) 102 { 103 int ssid; 104 int len; 105 u_int8_t data[33]; 106 107 ssid = 0; 108 len = strlen(val); 109 if (len > 2 && isdigit(val[0]) && val[1] == ':') { 110 ssid = atoi(val)-1; 111 val += 2; 112 } 113 114 bzero(data, sizeof(data)); 115 len = sizeof(data); 116 get_string(val, NULL, data, &len); 117 118 set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 119 } 120 121 void 122 set80211stationname(const char *val, int d __unused, int s, 123 const struct afswtch *rafp __unused) 124 { 125 int len; 126 u_int8_t data[33]; 127 128 bzero(data, sizeof(data)); 129 len = sizeof(data); 130 get_string(val, NULL, data, &len); 131 132 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 133 } 134 135 void 136 set80211channel(const char *val, int d __unused, int s, 137 const struct afswtch *rafp __unused) 138 { 139 if (strcmp(val, "-") == 0) 140 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 141 else 142 set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL); 143 } 144 145 void 146 set80211authmode(const char *val, int d __unused, int s, 147 const struct afswtch *rafp __unused) 148 { 149 int mode; 150 151 if (strcasecmp(val, "none") == 0) { 152 mode = IEEE80211_AUTH_NONE; 153 } else if (strcasecmp(val, "open") == 0) { 154 mode = IEEE80211_AUTH_OPEN; 155 } else if (strcasecmp(val, "shared") == 0) { 156 mode = IEEE80211_AUTH_SHARED; 157 } else { 158 err(1, "unknown authmode"); 159 } 160 161 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 162 } 163 164 void 165 set80211powersavemode(const char *val, int d __unused, int s, 166 const struct afswtch *rafp __unused) 167 { 168 int mode; 169 170 if (strcasecmp(val, "off") == 0) { 171 mode = IEEE80211_POWERSAVE_OFF; 172 } else if (strcasecmp(val, "on") == 0) { 173 mode = IEEE80211_POWERSAVE_ON; 174 } else if (strcasecmp(val, "cam") == 0) { 175 mode = IEEE80211_POWERSAVE_CAM; 176 } else if (strcasecmp(val, "psp") == 0) { 177 mode = IEEE80211_POWERSAVE_PSP; 178 } else if (strcasecmp(val, "psp-cam") == 0) { 179 mode = IEEE80211_POWERSAVE_PSP_CAM; 180 } else { 181 err(1, "unknown powersavemode"); 182 } 183 184 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 185 } 186 187 void 188 set80211powersave(const char *val __unused, int d, int s, 189 const struct afswtch *rafp __unused) 190 { 191 if (d == 0) 192 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 193 0, NULL); 194 else 195 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 196 0, NULL); 197 } 198 199 void 200 set80211powersavesleep(const char *val, int d __unused, int s, 201 const struct afswtch *rafp __unused) 202 { 203 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 204 } 205 206 void 207 set80211wepmode(const char *val, int d __unused, int s, 208 const struct afswtch *rafp __unused) 209 { 210 int mode; 211 212 if (strcasecmp(val, "off") == 0) { 213 mode = IEEE80211_WEP_OFF; 214 } else if (strcasecmp(val, "on") == 0) { 215 mode = IEEE80211_WEP_ON; 216 } else if (strcasecmp(val, "mixed") == 0) { 217 mode = IEEE80211_WEP_MIXED; 218 } else { 219 err(1, "unknown wep mode"); 220 } 221 222 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 223 } 224 225 void 226 set80211wep(const char *val __unused, int d, int s, 227 const struct afswtch *rafp __unused) 228 { 229 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 230 } 231 232 void 233 set80211weptxkey(const char *val, int d __unused, int s, 234 const struct afswtch *rafp __unused) 235 { 236 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 237 } 238 239 void 240 set80211wepkey(const char *val, int d __unused, int s, 241 const struct afswtch *rafp __unused) 242 { 243 int key = 0; 244 int len; 245 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 246 247 if (isdigit(val[0]) && val[1] == ':') { 248 key = atoi(val)-1; 249 val += 2; 250 } 251 252 bzero(data, sizeof(data)); 253 len = sizeof(data); 254 get_string(val, NULL, data, &len); 255 256 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 257 } 258 259 /* 260 * This function is purly a NetBSD compatability interface. The NetBSD 261 * iterface is too inflexable, but it's there so we'll support it since 262 * it's not all that hard. 263 */ 264 void 265 set80211nwkey(const char *val, int d __unused, int s, 266 const struct afswtch *rafp __unused) 267 { 268 int txkey; 269 int i, len; 270 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 271 272 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 273 274 if (isdigit(val[0]) && val[1] == ':') { 275 txkey = val[0]-'0'-1; 276 val += 2; 277 278 for (i = 0; i < 4; i++) { 279 bzero(data, sizeof(data)); 280 len = sizeof(data); 281 val = get_string(val, ",", data, &len); 282 283 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 284 } 285 } else { 286 bzero(data, sizeof(data)); 287 len = sizeof(data); 288 get_string(val, NULL, data, &len); 289 txkey = 0; 290 291 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 292 293 bzero(data, sizeof(data)); 294 for (i = 1; i < 4; i++) 295 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 296 } 297 298 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 299 } 300 301 void 302 set80211rtsthreshold(const char *val, int d __unused, int s, 303 const struct afswtch *rafp __unused) 304 { 305 set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL); 306 } 307 308 void 309 set80211protmode(const char *val, int d __unused, int s, 310 const struct afswtch *rafp __unused) 311 { 312 int mode; 313 314 if (strcasecmp(val, "off") == 0) { 315 mode = IEEE80211_PROTMODE_OFF; 316 } else if (strcasecmp(val, "cts") == 0) { 317 mode = IEEE80211_PROTMODE_CTS; 318 } else if (strcasecmp(val, "rtscts") == 0) { 319 mode = IEEE80211_PROTMODE_RTSCTS; 320 } else { 321 err(1, "unknown protection mode"); 322 } 323 324 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 325 } 326 327 void 328 set80211txpower(const char *val, int d __unused, int s, 329 const struct afswtch *rafp __unused) 330 { 331 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 332 } 333 334 void 335 ieee80211_status (int s, struct rt_addrinfo *info __unused) 336 { 337 int i; 338 int num; 339 struct ieee80211req ireq; 340 u_int8_t data[32]; 341 char spacer; 342 343 (void) memset(&ireq, 0, sizeof(ireq)); 344 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 345 ireq.i_data = &data; 346 347 ireq.i_type = IEEE80211_IOC_SSID; 348 ireq.i_val = -1; 349 if (ioctl(s, SIOCG80211, &ireq) < 0) { 350 /* If we can't get the SSID, the this isn't an 802.11 device. */ 351 return; 352 } 353 printf("\tssid "); 354 print_string(data, ireq.i_len); 355 num = 0; 356 ireq.i_type = IEEE80211_IOC_NUMSSIDS; 357 if (ioctl(s, SIOCG80211, &ireq) >= 0) { 358 num = ireq.i_val; 359 } 360 ireq.i_type = IEEE80211_IOC_SSID; 361 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 362 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 363 printf(" %d:", ireq.i_val + 1); 364 print_string(data, ireq.i_len); 365 } 366 } 367 printf("\n"); 368 369 ireq.i_type = IEEE80211_IOC_STATIONNAME; 370 if (ioctl(s, SIOCG80211, &ireq) != -1) { 371 printf("\tstationname "); 372 print_string(data, ireq.i_len); 373 printf("\n"); 374 } 375 376 ireq.i_type = IEEE80211_IOC_CHANNEL; 377 if (ioctl(s, SIOCG80211, &ireq) < 0) { 378 goto end; 379 } 380 printf("\tchannel %d", ireq.i_val); 381 382 ireq.i_type = IEEE80211_IOC_AUTHMODE; 383 if (ioctl(s, SIOCG80211, &ireq) != -1) { 384 printf(" authmode"); 385 switch (ireq.i_val) { 386 case IEEE80211_AUTH_NONE: 387 printf(" NONE"); 388 break; 389 case IEEE80211_AUTH_OPEN: 390 printf(" OPEN"); 391 break; 392 case IEEE80211_AUTH_SHARED: 393 printf(" SHARED"); 394 break; 395 default: 396 printf(" UNKNOWN"); 397 break; 398 } 399 } 400 401 ireq.i_type = IEEE80211_IOC_POWERSAVE; 402 if (ioctl(s, SIOCG80211, &ireq) != -1 && 403 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 404 printf(" powersavemode"); 405 switch (ireq.i_val) { 406 case IEEE80211_POWERSAVE_OFF: 407 printf(" OFF"); 408 break; 409 case IEEE80211_POWERSAVE_CAM: 410 printf(" CAM"); 411 break; 412 case IEEE80211_POWERSAVE_PSP: 413 printf(" PSP"); 414 break; 415 case IEEE80211_POWERSAVE_PSP_CAM: 416 printf(" PSP-CAM"); 417 break; 418 } 419 420 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 421 if (ioctl(s, SIOCG80211, &ireq) != -1) { 422 if (ireq.i_val) 423 printf(" powersavesleep %d", ireq.i_val); 424 } 425 } 426 427 printf("\n"); 428 429 spacer = '\t'; 430 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 431 if (ioctl(s, SIOCG80211, &ireq) != -1) { 432 printf("%crtsthreshold %d", spacer, ireq.i_val); 433 spacer = ' '; 434 } 435 436 ireq.i_type = IEEE80211_IOC_PROTMODE; 437 if (ioctl(s, SIOCG80211, &ireq) != -1) { 438 printf("%cprotmode", spacer); 439 switch (ireq.i_val) { 440 case IEEE80211_PROTMODE_OFF: 441 printf(" OFF"); 442 break; 443 case IEEE80211_PROTMODE_CTS: 444 printf(" CTS"); 445 break; 446 case IEEE80211_PROTMODE_RTSCTS: 447 printf(" RTSCTS"); 448 break; 449 default: 450 printf(" UNKNOWN"); 451 break; 452 } 453 spacer = ' '; 454 } 455 456 ireq.i_type = IEEE80211_IOC_TXPOWER; 457 if (ioctl(s, SIOCG80211, &ireq) != -1) { 458 printf("%ctxpower %d", spacer, ireq.i_val); 459 spacer = ' '; 460 } 461 462 if (spacer != '\t') 463 printf("\n"); 464 465 ireq.i_type = IEEE80211_IOC_WEP; 466 if (ioctl(s, SIOCG80211, &ireq) != -1 && 467 ireq.i_val != IEEE80211_WEP_NOSUP) { 468 printf("\twepmode"); 469 switch (ireq.i_val) { 470 case IEEE80211_WEP_OFF: 471 printf(" OFF"); 472 break; 473 case IEEE80211_WEP_ON: 474 printf(" ON"); 475 break; 476 case IEEE80211_WEP_MIXED: 477 printf(" MIXED"); 478 break; 479 default: 480 printf(" UNKNOWN"); 481 break; 482 } 483 484 /* 485 * If we get here then we've got WEP support so we need 486 * to print WEP status. 487 */ 488 489 ireq.i_type = IEEE80211_IOC_WEPTXKEY; 490 if (ioctl(s, SIOCG80211, &ireq) < 0) { 491 warn("WEP support, but no tx key!"); 492 goto end; 493 } 494 printf(" weptxkey %d", ireq.i_val+1); 495 496 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 497 if (ioctl(s, SIOCG80211, &ireq) < 0) { 498 warn("WEP support, but no NUMWEPKEYS support!"); 499 goto end; 500 } 501 num = ireq.i_val; 502 503 printf("\n"); 504 505 ireq.i_type = IEEE80211_IOC_WEPKEY; 506 spacer = '\t'; 507 for (i = 0; i < num; i++) { 508 ireq.i_val = i; 509 if (ioctl(s, SIOCG80211, &ireq) < 0) { 510 warn("WEP support, but can get keys!"); 511 goto end; 512 } 513 if (ireq.i_len == 0 || 514 ireq.i_len > IEEE80211_KEYBUF_SIZE) 515 continue; 516 printf("%cwepkey %d:%s", spacer, i+1, 517 ireq.i_len <= 5 ? "40-bit" : 518 ireq.i_len <= 13 ? "104-bit" : "128-bit"); 519 if (spacer == '\t') 520 spacer = ' '; 521 } 522 if (spacer == ' ') 523 printf("\n"); 524 } 525 526 end: 527 return; 528 } 529 530 static void 531 set80211(int s, int type, int val, int len, u_int8_t *data) 532 { 533 struct ieee80211req ireq; 534 535 (void) memset(&ireq, 0, sizeof(ireq)); 536 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 537 ireq.i_type = type; 538 ireq.i_val = val; 539 ireq.i_len = len; 540 ireq.i_data = data; 541 if (ioctl(s, SIOCS80211, &ireq) < 0) 542 err(1, "SIOCS80211"); 543 } 544 545 static const char * 546 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 547 { 548 int len; 549 int hexstr; 550 u_int8_t *p; 551 552 len = *lenp; 553 p = buf; 554 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 555 if (hexstr) 556 val += 2; 557 for (;;) { 558 if (*val == '\0') 559 break; 560 if (sep != NULL && strchr(sep, *val) != NULL) { 561 val++; 562 break; 563 } 564 if (hexstr) { 565 if (!isxdigit((u_char)val[0])) { 566 warnx("bad hexadecimal digits"); 567 return NULL; 568 } 569 if (!isxdigit((u_char)val[1])) { 570 warnx("odd count hexadecimal digits"); 571 return NULL; 572 } 573 } 574 if (p >= buf + len) { 575 if (hexstr) 576 warnx("hexadecimal digits too long"); 577 else 578 warnx("string too long"); 579 return NULL; 580 } 581 if (hexstr) { 582 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 583 *p++ = (tohex((u_char)val[0]) << 4) | 584 tohex((u_char)val[1]); 585 #undef tohex 586 val += 2; 587 } else 588 *p++ = *val++; 589 } 590 len = p - buf; 591 /* The string "-" is treated as the empty string. */ 592 if (!hexstr && len == 1 && buf[0] == '-') 593 len = 0; 594 if (len < *lenp) 595 memset(p, 0, *lenp - len); 596 *lenp = len; 597 return val; 598 } 599 600 static void 601 print_string(const u_int8_t *buf, int len) 602 { 603 int i; 604 int hasspc; 605 606 i = 0; 607 hasspc = 0; 608 for (; i < len; i++) { 609 if (!isprint(buf[i]) && buf[i] != '\0') 610 break; 611 if (isspace(buf[i])) 612 hasspc++; 613 } 614 if (i == len) { 615 if (hasspc || len == 0 || buf[0] == '\0') 616 printf("\"%.*s\"", len, buf); 617 else 618 printf("%.*s", len, buf); 619 } else { 620 printf("0x"); 621 for (i = 0; i < len; i++) 622 printf("%02x", buf[i]); 623 } 624 } 625 626