1 /* $NetBSD: wiconfig.c,v 1.25 2002/04/09 02:56:17 thorpej Exp $ */ 2 /* 3 * Copyright (c) 1997, 1998, 1999 4 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Bill Paul. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * From: Id: wicontrol.c,v 1.6 1999/05/22 16:12:49 wpaul Exp $ 34 */ 35 36 #include <sys/types.h> 37 #include <sys/cdefs.h> 38 #include <sys/param.h> 39 #include <sys/socket.h> 40 #include <sys/ioctl.h> 41 #include <sys/socket.h> 42 43 #include <net/if.h> 44 #ifdef __FreeBSD__ 45 #include <net/if_var.h> 46 #include <net/ethernet.h> 47 48 #include <machine/if_wavelan_ieee.h> 49 #else 50 #include <netinet/in.h> 51 #include <netinet/if_ether.h> 52 #ifdef __NetBSD__ 53 #include <net/if_ieee80211.h> 54 #include <dev/ic/wi_ieee.h> 55 #else 56 #include <dev/pcmcia/if_wavelan_ieee.h> 57 #endif 58 #endif 59 60 #include <stdio.h> 61 #include <string.h> 62 #include <ctype.h> 63 #include <stdlib.h> 64 #include <unistd.h> 65 #include <errno.h> 66 #include <err.h> 67 68 #if !defined(lint) 69 __COPYRIGHT( 70 "@(#) Copyright (c) 1997, 1998, 1999\ 71 Bill Paul. All rights reserved."); 72 __RCSID("$NetBSD: wiconfig.c,v 1.25 2002/04/09 02:56:17 thorpej Exp $"); 73 #endif 74 75 struct wi_table { 76 int wi_type; 77 int wi_code; 78 #define WI_NONE 0x00 79 #define WI_STRING 0x01 80 #define WI_BOOL 0x02 81 #define WI_WORDS 0x03 82 #define WI_HEXBYTES 0x04 83 #define WI_KEYSTRUCT 0x05 84 #define WI_BITS 0x06 85 char *wi_label; /* label used to print info */ 86 int wi_opt; /* option character to set this */ 87 char *wi_desc; 88 char *wi_optval; 89 }; 90 91 /* already define in wireg.h XXX */ 92 #define WI_APRATE_0 0x00 /* NONE */ 93 #define WI_APRATE_1 0x0A /* 1 Mbps */ 94 #define WI_APRATE_2 0x14 /* 2 Mbps */ 95 #define WI_APRATE_5 0x37 /* 5.5 Mbps */ 96 #define WI_APRATE_11 0x6E /* 11 Mbps */ 97 98 #ifdef WI_RID_SCAN_APS 99 static void wi_apscan __P((char *)); 100 static int get_if_flags __P((int, const char *)); 101 static int set_if_flags __P((int, const char *, int)); 102 #endif 103 static void wi_getval __P((char *, struct wi_req *)); 104 static void wi_setval __P((char *, struct wi_req *)); 105 static void wi_printstr __P((struct wi_req *)); 106 static void wi_setstr __P((char *, int, char *)); 107 static void wi_setbytes __P((char *, int, char *, int)); 108 static void wi_setword __P((char *, int, int)); 109 static void wi_sethex __P((char *, int, char *)); 110 static void wi_printwords __P((struct wi_req *)); 111 static void wi_printbool __P((struct wi_req *)); 112 static void wi_printhex __P((struct wi_req *)); 113 static void wi_printbits __P((struct wi_req *)); 114 static void wi_dumpinfo __P((char *)); 115 static void wi_setkeys __P((char *, char *, int)); 116 static void wi_printkeys __P((struct wi_req *)); 117 static void wi_dumpstats __P((char *)); 118 static void usage __P((void)); 119 static struct wi_table * 120 wi_optlookup __P((struct wi_table *, int)); 121 static int wi_hex2int(char c); 122 static void wi_str2key __P((char *, struct wi_key *)); 123 int main __P((int argc, char **argv)); 124 125 #ifdef WI_RID_SCAN_APS 126 static int get_if_flags(s, name) 127 int s; 128 const char *name; 129 { 130 struct ifreq ifreq; 131 int flags; 132 133 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 134 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) == -1) 135 err(1, "SIOCGIFFLAGS"); 136 flags = ifreq.ifr_flags; 137 138 return flags; 139 } 140 141 static int set_if_flags(s, name, flags) 142 int s; 143 const char *name; 144 int flags; 145 { 146 struct ifreq ifreq; 147 148 ifreq.ifr_flags = flags; 149 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 150 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) == -1) 151 err(1, "SIOCSIFFLAGS"); 152 153 return 0; 154 } 155 156 static void wi_apscan(iface) 157 char *iface; 158 { 159 struct wi_req wreq; 160 struct ifreq ifr; 161 int s; 162 int naps, rate; 163 int retries = 10; 164 int flags; 165 struct wi_apinfo *w; 166 int i, j; 167 168 if (iface == NULL) 169 errx(1, "must specify interface name"); 170 171 s = socket(AF_INET, SOCK_DGRAM, 0); 172 if (s == -1) 173 err(1, "socket"); 174 flags = get_if_flags(s, iface); 175 if ((flags & IFF_UP) == 0) 176 flags = set_if_flags(s, iface, flags | IFF_UP); 177 178 memset((char *)&wreq, 0, sizeof(wreq)); 179 180 wreq.wi_type = WI_RID_SCAN_APS; 181 wreq.wi_len = 4; 182 /* note chan. 1 is the least significant bit */ 183 wreq.wi_val[0] = 0x3fff; /* 1 bit per channel, 1-14 */ 184 wreq.wi_val[1] = 0xf; /* tx rate */ 185 186 /* write the request */ 187 wi_setval(iface, &wreq); 188 189 /* now poll for a result */ 190 memset((char *)&wreq, 0, sizeof(wreq)); 191 192 wreq.wi_type = WI_RID_READ_APS; 193 wreq.wi_len = WI_MAX_DATALEN; 194 195 /* we have to do this ourself as opposed to 196 * using getval, because we cannot bail if 197 * the ioctl fails 198 */ 199 memset((char *)&ifr, 0, sizeof(ifr)); 200 strcpy(ifr.ifr_name, iface); 201 ifr.ifr_data = (caddr_t)&wreq; 202 203 printf("scanning ..."); 204 fflush(stdout); 205 while (ioctl(s, SIOCGWAVELAN, &ifr) == -1) { 206 retries--; 207 if (retries >= 0) { 208 printf("."); fflush(stdout); 209 sleep(1); 210 } else 211 break; 212 errno = 0; 213 } 214 215 if (errno) { 216 set_if_flags(s, iface, flags); 217 close(s); 218 err(1, "ioctl"); 219 } 220 221 naps = *(int *)wreq.wi_val; 222 223 if (naps > 0) 224 printf("\nAP Information\n"); 225 else 226 printf("\nNo APs available\n"); 227 228 w = (struct wi_apinfo *)(((char *)&wreq.wi_val) + sizeof(int)); 229 for ( i = 0; i < naps; i++, w++) { 230 printf("ap[%d]:\n", i); 231 if (w->scanreason) { 232 static char *scanm[] = { 233 "Host initiated", 234 "Firmware initiated", 235 "Inquiry request from host" 236 }; 237 printf("\tScanReason:\t\t\t[ %s ]\n", 238 scanm[w->scanreason - 1]); 239 } 240 printf("\tnetname (SSID):\t\t\t[ "); 241 for (j = 0; j < w->namelen; j++) { 242 printf("%c", w->name[j]); 243 } 244 printf(" ]\n"); 245 printf("\tBSSID:\t\t\t\t[ %02x:%02x:%02x:%02x:%02x:%02x ]\n", 246 w->bssid[0]&0xff, w->bssid[1]&0xff, 247 w->bssid[2]&0xff, w->bssid[3]&0xff, 248 w->bssid[4]&0xff, w->bssid[5]&0xff); 249 printf("\tChannel:\t\t\t[ %d ]\n", w->channel); 250 printf("\tQuality/Signal/Noise [signal]:\t[ %d / %d / %d ]\n" 251 "\t [dBm]:\t[ %d / %d / %d ]\n", 252 w->quality, w->signal, w->noise, 253 w->quality, w->signal - 149, w->noise - 149); 254 printf("\tBSS Beacon Interval [msec]:\t[ %d ]\n", w->interval); 255 printf("\tCapinfo:\t\t\t[ "); 256 if (w->capinfo & IEEE80211_CAPINFO_ESS) 257 printf("ESS "); 258 if (w->capinfo & IEEE80211_CAPINFO_PRIVACY) 259 printf("WEP "); 260 printf("]\n"); 261 262 switch (w->rate) { 263 case WI_APRATE_1: 264 rate = 1; 265 break; 266 case WI_APRATE_2: 267 rate = 2; 268 break; 269 case WI_APRATE_5: 270 rate = 5.5; 271 break; 272 case WI_APRATE_11: 273 rate = 11; 274 break; 275 case WI_APRATE_0: 276 default: 277 rate = 0; 278 break; 279 } 280 if (rate) printf("\tDataRate [Mbps]:\t\t[ %d ]\n", rate); 281 } 282 283 set_if_flags(s, iface, flags); 284 close(s); 285 } 286 #endif 287 288 static void wi_getval(iface, wreq) 289 char *iface; 290 struct wi_req *wreq; 291 { 292 struct ifreq ifr; 293 int s; 294 295 bzero((char *)&ifr, sizeof(ifr)); 296 297 strcpy(ifr.ifr_name, iface); 298 ifr.ifr_data = (caddr_t)wreq; 299 300 s = socket(AF_INET, SOCK_DGRAM, 0); 301 302 if (s == -1) 303 err(1, "socket"); 304 305 if (ioctl(s, SIOCGWAVELAN, &ifr) == -1) 306 err(1, "SIOCGWAVELAN"); 307 308 close(s); 309 310 return; 311 } 312 313 static void wi_setval(iface, wreq) 314 char *iface; 315 struct wi_req *wreq; 316 { 317 struct ifreq ifr; 318 int s; 319 320 bzero((char *)&ifr, sizeof(ifr)); 321 322 strcpy(ifr.ifr_name, iface); 323 ifr.ifr_data = (caddr_t)wreq; 324 325 s = socket(AF_INET, SOCK_DGRAM, 0); 326 327 if (s == -1) 328 err(1, "socket"); 329 330 if (ioctl(s, SIOCSWAVELAN, &ifr) == -1) 331 err(1, "SIOCSWAVELAN"); 332 333 close(s); 334 335 return; 336 } 337 338 void wi_printstr(wreq) 339 struct wi_req *wreq; 340 { 341 char *ptr; 342 int i; 343 344 if (wreq->wi_type == WI_RID_SERIALNO) { 345 ptr = (char *)&wreq->wi_val; 346 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) { 347 if (ptr[i] == '\0') 348 ptr[i] = ' '; 349 } 350 } else { 351 int len = le16toh(wreq->wi_val[0]); 352 353 ptr = (char *)&wreq->wi_val[1]; 354 for (i = 0; i < len; i++) { 355 if (ptr[i] == '\0') 356 ptr[i] = ' '; 357 } 358 } 359 360 ptr[i] = '\0'; 361 printf("[ %s ]", ptr); 362 363 return; 364 } 365 366 void wi_setstr(iface, code, str) 367 char *iface; 368 int code; 369 char *str; 370 { 371 struct wi_req wreq; 372 373 bzero((char *)&wreq, sizeof(wreq)); 374 375 if (strlen(str) > 30) 376 errx(1, "string too long"); 377 378 wreq.wi_type = code; 379 wreq.wi_len = 18; 380 wreq.wi_val[0] = htole16(strlen(str)); 381 bcopy(str, (char *)&wreq.wi_val[1], strlen(str)); 382 383 wi_setval(iface, &wreq); 384 385 return; 386 } 387 388 void wi_setbytes(iface, code, bytes, len) 389 char *iface; 390 int code; 391 char *bytes; 392 int len; 393 { 394 struct wi_req wreq; 395 396 bzero((char *)&wreq, sizeof(wreq)); 397 398 wreq.wi_type = code; 399 wreq.wi_len = (len / 2) + 1; 400 bcopy(bytes, (char *)&wreq.wi_val[0], len); 401 402 wi_setval(iface, &wreq); 403 404 return; 405 } 406 407 void wi_setword(iface, code, word) 408 char *iface; 409 int code; 410 int word; 411 { 412 struct wi_req wreq; 413 414 bzero((char *)&wreq, sizeof(wreq)); 415 416 wreq.wi_type = code; 417 wreq.wi_len = 2; 418 wreq.wi_val[0] = htole16(word); 419 420 wi_setval(iface, &wreq); 421 422 return; 423 } 424 425 void wi_sethex(iface, code, str) 426 char *iface; 427 int code; 428 char *str; 429 { 430 struct ether_addr *addr; 431 432 addr = ether_aton(str); 433 if (addr == NULL) 434 errx(1, "badly formatted address"); 435 436 wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN); 437 438 return; 439 } 440 441 static int 442 wi_hex2int(char c) 443 { 444 if (c >= '0' && c <= '9') 445 return (c - '0'); 446 if (c >= 'A' && c <= 'F') 447 return (c - 'A' + 10); 448 if (c >= 'a' && c <= 'f') 449 return (c - 'a' + 10); 450 451 return (0); 452 } 453 454 static void wi_str2key(s, k) 455 char *s; 456 struct wi_key *k; 457 { 458 int n, i; 459 char *p; 460 461 /* Is this a hex string? */ 462 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 463 /* Yes, convert to int. */ 464 n = 0; 465 p = (char *)&k->wi_keydat[0]; 466 for (i = 2; i < strlen(s); i+= 2) { 467 *p++ = (wi_hex2int(s[i]) << 4) + wi_hex2int(s[i + 1]); 468 n++; 469 } 470 k->wi_keylen = htole16(n); 471 } else { 472 /* No, just copy it in. */ 473 bcopy(s, k->wi_keydat, strlen(s)); 474 k->wi_keylen = htole16(strlen(s)); 475 } 476 477 return; 478 } 479 480 static void wi_setkeys(iface, key, idx) 481 char *iface; 482 char *key; 483 int idx; 484 { 485 struct wi_req wreq; 486 struct wi_ltv_keys *keys; 487 struct wi_key *k; 488 489 bzero((char *)&wreq, sizeof(wreq)); 490 wreq.wi_len = WI_MAX_DATALEN; 491 wreq.wi_type = WI_RID_WEP_AVAIL; 492 493 wi_getval(iface, &wreq); 494 if (le16toh(wreq.wi_val[0]) == 0) 495 err(1, "no WEP option available on this card"); 496 497 bzero((char *)&wreq, sizeof(wreq)); 498 wreq.wi_len = WI_MAX_DATALEN; 499 wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS; 500 501 wi_getval(iface, &wreq); 502 keys = (struct wi_ltv_keys *)&wreq; 503 504 if (key[0] == '0' && (key[1] == 'x' || key[1] == 'X')) { 505 if (strlen(key) > 30) 506 err(1, "encryption key must be no " 507 "more than 28 hex digits long"); 508 } else { 509 if (strlen(key) > 14) 510 err(1, "encryption key must be no " 511 "more than 14 characters long"); 512 } 513 514 if (idx > 3) 515 err(1, "only 4 encryption keys available"); 516 517 k = &keys->wi_keys[idx]; 518 wi_str2key(key, k); 519 520 wreq.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; 521 wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS; 522 wi_setval(iface, &wreq); 523 524 return; 525 } 526 527 static void wi_printkeys(wreq) 528 struct wi_req *wreq; 529 { 530 int i, j, bn; 531 struct wi_key *k; 532 struct wi_ltv_keys *keys; 533 char *ptr; 534 535 keys = (struct wi_ltv_keys *)wreq; 536 537 for (i = 0, bn = 0; i < 4; i++, bn = 0) { 538 k = &keys->wi_keys[i]; 539 ptr = (char *)k->wi_keydat; 540 for (j = 0; j < le16toh(k->wi_keylen); j++) { 541 if (!isprint((unsigned char) ptr[j])) { 542 bn = 1; 543 break; 544 } 545 } 546 547 if (bn) { 548 printf("[ 0x"); 549 for (j = 0; j < le16toh(k->wi_keylen); j++) 550 printf("%02x", ((unsigned char *) ptr)[j]); 551 printf(" ]"); 552 } else { 553 ptr[j] = '\0'; 554 printf("[ %s ]", ptr); 555 } 556 } 557 558 return; 559 }; 560 561 void wi_printwords(wreq) 562 struct wi_req *wreq; 563 { 564 int i; 565 566 printf("[ "); 567 for (i = 0; i < wreq->wi_len - 1; i++) 568 printf("%d ", le16toh(wreq->wi_val[i])); 569 printf("]"); 570 571 return; 572 } 573 574 void wi_printbool(wreq) 575 struct wi_req *wreq; 576 { 577 if (le16toh(wreq->wi_val[0])) 578 printf("[ On ]"); 579 else 580 printf("[ Off ]"); 581 582 return; 583 } 584 585 void wi_printhex(wreq) 586 struct wi_req *wreq; 587 { 588 int i; 589 unsigned char *c; 590 591 c = (unsigned char *)&wreq->wi_val; 592 593 printf("[ "); 594 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) { 595 printf("%02x", c[i]); 596 if (i < ((wreq->wi_len - 1) * 2) - 1) 597 printf(":"); 598 } 599 600 printf(" ]"); 601 return; 602 } 603 604 void wi_printbits(wreq) 605 struct wi_req *wreq; 606 { 607 int i; 608 int bits = le16toh(wreq->wi_val[0]); 609 610 printf("["); 611 for (i = 0; i < 16; i++) { 612 if (bits & 0x1) { 613 printf(" %d", i+1); 614 } 615 bits >>= 1; 616 } 617 printf(" ]"); 618 return; 619 } 620 621 static struct wi_table wi_table[] = { 622 { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" }, 623 { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t", 624 's', "station name" }, 625 { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t", 626 'q', "own SSID" }, 627 { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" }, 628 { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t", 629 'n', "network name" }, 630 { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" }, 631 { WI_RID_CHANNEL_LIST, WI_BITS, "Channel list:\t\t\t\t" }, 632 { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t", 633 'f', "frequency" }, 634 { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" }, 635 { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" }, 636 { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" }, 637 { WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t", 638 'p', "port type" }, 639 { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t", 640 'm', "MAC address" }, 641 { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t", 642 't', "TX rate" }, 643 { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"}, 644 { WI_RID_OWN_BEACON_INT, WI_WORDS, "Beacon Interval (current) [msec]:\t"}, 645 { WI_RID_MAX_DATALEN, WI_WORDS, "Maximum data length:\t\t\t", 646 'd', "maximum data length" }, 647 { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t", 648 'r', "RTS threshold" }, 649 { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t", 650 'c', "create ibss" }, 651 { WI_RID_MICROWAVE_OVEN, WI_WORDS, "Microwave oven robustness:\t\t", 652 'M', "microwave oven robustness enabled" }, 653 { WI_RID_ROAMING_MODE, WI_WORDS, "Roaming mode(1:firm,3:disable):\t\t", 654 'R', "roaming mode" }, 655 { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t", 656 'a', "system scale" }, 657 { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t", 658 'P', "power management enabled" }, 659 { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time (msec):\t\t\t", 660 'S', "max sleep duration" }, 661 { 0, WI_NONE } 662 }; 663 664 static struct wi_table wi_crypt_table[] = { 665 { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t", 666 'e', "encryption" }, 667 { WI_RID_AUTH_CNTL, WI_WORDS, "Authentication type \n(1=OpenSys, 2=Shared Key):\t\t", 668 'A', "authentication type" }, 669 { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" }, 670 { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" }, 671 { 0, WI_NONE } 672 }; 673 674 static struct wi_table *wi_tables[] = { 675 wi_table, 676 wi_crypt_table, 677 NULL 678 }; 679 680 static struct wi_table * 681 wi_optlookup(table, opt) 682 struct wi_table *table; 683 int opt; 684 { 685 struct wi_table *wt; 686 687 for (wt = table; wt->wi_type != 0; wt++) 688 if (wt->wi_opt == opt) 689 return (wt); 690 return (NULL); 691 } 692 693 static void wi_dumpinfo(iface) 694 char *iface; 695 { 696 struct wi_req wreq; 697 int i, has_wep; 698 struct wi_table *w; 699 700 bzero((char *)&wreq, sizeof(wreq)); 701 702 wreq.wi_len = WI_MAX_DATALEN; 703 wreq.wi_type = WI_RID_WEP_AVAIL; 704 705 wi_getval(iface, &wreq); 706 has_wep = le16toh(wreq.wi_val[0]); 707 708 w = wi_table; 709 710 for (i = 0; w[i].wi_code != WI_NONE; i++) { 711 bzero((char *)&wreq, sizeof(wreq)); 712 713 wreq.wi_len = WI_MAX_DATALEN; 714 wreq.wi_type = w[i].wi_type; 715 716 wi_getval(iface, &wreq); 717 printf("%s", w[i].wi_label); 718 switch (w[i].wi_code) { 719 case WI_STRING: 720 wi_printstr(&wreq); 721 break; 722 case WI_WORDS: 723 wi_printwords(&wreq); 724 break; 725 case WI_BOOL: 726 wi_printbool(&wreq); 727 break; 728 case WI_HEXBYTES: 729 wi_printhex(&wreq); 730 break; 731 case WI_BITS: 732 wi_printbits(&wreq); 733 break; 734 default: 735 break; 736 } 737 printf("\n"); 738 } 739 740 if (has_wep) { 741 w = wi_crypt_table; 742 for (i = 0; w[i].wi_code != WI_NONE; i++) { 743 bzero((char *)&wreq, sizeof(wreq)); 744 745 wreq.wi_len = WI_MAX_DATALEN; 746 wreq.wi_type = w[i].wi_type; 747 748 wi_getval(iface, &wreq); 749 printf("%s", w[i].wi_label); 750 switch (w[i].wi_code) { 751 case WI_STRING: 752 wi_printstr(&wreq); 753 break; 754 case WI_WORDS: 755 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY) 756 wreq.wi_val[0] = 757 htole16(le16toh(wreq.wi_val[0]) + 1); 758 wi_printwords(&wreq); 759 break; 760 case WI_BOOL: 761 wi_printbool(&wreq); 762 break; 763 case WI_HEXBYTES: 764 wi_printhex(&wreq); 765 break; 766 case WI_KEYSTRUCT: 767 wi_printkeys(&wreq); 768 break; 769 default: 770 break; 771 } 772 printf("\n"); 773 } 774 } 775 776 return; 777 } 778 779 static void wi_dumpstats(iface) 780 char *iface; 781 { 782 struct wi_req wreq; 783 struct wi_counters *c; 784 785 bzero((char *)&wreq, sizeof(wreq)); 786 wreq.wi_len = WI_MAX_DATALEN; 787 wreq.wi_type = WI_RID_IFACE_STATS; 788 789 wi_getval(iface, &wreq); 790 791 c = (struct wi_counters *)&wreq.wi_val; 792 793 /* XXX native byte order */ 794 printf("Transmitted unicast frames:\t\t%d\n", 795 c->wi_tx_unicast_frames); 796 printf("Transmitted multicast frames:\t\t%d\n", 797 c->wi_tx_multicast_frames); 798 printf("Transmitted fragments:\t\t\t%d\n", 799 c->wi_tx_fragments); 800 printf("Transmitted unicast octets:\t\t%d\n", 801 c->wi_tx_unicast_octets); 802 printf("Transmitted multicast octets:\t\t%d\n", 803 c->wi_tx_multicast_octets); 804 printf("Single transmit retries:\t\t%d\n", 805 c->wi_tx_single_retries); 806 printf("Multiple transmit retries:\t\t%d\n", 807 c->wi_tx_multi_retries); 808 printf("Transmit retry limit exceeded:\t\t%d\n", 809 c->wi_tx_retry_limit); 810 printf("Transmit discards:\t\t\t%d\n", 811 c->wi_tx_discards); 812 printf("Transmit discards due to wrong SA:\t%d\n", 813 c->wi_tx_discards_wrong_sa); 814 printf("Received unicast frames:\t\t%d\n", 815 c->wi_rx_unicast_frames); 816 printf("Received multicast frames:\t\t%d\n", 817 c->wi_rx_multicast_frames); 818 printf("Received fragments:\t\t\t%d\n", 819 c->wi_rx_fragments); 820 printf("Received unicast octets:\t\t%d\n", 821 c->wi_rx_unicast_octets); 822 printf("Received multicast octets:\t\t%d\n", 823 c->wi_rx_multicast_octets); 824 printf("Receive FCS errors:\t\t\t%d\n", 825 c->wi_rx_fcs_errors); 826 printf("Receive discards due to no buffer:\t%d\n", 827 c->wi_rx_discards_nobuf); 828 printf("Can't decrypt WEP frame:\t\t%d\n", 829 c->wi_rx_WEP_cant_decrypt); 830 printf("Received message fragments:\t\t%d\n", 831 c->wi_rx_msg_in_msg_frags); 832 printf("Received message bad fragments:\t\t%d\n", 833 c->wi_rx_msg_in_bad_msg_frags); 834 835 return; 836 } 837 838 static void 839 usage() 840 { 841 842 fprintf(stderr, 843 "usage: %s interface " 844 "[-oD] [-t tx rate] [-n network name] [-s station name]\n" 845 " [-e 0|1] [-k key [-v 1|2|3|4]] [-T 1|2|3|4]\n" 846 " [-c 0|1] [-q SSID] [-p port type] [-a access point density]\n" 847 " [-m MAC address] [-d max data length] [-r RTS threshold]\n" 848 " [-f frequency] [-M 0|1] [-P 0|1] [-S max sleep duration]\n" 849 " [-A 0|1 ] [-R 1|3]\n" 850 , 851 getprogname()); 852 exit(1); 853 } 854 855 int main(argc, argv) 856 int argc; 857 char *argv[]; 858 { 859 struct wi_table *wt, **table; 860 char *iface, *key, *keyv[4], *tx_crypt_key; 861 int ch, dumpinfo, dumpstats, modifier, oldind, apscan; 862 863 #define SET_OPERAND(opr, desc) do { \ 864 if ((opr) == NULL) \ 865 (opr) = optarg; \ 866 else \ 867 warnx("%s is already specified to %s", \ 868 desc, (opr)); \ 869 } while (0) 870 871 dumpinfo = 1; 872 dumpstats = 0; 873 apscan = 0; 874 iface = key = keyv[0] = keyv[1] = keyv[2] = keyv[3] = 875 tx_crypt_key = NULL; 876 877 if (argc > 1 && argv[1][0] != '-') { 878 iface = argv[1]; 879 optind++; 880 } 881 882 while ((ch = getopt(argc, argv, 883 "a:c:d:e:f:hi:k:m:n:op:q:r:s:t:A:M:S:P:R:T:DZ:")) != -1) { 884 if (ch != 'i') 885 dumpinfo = 0; 886 /* 887 * Lookup generic options and remeber operand if found. 888 */ 889 for (table = wi_tables; *table != NULL; table++) 890 if ((wt = wi_optlookup(*table, ch)) != NULL) { 891 SET_OPERAND(wt->wi_optval, wt->wi_desc); 892 break; 893 } 894 if (wt == NULL) 895 /* 896 * Handle special options. 897 */ 898 switch (ch) { 899 case 'o': 900 dumpstats = 1; 901 break; 902 case 'i': 903 SET_OPERAND(iface, "interface"); 904 break; 905 case 'k': 906 key = optarg; 907 oldind = optind; 908 opterr = 0; 909 ch = getopt(argc, argv, "v:"); 910 opterr = 1; 911 switch (ch) { 912 case 'v': 913 modifier = atoi(optarg) - 1; 914 break; 915 default: 916 modifier = 0; 917 optind = oldind; 918 break; 919 } 920 keyv[modifier] = key; 921 break; 922 case 'T': 923 SET_OPERAND(tx_crypt_key, "TX encryption key"); 924 break; 925 case 'D': 926 apscan = 1; 927 break; 928 case 'h': 929 default: 930 usage(); 931 break; 932 } 933 } 934 935 if (iface == NULL) 936 usage(); 937 938 for (table = wi_tables; *table != NULL; table++) 939 for (wt = *table; wt->wi_code != WI_NONE; wt++) 940 if (wt->wi_optval != NULL) { 941 switch (wt->wi_code) { 942 case WI_BOOL: 943 case WI_WORDS: 944 wi_setword(iface, wt->wi_type, 945 atoi(wt->wi_optval)); 946 break; 947 case WI_STRING: 948 wi_setstr(iface, wt->wi_type, 949 wt->wi_optval); 950 break; 951 case WI_HEXBYTES: 952 wi_sethex(iface, wt->wi_type, 953 wt->wi_optval); 954 break; 955 } 956 } 957 958 if (tx_crypt_key != NULL) 959 wi_setword(iface, WI_RID_TX_CRYPT_KEY, atoi(tx_crypt_key) - 1); 960 961 for (modifier = 0; modifier < sizeof(keyv) / sizeof(keyv[0]); 962 modifier++) 963 if (keyv[modifier] != NULL) 964 wi_setkeys(iface, keyv[modifier], modifier); 965 966 if (dumpstats) 967 wi_dumpstats(iface); 968 if (dumpinfo) 969 wi_dumpinfo(iface); 970 971 if (apscan) 972 #ifdef WI_RID_SCAN_APS 973 wi_apscan(iface); 974 #else 975 errx(1, "AP scan mode is not available."); 976 #endif 977 978 exit(0); 979 } 980