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.6 2004/12/18 21:43:38 swildner 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 <netproto/802_11/ieee80211.h> 78 #include <netproto/802_11/ieee80211_ioctl.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 91 static void set80211(int s, int type, int val, int len, u_int8_t *data); 92 static const char *get_string(const char *val, const char *sep, 93 u_int8_t *buf, int *lenp); 94 static void print_string(const u_int8_t *buf, int len); 95 96 void 97 set80211ssid(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 117 void 118 set80211stationname(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 130 void 131 set80211channel(const char *val, int d, int s, const struct afswtch *rafp) 132 { 133 set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL); 134 } 135 136 void 137 set80211authmode(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 154 void 155 set80211powersavemode(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 176 void 177 set80211powersave(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 187 void 188 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 189 { 190 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 191 } 192 193 void 194 set80211wepmode(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 211 void 212 set80211wep(const char *val, int d, int s, const struct afswtch *rafp) 213 { 214 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 215 } 216 217 void 218 set80211weptxkey(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 223 void 224 set80211wepkey(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 compatibility 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 */ 247 void 248 set80211nwkey(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 283 void 284 ieee80211_status (int s, struct rt_addrinfo *info __unused) 285 { 286 int i; 287 int num; 288 struct ieee80211req ireq; 289 u_int8_t data[32]; 290 char spacer; 291 292 memset(&ireq, 0, sizeof(ireq)); 293 strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 294 ireq.i_data = &data; 295 296 ireq.i_type = IEEE80211_IOC_SSID; 297 ireq.i_val = -1; 298 if (ioctl(s, SIOCG80211, &ireq) < 0) { 299 /* If we can't get the SSID, the this isn't an 802.11 device. */ 300 return; 301 } 302 printf("\tssid "); 303 print_string(data, ireq.i_len); 304 num = 0; 305 ireq.i_type = IEEE80211_IOC_NUMSSIDS; 306 if (ioctl(s, SIOCG80211, &ireq) >= 0) { 307 num = ireq.i_val; 308 } 309 ireq.i_type = IEEE80211_IOC_SSID; 310 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 311 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 312 printf(" %d:", ireq.i_val + 1); 313 print_string(data, ireq.i_len); 314 } 315 } 316 printf("\n"); 317 318 ireq.i_type = IEEE80211_IOC_STATIONNAME; 319 if (ioctl(s, SIOCG80211, &ireq) != -1) { 320 printf("\tstationname "); 321 print_string(data, ireq.i_len); 322 printf("\n"); 323 } 324 325 ireq.i_type = IEEE80211_IOC_CHANNEL; 326 if (ioctl(s, SIOCG80211, &ireq) < 0) { 327 goto end; 328 } 329 printf("\tchannel %d", ireq.i_val); 330 331 ireq.i_type = IEEE80211_IOC_AUTHMODE; 332 if (ioctl(s, SIOCG80211, &ireq) != -1) { 333 printf(" authmode"); 334 switch (ireq.i_val) { 335 case IEEE80211_AUTH_NONE: 336 printf(" NONE"); 337 break; 338 case IEEE80211_AUTH_OPEN: 339 printf(" OPEN"); 340 break; 341 case IEEE80211_AUTH_SHARED: 342 printf(" SHARED"); 343 break; 344 default: 345 printf(" UNKNOWN"); 346 break; 347 } 348 } 349 350 ireq.i_type = IEEE80211_IOC_POWERSAVE; 351 if (ioctl(s, SIOCG80211, &ireq) != -1 && 352 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 353 printf(" powersavemode"); 354 switch (ireq.i_val) { 355 case IEEE80211_POWERSAVE_OFF: 356 printf(" OFF"); 357 break; 358 case IEEE80211_POWERSAVE_CAM: 359 printf(" CAM"); 360 break; 361 case IEEE80211_POWERSAVE_PSP: 362 printf(" PSP"); 363 break; 364 case IEEE80211_POWERSAVE_PSP_CAM: 365 printf(" PSP-CAM"); 366 break; 367 } 368 369 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 370 if (ioctl(s, SIOCG80211, &ireq) != -1) { 371 if(ireq.i_val) 372 printf(" powersavesleep %d", ireq.i_val); 373 } 374 } 375 376 printf("\n"); 377 378 ireq.i_type = IEEE80211_IOC_WEP; 379 if (ioctl(s, SIOCG80211, &ireq) != -1 && 380 ireq.i_val != IEEE80211_WEP_NOSUP) { 381 printf("\twepmode"); 382 switch (ireq.i_val) { 383 case IEEE80211_WEP_OFF: 384 printf(" OFF"); 385 break; 386 case IEEE80211_WEP_ON: 387 printf(" ON"); 388 break; 389 case IEEE80211_WEP_MIXED: 390 printf(" MIXED"); 391 break; 392 default: 393 printf(" UNKNOWN"); 394 break; 395 } 396 397 /* 398 * If we get here then we've got WEP support so we need 399 * to print WEP status. 400 */ 401 402 ireq.i_type = IEEE80211_IOC_WEPTXKEY; 403 if (ioctl(s, SIOCG80211, &ireq) < 0) { 404 warn("WEP support, but no tx key!"); 405 goto end; 406 } 407 printf(" weptxkey %d", ireq.i_val+1); 408 409 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 410 if (ioctl(s, SIOCG80211, &ireq) < 0) { 411 warn("WEP support, but no NUMWEPKEYS support!"); 412 goto end; 413 } 414 num = ireq.i_val; 415 416 printf("\n"); 417 418 ireq.i_type = IEEE80211_IOC_WEPKEY; 419 spacer = '\t'; 420 for(i = 0; i < num; i++) { 421 ireq.i_val = i; 422 if (ioctl(s, SIOCG80211, &ireq) < 0) { 423 warn("WEP support, but can get keys!"); 424 goto end; 425 } 426 if(ireq.i_len == 0 || ireq.i_len > 13) 427 continue; 428 printf("%cwepkey %d:%s", spacer, i+1, 429 ireq.i_len <= 5 ? "64-bit" : "128-bit"); 430 if(spacer == '\t') 431 spacer = ' '; 432 } 433 if (spacer == ' ') 434 printf("\n"); 435 } 436 437 end: 438 return; 439 } 440 441 static void 442 set80211(int s, int type, int val, int len, u_int8_t *data) 443 { 444 struct ieee80211req ireq; 445 446 memset(&ireq, 0, sizeof(ireq)); 447 strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 448 ireq.i_type = type; 449 ireq.i_val = val; 450 ireq.i_len = len; 451 ireq.i_data = data; 452 if(ioctl(s, SIOCS80211, &ireq) < 0) 453 err(1, "SIOCS80211"); 454 } 455 456 static const char * 457 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 458 { 459 int len; 460 int hexstr; 461 u_int8_t *p; 462 463 len = *lenp; 464 p = buf; 465 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 466 if (hexstr) 467 val += 2; 468 for (;;) { 469 if (*val == '\0') 470 break; 471 if (sep != NULL && strchr(sep, *val) != NULL) { 472 val++; 473 break; 474 } 475 if (hexstr) { 476 if (!isxdigit((u_char)val[0]) || 477 !isxdigit((u_char)val[1])) { 478 warnx("bad hexadecimal digits"); 479 return NULL; 480 } 481 } 482 if (p > buf + len) { 483 if (hexstr) 484 warnx("hexadecimal digits too long"); 485 else 486 warnx("strings too long"); 487 return NULL; 488 } 489 if (hexstr) { 490 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 491 *p++ = (tohex((u_char)val[0]) << 4) | 492 tohex((u_char)val[1]); 493 #undef tohex 494 val += 2; 495 } else 496 *p++ = *val++; 497 } 498 len = p - buf; 499 /* The string "-" is treated as the empty string. */ 500 if (!hexstr && len == 1 && buf[0] == '-') 501 len = 0; 502 if (len < *lenp) 503 memset(p, 0, *lenp - len); 504 *lenp = len; 505 return val; 506 } 507 508 static void 509 print_string(const u_int8_t *buf, int len) 510 { 511 int i; 512 int hasspc; 513 514 i = 0; 515 hasspc = 0; 516 for(; i < len; i++) { 517 if (!isprint(buf[i]) && buf[i] != '\0') 518 break; 519 if (isspace(buf[i])) 520 hasspc++; 521 } 522 if (i == len) { 523 if (hasspc || len == 0 || buf[0] == '\0') 524 printf("\"%.*s\"", len, buf); 525 else 526 printf("%.*s", len, buf); 527 } else { 528 printf("0x"); 529 for (i = 0; i < len; i++) 530 printf("%02x", buf[i]); 531 } 532 } 533 534