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$ 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/route.h> 78 #include <net80211/ieee80211.h> 79 #include <net80211/ieee80211_crypto.h> 80 #include <net80211/ieee80211_ioctl.h> 81 82 #include <ctype.h> 83 #include <err.h> 84 #include <errno.h> 85 #include <fcntl.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <unistd.h> 90 91 #include "ifconfig.h" 92 93 static void set80211(int s, int type, int val, int len, u_int8_t *data); 94 static const char *get_string(const char *val, const char *sep, 95 u_int8_t *buf, int *lenp); 96 static void print_string(const u_int8_t *buf, int len); 97 98 void 99 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 100 { 101 int ssid; 102 int len; 103 u_int8_t data[33]; 104 105 ssid = 0; 106 len = strlen(val); 107 if (len > 2 && isdigit(val[0]) && val[1] == ':') { 108 ssid = atoi(val)-1; 109 val += 2; 110 } 111 112 bzero(data, sizeof(data)); 113 len = sizeof(data); 114 get_string(val, NULL, data, &len); 115 116 set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 117 } 118 119 void 120 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 121 { 122 int len; 123 u_int8_t data[33]; 124 125 bzero(data, sizeof(data)); 126 len = sizeof(data); 127 get_string(val, NULL, data, &len); 128 129 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 130 } 131 132 void 133 set80211channel(const char *val, int d, int s, const struct afswtch *rafp) 134 { 135 if (strcmp(val, "-") == 0) 136 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 137 else 138 set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL); 139 } 140 141 void 142 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 143 { 144 int mode; 145 146 if (strcasecmp(val, "none") == 0) { 147 mode = IEEE80211_AUTH_NONE; 148 } else if (strcasecmp(val, "open") == 0) { 149 mode = IEEE80211_AUTH_OPEN; 150 } else if (strcasecmp(val, "shared") == 0) { 151 mode = IEEE80211_AUTH_SHARED; 152 } else { 153 err(1, "unknown authmode"); 154 } 155 156 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 157 } 158 159 void 160 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 161 { 162 int mode; 163 164 if (strcasecmp(val, "off") == 0) { 165 mode = IEEE80211_POWERSAVE_OFF; 166 } else if (strcasecmp(val, "on") == 0) { 167 mode = IEEE80211_POWERSAVE_ON; 168 } else if (strcasecmp(val, "cam") == 0) { 169 mode = IEEE80211_POWERSAVE_CAM; 170 } else if (strcasecmp(val, "psp") == 0) { 171 mode = IEEE80211_POWERSAVE_PSP; 172 } else if (strcasecmp(val, "psp-cam") == 0) { 173 mode = IEEE80211_POWERSAVE_PSP_CAM; 174 } else { 175 err(1, "unknown powersavemode"); 176 } 177 178 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 179 } 180 181 void 182 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 183 { 184 if (d == 0) 185 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 186 0, NULL); 187 else 188 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 189 0, NULL); 190 } 191 192 void 193 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 194 { 195 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 196 } 197 198 void 199 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 200 { 201 int mode; 202 203 if (strcasecmp(val, "off") == 0) { 204 mode = IEEE80211_WEP_OFF; 205 } else if (strcasecmp(val, "on") == 0) { 206 mode = IEEE80211_WEP_ON; 207 } else if (strcasecmp(val, "mixed") == 0) { 208 mode = IEEE80211_WEP_MIXED; 209 } else { 210 err(1, "unknown wep mode"); 211 } 212 213 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 214 } 215 216 void 217 set80211wep(const char *val, int d, int s, const struct afswtch *rafp) 218 { 219 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 220 } 221 222 void 223 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 224 { 225 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 226 } 227 228 void 229 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 230 { 231 int key = 0; 232 int len; 233 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 234 235 if (isdigit(val[0]) && val[1] == ':') { 236 key = atoi(val)-1; 237 val += 2; 238 } 239 240 bzero(data, sizeof(data)); 241 len = sizeof(data); 242 get_string(val, NULL, data, &len); 243 244 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 245 } 246 247 /* 248 * This function is purly a NetBSD compatability interface. The NetBSD 249 * iterface is too inflexable, but it's there so we'll support it since 250 * it's not all that hard. 251 */ 252 void 253 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 254 { 255 int txkey; 256 int i, len; 257 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 258 259 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 260 261 if (isdigit(val[0]) && val[1] == ':') { 262 txkey = val[0]-'0'-1; 263 val += 2; 264 265 for (i = 0; i < 4; i++) { 266 bzero(data, sizeof(data)); 267 len = sizeof(data); 268 val = get_string(val, ",", data, &len); 269 270 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 271 } 272 } else { 273 bzero(data, sizeof(data)); 274 len = sizeof(data); 275 get_string(val, NULL, data, &len); 276 txkey = 0; 277 278 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 279 280 bzero(data, sizeof(data)); 281 for (i = 1; i < 4; i++) 282 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 283 } 284 285 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 286 } 287 288 void 289 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 290 { 291 set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL); 292 } 293 294 void 295 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 296 { 297 int mode; 298 299 if (strcasecmp(val, "off") == 0) { 300 mode = IEEE80211_PROTMODE_OFF; 301 } else if (strcasecmp(val, "cts") == 0) { 302 mode = IEEE80211_PROTMODE_CTS; 303 } else if (strcasecmp(val, "rtscts") == 0) { 304 mode = IEEE80211_PROTMODE_RTSCTS; 305 } else { 306 err(1, "unknown protection mode"); 307 } 308 309 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 310 } 311 312 void 313 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 314 { 315 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 316 } 317 318 void 319 ieee80211_status (int s, struct rt_addrinfo *info __unused) 320 { 321 int i; 322 int num; 323 struct ieee80211req ireq; 324 u_int8_t data[32]; 325 char spacer; 326 327 (void) memset(&ireq, 0, sizeof(ireq)); 328 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 329 ireq.i_data = &data; 330 331 ireq.i_type = IEEE80211_IOC_SSID; 332 ireq.i_val = -1; 333 if (ioctl(s, SIOCG80211, &ireq) < 0) { 334 /* If we can't get the SSID, the this isn't an 802.11 device. */ 335 return; 336 } 337 printf("\tssid "); 338 print_string(data, ireq.i_len); 339 num = 0; 340 ireq.i_type = IEEE80211_IOC_NUMSSIDS; 341 if (ioctl(s, SIOCG80211, &ireq) >= 0) { 342 num = ireq.i_val; 343 } 344 ireq.i_type = IEEE80211_IOC_SSID; 345 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 346 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 347 printf(" %d:", ireq.i_val + 1); 348 print_string(data, ireq.i_len); 349 } 350 } 351 printf("\n"); 352 353 ireq.i_type = IEEE80211_IOC_STATIONNAME; 354 if (ioctl(s, SIOCG80211, &ireq) != -1) { 355 printf("\tstationname "); 356 print_string(data, ireq.i_len); 357 printf("\n"); 358 } 359 360 ireq.i_type = IEEE80211_IOC_CHANNEL; 361 if (ioctl(s, SIOCG80211, &ireq) < 0) { 362 goto end; 363 } 364 printf("\tchannel %d", ireq.i_val); 365 366 ireq.i_type = IEEE80211_IOC_AUTHMODE; 367 if (ioctl(s, SIOCG80211, &ireq) != -1) { 368 printf(" authmode"); 369 switch (ireq.i_val) { 370 case IEEE80211_AUTH_NONE: 371 printf(" NONE"); 372 break; 373 case IEEE80211_AUTH_OPEN: 374 printf(" OPEN"); 375 break; 376 case IEEE80211_AUTH_SHARED: 377 printf(" SHARED"); 378 break; 379 default: 380 printf(" UNKNOWN"); 381 break; 382 } 383 } 384 385 ireq.i_type = IEEE80211_IOC_POWERSAVE; 386 if (ioctl(s, SIOCG80211, &ireq) != -1 && 387 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 388 printf(" powersavemode"); 389 switch (ireq.i_val) { 390 case IEEE80211_POWERSAVE_OFF: 391 printf(" OFF"); 392 break; 393 case IEEE80211_POWERSAVE_CAM: 394 printf(" CAM"); 395 break; 396 case IEEE80211_POWERSAVE_PSP: 397 printf(" PSP"); 398 break; 399 case IEEE80211_POWERSAVE_PSP_CAM: 400 printf(" PSP-CAM"); 401 break; 402 } 403 404 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 405 if (ioctl(s, SIOCG80211, &ireq) != -1) { 406 if (ireq.i_val) 407 printf(" powersavesleep %d", ireq.i_val); 408 } 409 } 410 411 printf("\n"); 412 413 spacer = '\t'; 414 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 415 if (ioctl(s, SIOCG80211, &ireq) != -1) { 416 printf("%crtsthreshold %d", spacer, ireq.i_val); 417 spacer = ' '; 418 } 419 420 ireq.i_type = IEEE80211_IOC_PROTMODE; 421 if (ioctl(s, SIOCG80211, &ireq) != -1) { 422 printf("%cprotmode", spacer); 423 switch (ireq.i_val) { 424 case IEEE80211_PROTMODE_OFF: 425 printf(" OFF"); 426 break; 427 case IEEE80211_PROTMODE_CTS: 428 printf(" CTS"); 429 break; 430 case IEEE80211_PROTMODE_RTSCTS: 431 printf(" RTSCTS"); 432 break; 433 default: 434 printf(" UNKNOWN"); 435 break; 436 } 437 spacer = ' '; 438 } 439 440 ireq.i_type = IEEE80211_IOC_TXPOWER; 441 if (ioctl(s, SIOCG80211, &ireq) != -1) { 442 printf("%ctxpower %d", spacer, ireq.i_val); 443 spacer = ' '; 444 } 445 446 if (spacer != '\t') 447 printf("\n"); 448 449 ireq.i_type = IEEE80211_IOC_WEP; 450 if (ioctl(s, SIOCG80211, &ireq) != -1 && 451 ireq.i_val != IEEE80211_WEP_NOSUP) { 452 printf("\twepmode"); 453 switch (ireq.i_val) { 454 case IEEE80211_WEP_OFF: 455 printf(" OFF"); 456 break; 457 case IEEE80211_WEP_ON: 458 printf(" ON"); 459 break; 460 case IEEE80211_WEP_MIXED: 461 printf(" MIXED"); 462 break; 463 default: 464 printf(" UNKNOWN"); 465 break; 466 } 467 468 /* 469 * If we get here then we've got WEP support so we need 470 * to print WEP status. 471 */ 472 473 ireq.i_type = IEEE80211_IOC_WEPTXKEY; 474 if (ioctl(s, SIOCG80211, &ireq) < 0) { 475 warn("WEP support, but no tx key!"); 476 goto end; 477 } 478 printf(" weptxkey %d", ireq.i_val+1); 479 480 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 481 if (ioctl(s, SIOCG80211, &ireq) < 0) { 482 warn("WEP support, but no NUMWEPKEYS support!"); 483 goto end; 484 } 485 num = ireq.i_val; 486 487 printf("\n"); 488 489 ireq.i_type = IEEE80211_IOC_WEPKEY; 490 spacer = '\t'; 491 for (i = 0; i < num; i++) { 492 ireq.i_val = i; 493 if (ioctl(s, SIOCG80211, &ireq) < 0) { 494 warn("WEP support, but can get keys!"); 495 goto end; 496 } 497 if (ireq.i_len == 0 || 498 ireq.i_len > IEEE80211_KEYBUF_SIZE) 499 continue; 500 printf("%cwepkey %d:%s", spacer, i+1, 501 ireq.i_len <= 5 ? "40-bit" : 502 ireq.i_len <= 13 ? "104-bit" : "128-bit"); 503 if (spacer == '\t') 504 spacer = ' '; 505 } 506 if (spacer == ' ') 507 printf("\n"); 508 } 509 510 end: 511 return; 512 } 513 514 static void 515 set80211(int s, int type, int val, int len, u_int8_t *data) 516 { 517 struct ieee80211req ireq; 518 519 (void) memset(&ireq, 0, sizeof(ireq)); 520 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 521 ireq.i_type = type; 522 ireq.i_val = val; 523 ireq.i_len = len; 524 ireq.i_data = data; 525 if (ioctl(s, SIOCS80211, &ireq) < 0) 526 err(1, "SIOCS80211"); 527 } 528 529 static const char * 530 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 531 { 532 int len; 533 int hexstr; 534 u_int8_t *p; 535 536 len = *lenp; 537 p = buf; 538 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 539 if (hexstr) 540 val += 2; 541 for (;;) { 542 if (*val == '\0') 543 break; 544 if (sep != NULL && strchr(sep, *val) != NULL) { 545 val++; 546 break; 547 } 548 if (hexstr) { 549 if (!isxdigit((u_char)val[0])) { 550 warnx("bad hexadecimal digits"); 551 return NULL; 552 } 553 if (!isxdigit((u_char)val[1])) { 554 warnx("odd count hexadecimal digits"); 555 return NULL; 556 } 557 } 558 if (p >= buf + len) { 559 if (hexstr) 560 warnx("hexadecimal digits too long"); 561 else 562 warnx("string too long"); 563 return NULL; 564 } 565 if (hexstr) { 566 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 567 *p++ = (tohex((u_char)val[0]) << 4) | 568 tohex((u_char)val[1]); 569 #undef tohex 570 val += 2; 571 } else 572 *p++ = *val++; 573 } 574 len = p - buf; 575 /* The string "-" is treated as the empty string. */ 576 if (!hexstr && len == 1 && buf[0] == '-') 577 len = 0; 578 if (len < *lenp) 579 memset(p, 0, *lenp - len); 580 *lenp = len; 581 return val; 582 } 583 584 static void 585 print_string(const u_int8_t *buf, int len) 586 { 587 int i; 588 int hasspc; 589 590 i = 0; 591 hasspc = 0; 592 for (; i < len; i++) { 593 if (!isprint(buf[i]) && buf[i] != '\0') 594 break; 595 if (isspace(buf[i])) 596 hasspc++; 597 } 598 if (i == len) { 599 if (hasspc || len == 0 || buf[0] == '\0') 600 printf("\"%.*s\"", len, buf); 601 else 602 printf("%.*s", len, buf); 603 } else { 604 printf("0x"); 605 for (i = 0; i < len; i++) 606 printf("%02x", buf[i]); 607 } 608 } 609 610