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