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