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