1 /* $NetBSD: wiconfig.c,v 1.37 2005/06/02 09:47:37 lukem 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 42 #include <net/if.h> 43 #ifdef __FreeBSD__ 44 #include <net/if_var.h> 45 #include <net/ethernet.h> 46 47 #include <machine/if_wavelan_ieee.h> 48 #else 49 #include <netinet/in.h> 50 #include <netinet/if_ether.h> 51 #ifdef __NetBSD__ 52 #include <net80211/ieee80211.h> 53 #include <net80211/ieee80211_ioctl.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.37 2005/06/02 09:47:37 lukem 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 #define WI_VENDOR 0x07 86 char *wi_label; /* label used to print info */ 87 int wi_opt; /* option character to set this */ 88 char *wi_desc; 89 char *wi_optval; 90 }; 91 92 /* already define in wireg.h XXX */ 93 #define WI_APRATE_0 0x00 /* NONE */ 94 #define WI_APRATE_1 0x0A /* 1 Mbps */ 95 #define WI_APRATE_2 0x14 /* 2 Mbps */ 96 #define WI_APRATE_5 0x37 /* 5.5 Mbps */ 97 #define WI_APRATE_11 0x6E /* 11 Mbps */ 98 99 #ifdef WI_RID_SCAN_APS 100 static void wi_apscan __P((char *)); 101 static int get_if_flags __P((int, const char *)); 102 static int set_if_flags __P((int, const char *, int)); 103 #endif 104 static void wi_getval __P((char *, struct wi_req *)); 105 static void wi_setval __P((char *, struct wi_req *)); 106 static void wi_printstr __P((struct wi_req *)); 107 static void wi_setstr __P((char *, int, char *)); 108 static void wi_setbytes __P((char *, int, char *, int)); 109 static void wi_setword __P((char *, int, int)); 110 static void wi_sethex __P((char *, int, char *)); 111 static void wi_printwords __P((struct wi_req *)); 112 static void wi_printbool __P((struct wi_req *)); 113 static void wi_printhex __P((struct wi_req *)); 114 static void wi_printbits __P((struct wi_req *)); 115 static void wi_dumpinfo __P((char *)); 116 static void wi_printkeys __P((struct wi_req *)); 117 static void wi_printvendor __P((struct wi_req *)); 118 static void wi_dumpstats __P((char *)); 119 static void usage __P((void)); 120 static struct wi_table * 121 wi_optlookup __P((struct wi_table *, int)); 122 int main __P((int argc, char **argv)); 123 124 #ifdef WI_RID_SCAN_APS 125 static int get_if_flags(s, name) 126 int s; 127 const char *name; 128 { 129 struct ifreq ifreq; 130 int flags; 131 132 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 133 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) == -1) 134 err(1, "SIOCGIFFLAGS"); 135 flags = ifreq.ifr_flags; 136 137 return flags; 138 } 139 140 static int set_if_flags(s, name, flags) 141 int s; 142 const char *name; 143 int flags; 144 { 145 struct ifreq ifreq; 146 147 ifreq.ifr_flags = flags; 148 strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 149 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) == -1) 150 err(1, "SIOCSIFFLAGS"); 151 152 return 0; 153 } 154 155 static void wi_apscan(iface) 156 char *iface; 157 { 158 struct wi_req wreq; 159 struct ifreq ifr; 160 int s; 161 int naps, rate; 162 int retries = 10; 163 int flags; 164 struct wi_apinfo *w; 165 int i, j; 166 167 if (iface == NULL) 168 errx(1, "must specify interface name"); 169 170 s = socket(AF_INET, SOCK_DGRAM, 0); 171 if (s == -1) 172 err(1, "socket"); 173 flags = get_if_flags(s, iface); 174 if ((flags & IFF_UP) == 0) 175 flags = set_if_flags(s, iface, flags | IFF_UP); 176 177 memset((char *)&wreq, 0, sizeof(wreq)); 178 179 wreq.wi_type = WI_RID_SCAN_APS; 180 wreq.wi_len = 4; 181 /* note chan. 1 is the least significant bit */ 182 wreq.wi_val[0] = htole16(0x3fff); /* 1 bit per channel, 1-14 */ 183 wreq.wi_val[1] = htole16(0xf); /* tx rate */ 184 185 /* write the request */ 186 wi_setval(iface, &wreq); 187 188 /* now poll for a result */ 189 memset((char *)&wreq, 0, sizeof(wreq)); 190 191 wreq.wi_type = WI_RID_READ_APS; 192 wreq.wi_len = WI_MAX_DATALEN; 193 194 /* we have to do this ourself as opposed to 195 * using getval, because we cannot bail if 196 * the ioctl fails 197 */ 198 memset((char *)&ifr, 0, sizeof(ifr)); 199 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 200 ifr.ifr_data = (caddr_t)&wreq; 201 202 printf("scanning ..."); 203 fflush(stdout); 204 while (ioctl(s, SIOCGWAVELAN, &ifr) == -1) { 205 retries--; 206 if (retries >= 0) { 207 printf("."); fflush(stdout); 208 sleep(1); 209 } else 210 break; 211 errno = 0; 212 } 213 214 if (errno) { 215 set_if_flags(s, iface, flags); 216 close(s); 217 err(1, "ioctl"); 218 } 219 220 naps = *(int *)wreq.wi_val; 221 222 if (naps > 0) 223 printf("\nAP Information\n"); 224 else 225 printf("\nNo APs available\n"); 226 227 w = (struct wi_apinfo *)(((char *)&wreq.wi_val) + sizeof(int)); 228 for ( i = 0; i < naps; i++, w++) { 229 printf("ap[%d]:\n", i); 230 if (w->scanreason) { 231 static char *scanm[] = { 232 "Host initiated", 233 "Firmware initiated", 234 "Inquiry request from host" 235 }; 236 printf("\tScanReason:\t\t\t[ %s ]\n", 237 scanm[w->scanreason - 1]); 238 } 239 printf("\tnetname (SSID):\t\t\t[ "); 240 for (j = 0; j < w->namelen; j++) { 241 printf("%c", w->name[j]); 242 } 243 printf(" ]\n"); 244 printf("\tBSSID:\t\t\t\t[ %02x:%02x:%02x:%02x:%02x:%02x ]\n", 245 w->bssid[0]&0xff, w->bssid[1]&0xff, 246 w->bssid[2]&0xff, w->bssid[3]&0xff, 247 w->bssid[4]&0xff, w->bssid[5]&0xff); 248 printf("\tChannel:\t\t\t[ %d ]\n", w->channel); 249 printf("\tQuality/Signal/Noise [signal]:\t[ %d / %d / %d ]\n" 250 "\t [dBm]:\t[ %d / %d / %d ]\n", 251 w->quality, w->signal, w->noise, 252 w->quality, w->signal - 149, w->noise - 149); 253 printf("\tBSS Beacon Interval [msec]:\t[ %d ]\n", w->interval); 254 printf("\tCapinfo:\t\t\t[ "); 255 if (w->capinfo & IEEE80211_CAPINFO_ESS) 256 printf("ESS "); 257 if (w->capinfo & IEEE80211_CAPINFO_PRIVACY) 258 printf("WEP "); 259 printf("]\n"); 260 261 switch (w->rate) { 262 case WI_APRATE_1: 263 rate = 1; 264 break; 265 case WI_APRATE_2: 266 rate = 2; 267 break; 268 case WI_APRATE_5: 269 rate = 5.5; 270 break; 271 case WI_APRATE_11: 272 rate = 11; 273 break; 274 case WI_APRATE_0: 275 default: 276 rate = 0; 277 break; 278 } 279 if (rate) printf("\tDataRate [Mbps]:\t\t[ %d ]\n", rate); 280 } 281 282 set_if_flags(s, iface, flags); 283 close(s); 284 } 285 #endif 286 287 static void wi_getval(iface, wreq) 288 char *iface; 289 struct wi_req *wreq; 290 { 291 struct ifreq ifr; 292 int s; 293 294 bzero((char *)&ifr, sizeof(ifr)); 295 296 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 297 ifr.ifr_data = (caddr_t)wreq; 298 299 s = socket(AF_INET, SOCK_DGRAM, 0); 300 301 if (s == -1) 302 err(1, "socket"); 303 304 if (ioctl(s, SIOCGWAVELAN, &ifr) == -1) 305 err(1, "SIOCGWAVELAN"); 306 307 close(s); 308 309 return; 310 } 311 312 static void wi_setval(iface, wreq) 313 char *iface; 314 struct wi_req *wreq; 315 { 316 struct ifreq ifr; 317 int s; 318 319 bzero((char *)&ifr, sizeof(ifr)); 320 321 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 322 ifr.ifr_data = (caddr_t)wreq; 323 324 s = socket(AF_INET, SOCK_DGRAM, 0); 325 326 if (s == -1) 327 err(1, "socket"); 328 329 if (ioctl(s, SIOCSWAVELAN, &ifr) == -1) 330 err(1, "SIOCSWAVELAN"); 331 332 close(s); 333 334 return; 335 } 336 337 void wi_printstr(wreq) 338 struct wi_req *wreq; 339 { 340 char *ptr; 341 int i; 342 343 if (wreq->wi_type == WI_RID_SERIALNO) { 344 ptr = (char *)&wreq->wi_val; 345 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) { 346 if (ptr[i] == '\0') 347 ptr[i] = ' '; 348 } 349 } else { 350 int len = le16toh(wreq->wi_val[0]); 351 352 ptr = (char *)&wreq->wi_val[1]; 353 for (i = 0; i < len; i++) { 354 if (ptr[i] == '\0') 355 ptr[i] = ' '; 356 } 357 } 358 359 ptr[i] = '\0'; 360 printf("[ %s ]", ptr); 361 362 return; 363 } 364 365 void wi_setstr(iface, code, str) 366 char *iface; 367 int code; 368 char *str; 369 { 370 struct wi_req wreq; 371 372 bzero((char *)&wreq, sizeof(wreq)); 373 374 if (strlen(str) > 30) 375 errx(1, "string too long"); 376 377 wreq.wi_type = code; 378 wreq.wi_len = 18; 379 wreq.wi_val[0] = htole16(strlen(str)); 380 bcopy(str, (char *)&wreq.wi_val[1], strlen(str)); 381 382 wi_setval(iface, &wreq); 383 384 return; 385 } 386 387 void wi_setbytes(iface, code, bytes, len) 388 char *iface; 389 int code; 390 char *bytes; 391 int len; 392 { 393 struct wi_req wreq; 394 395 bzero((char *)&wreq, sizeof(wreq)); 396 397 wreq.wi_type = code; 398 wreq.wi_len = (len / 2) + 1; 399 bcopy(bytes, (char *)&wreq.wi_val[0], len); 400 401 wi_setval(iface, &wreq); 402 403 return; 404 } 405 406 void wi_setword(iface, code, word) 407 char *iface; 408 int code; 409 int word; 410 { 411 struct wi_req wreq; 412 413 bzero((char *)&wreq, sizeof(wreq)); 414 415 wreq.wi_type = code; 416 wreq.wi_len = 2; 417 wreq.wi_val[0] = htole16(word); 418 419 wi_setval(iface, &wreq); 420 421 return; 422 } 423 424 void wi_sethex(iface, code, str) 425 char *iface; 426 int code; 427 char *str; 428 { 429 struct ether_addr *addr; 430 431 addr = ether_aton(str); 432 if (addr == NULL) 433 errx(1, "badly formatted address"); 434 435 wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN); 436 437 return; 438 } 439 440 static void wi_printkeys(wreq) 441 struct wi_req *wreq; 442 { 443 int i, j, bn; 444 struct wi_key *k; 445 struct wi_ltv_keys *keys; 446 char *ptr; 447 448 keys = (struct wi_ltv_keys *)wreq; 449 450 for (i = 0, bn = 0; i < 4; i++, bn = 0) { 451 k = &keys->wi_keys[i]; 452 ptr = (char *)k->wi_keydat; 453 for (j = 0; j < le16toh(k->wi_keylen); j++) { 454 if (!isprint((unsigned char) ptr[j])) { 455 bn = 1; 456 break; 457 } 458 } 459 460 if (bn) { 461 printf("[ 0x"); 462 for (j = 0; j < le16toh(k->wi_keylen); j++) 463 printf("%02x", ((unsigned char *) ptr)[j]); 464 printf(" ]"); 465 } else { 466 ptr[j] = '\0'; 467 printf("[ %s ]", ptr); 468 } 469 } 470 471 return; 472 }; 473 474 void wi_printvendor(wreq) 475 struct wi_req *wreq; 476 { 477 /* id 478 * vendor 479 * firmware major 480 * minor 481 */ 482 #define WI_RID_STA_IDENTITY_LUCENT 0x1 483 #define WI_RID_STA_IDENTITY_PRISMII 0x2 484 #define WI_RID_STA_IDENTITY_SAMSUNG 0x3 485 #define WI_RID_STA_IDENTITY_DLINK 0x6 486 487 const char *vendor = "Unknown"; 488 489 if (wreq->wi_len < 4) 490 return; 491 492 switch (le16toh(wreq->wi_val[1])) { 493 case WI_RID_STA_IDENTITY_LUCENT: 494 vendor = "Lucent"; 495 break; 496 case WI_RID_STA_IDENTITY_PRISMII: 497 vendor = "generic PRISM II"; 498 break; 499 case WI_RID_STA_IDENTITY_SAMSUNG: 500 vendor = "Samsung"; 501 break; 502 case WI_RID_STA_IDENTITY_DLINK: 503 vendor = "D-Link"; 504 break; 505 } 506 printf("[ %s ID: %d version: %d.%d ]", vendor, le16toh(wreq->wi_val[0]), 507 le16toh(wreq->wi_val[2]), le16toh(wreq->wi_val[3])); 508 return; 509 } 510 511 void wi_printwords(wreq) 512 struct wi_req *wreq; 513 { 514 int i; 515 516 printf("[ "); 517 for (i = 0; i < wreq->wi_len - 1; i++) 518 printf("%d ", le16toh(wreq->wi_val[i])); 519 printf("]"); 520 521 return; 522 } 523 524 void wi_printbool(wreq) 525 struct wi_req *wreq; 526 { 527 if (le16toh(wreq->wi_val[0])) 528 printf("[ On ]"); 529 else 530 printf("[ Off ]"); 531 532 return; 533 } 534 535 void wi_printhex(wreq) 536 struct wi_req *wreq; 537 { 538 int i; 539 unsigned char *c; 540 541 c = (unsigned char *)&wreq->wi_val; 542 543 printf("[ "); 544 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) { 545 printf("%02x", c[i]); 546 if (i < ((wreq->wi_len - 1) * 2) - 1) 547 printf(":"); 548 } 549 550 printf(" ]"); 551 return; 552 } 553 554 void wi_printbits(wreq) 555 struct wi_req *wreq; 556 { 557 int i; 558 int bits = le16toh(wreq->wi_val[0]); 559 560 printf("["); 561 for (i = 0; i < 16; i++) { 562 if (bits & 0x1) { 563 printf(" %d", i+1); 564 } 565 bits >>= 1; 566 } 567 printf(" ]"); 568 return; 569 } 570 571 static struct wi_table wi_table[] = { 572 { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" }, 573 { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t", 574 's', "station name" }, 575 { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t" }, 576 { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" }, 577 { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t" }, 578 { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" }, 579 { WI_RID_CHANNEL_LIST, WI_BITS, "Channel list:\t\t\t\t" }, 580 { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t" }, 581 { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" }, 582 { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" }, 583 { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" }, 584 { WI_RID_PORTTYPE, WI_WORDS, "Port type:\t\t\t\t" }, 585 { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t", 586 'm', "MAC address" }, 587 { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t" }, 588 { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"}, 589 { WI_RID_CUR_BEACON_INT, WI_WORDS, "Beacon Interval (current) [msec]:\t"}, 590 { WI_RID_MAX_DATALEN, WI_WORDS, "Maximum data length:\t\t\t", 591 'd', "maximum data length" }, 592 { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t", 593 'r', "RTS threshold" }, 594 { WI_RID_FRAG_THRESH, WI_WORDS, "fragmentation threshold:\t\t", 595 'g', "fragmentation threshold" }, 596 { WI_RID_DBM_ADJUST, WI_WORDS, "RSSI -> dBm adjustment:\t\t\t" }, 597 { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t" }, 598 { WI_RID_MICROWAVE_OVEN, WI_WORDS, "Microwave oven robustness:\t\t", 599 'M', "microwave oven robustness enabled" }, 600 { WI_RID_ROAMING_MODE, WI_WORDS, "Roaming mode(1:firm,3:disable):\t\t", 601 'R', "roaming mode" }, 602 { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t", 603 'a', "system scale" }, 604 { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t" }, 605 { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time (msec):\t\t\t" }, 606 { WI_RID_STA_IDENTITY, WI_VENDOR, "Vendor info:\t\t\t\t" }, 607 { 0, WI_NONE } 608 }; 609 610 static struct wi_table wi_crypt_table[] = { 611 { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t" }, 612 { WI_RID_CNFAUTHMODE, WI_WORDS, "Authentication type \n(1=OpenSys, 2=Shared Key):\t\t", 613 'A', "authentication type" }, 614 { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" }, 615 { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" }, 616 { 0, WI_NONE } 617 }; 618 619 static struct wi_table *wi_tables[] = { 620 wi_table, 621 wi_crypt_table, 622 NULL 623 }; 624 625 static struct wi_table * 626 wi_optlookup(table, opt) 627 struct wi_table *table; 628 int opt; 629 { 630 struct wi_table *wt; 631 632 for (wt = table; wt->wi_type != 0; wt++) 633 if (wt->wi_opt == opt) 634 return (wt); 635 return (NULL); 636 } 637 638 static void wi_dumpinfo(iface) 639 char *iface; 640 { 641 struct wi_req wreq; 642 int i, has_wep; 643 struct wi_table *w; 644 645 bzero((char *)&wreq, sizeof(wreq)); 646 647 wreq.wi_len = WI_MAX_DATALEN; 648 wreq.wi_type = WI_RID_WEP_AVAIL; 649 650 wi_getval(iface, &wreq); 651 has_wep = le16toh(wreq.wi_val[0]); 652 653 w = wi_table; 654 655 for (i = 0; w[i].wi_code != WI_NONE; i++) { 656 bzero((char *)&wreq, sizeof(wreq)); 657 658 wreq.wi_len = WI_MAX_DATALEN; 659 wreq.wi_type = w[i].wi_type; 660 661 wi_getval(iface, &wreq); 662 printf("%s", w[i].wi_label); 663 switch (w[i].wi_code) { 664 case WI_STRING: 665 wi_printstr(&wreq); 666 break; 667 case WI_WORDS: 668 wi_printwords(&wreq); 669 break; 670 case WI_BOOL: 671 wi_printbool(&wreq); 672 break; 673 case WI_HEXBYTES: 674 wi_printhex(&wreq); 675 break; 676 case WI_BITS: 677 wi_printbits(&wreq); 678 break; 679 case WI_VENDOR: 680 wi_printvendor(&wreq); 681 break; 682 default: 683 break; 684 } 685 printf("\n"); 686 } 687 688 if (has_wep) { 689 w = wi_crypt_table; 690 for (i = 0; w[i].wi_code != WI_NONE; i++) { 691 bzero((char *)&wreq, sizeof(wreq)); 692 693 wreq.wi_len = WI_MAX_DATALEN; 694 wreq.wi_type = w[i].wi_type; 695 696 wi_getval(iface, &wreq); 697 printf("%s", w[i].wi_label); 698 switch (w[i].wi_code) { 699 case WI_STRING: 700 wi_printstr(&wreq); 701 break; 702 case WI_WORDS: 703 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY) 704 wreq.wi_val[0] = 705 htole16(le16toh(wreq.wi_val[0]) + 1); 706 wi_printwords(&wreq); 707 break; 708 case WI_BOOL: 709 wi_printbool(&wreq); 710 break; 711 case WI_HEXBYTES: 712 wi_printhex(&wreq); 713 break; 714 case WI_KEYSTRUCT: 715 wi_printkeys(&wreq); 716 break; 717 default: 718 break; 719 } 720 printf("\n"); 721 } 722 } 723 724 return; 725 } 726 727 static void wi_dumpstats(iface) 728 char *iface; 729 { 730 struct wi_req wreq; 731 struct wi_counters *c; 732 733 bzero((char *)&wreq, sizeof(wreq)); 734 wreq.wi_len = WI_MAX_DATALEN; 735 wreq.wi_type = WI_RID_IFACE_STATS; 736 737 wi_getval(iface, &wreq); 738 739 c = (struct wi_counters *)&wreq.wi_val; 740 741 /* XXX native byte order */ 742 printf("Transmitted unicast frames:\t\t%d\n", 743 c->wi_tx_unicast_frames); 744 printf("Transmitted multicast frames:\t\t%d\n", 745 c->wi_tx_multicast_frames); 746 printf("Transmitted fragments:\t\t\t%d\n", 747 c->wi_tx_fragments); 748 printf("Transmitted unicast octets:\t\t%d\n", 749 c->wi_tx_unicast_octets); 750 printf("Transmitted multicast octets:\t\t%d\n", 751 c->wi_tx_multicast_octets); 752 printf("Single transmit retries:\t\t%d\n", 753 c->wi_tx_single_retries); 754 printf("Multiple transmit retries:\t\t%d\n", 755 c->wi_tx_multi_retries); 756 printf("Transmit retry limit exceeded:\t\t%d\n", 757 c->wi_tx_retry_limit); 758 printf("Transmit discards:\t\t\t%d\n", 759 c->wi_tx_discards); 760 printf("Transmit discards due to wrong SA:\t%d\n", 761 c->wi_tx_discards_wrong_sa); 762 printf("Received unicast frames:\t\t%d\n", 763 c->wi_rx_unicast_frames); 764 printf("Received multicast frames:\t\t%d\n", 765 c->wi_rx_multicast_frames); 766 printf("Received fragments:\t\t\t%d\n", 767 c->wi_rx_fragments); 768 printf("Received unicast octets:\t\t%d\n", 769 c->wi_rx_unicast_octets); 770 printf("Received multicast octets:\t\t%d\n", 771 c->wi_rx_multicast_octets); 772 printf("Receive FCS errors:\t\t\t%d\n", 773 c->wi_rx_fcs_errors); 774 printf("Receive discards due to no buffer:\t%d\n", 775 c->wi_rx_discards_nobuf); 776 printf("Can't decrypt WEP frame:\t\t%d\n", 777 c->wi_rx_WEP_cant_decrypt); 778 printf("Received message fragments:\t\t%d\n", 779 c->wi_rx_msg_in_msg_frags); 780 printf("Received message bad fragments:\t\t%d\n", 781 c->wi_rx_msg_in_bad_msg_frags); 782 783 return; 784 } 785 786 static void 787 usage() 788 { 789 790 fprintf(stderr, 791 "usage: %s interface [-Dho] [-A 1|2] [-a access point density]\n" 792 " [-d max data length] [-g fragmentation threshold] [-M 0|1]\n" 793 " [-m MAC address] [-R 1|3] [-r RTS threshold] [-s station name]\n" 794 , 795 getprogname()); 796 exit(1); 797 } 798 799 int main(argc, argv) 800 int argc; 801 char *argv[]; 802 { 803 struct wi_table *wt, **table; 804 char *iface; 805 int ch, dumpinfo, dumpstats, apscan; 806 807 #define SET_OPERAND(opr, desc) do { \ 808 if ((opr) == NULL) \ 809 (opr) = optarg; \ 810 else \ 811 warnx("%s is already specified to %s", \ 812 desc, (opr)); \ 813 } while (0) 814 815 dumpinfo = 1; 816 dumpstats = 0; 817 apscan = 0; 818 iface = NULL; 819 820 if (argc > 1 && argv[1][0] != '-') { 821 iface = argv[1]; 822 optind++; 823 } 824 825 while ((ch = getopt(argc, argv, 826 "a:d:g:hi:m:or:s:A:M:R:D")) != -1) { 827 if (ch != 'i') 828 dumpinfo = 0; 829 /* 830 * Lookup generic options and remember operand if found. 831 */ 832 wt = NULL; /* XXXGCC -Wuninitialized */ 833 for (table = wi_tables; *table != NULL; table++) 834 if ((wt = wi_optlookup(*table, ch)) != NULL) { 835 SET_OPERAND(wt->wi_optval, wt->wi_desc); 836 break; 837 } 838 if (wt == NULL) 839 /* 840 * Handle special options. 841 */ 842 switch (ch) { 843 case 'o': 844 dumpstats = 1; 845 break; 846 case 'i': 847 SET_OPERAND(iface, "interface"); 848 break; 849 case 'D': 850 apscan = 1; 851 break; 852 case 'h': 853 default: 854 usage(); 855 break; 856 } 857 } 858 859 if (iface == NULL) 860 usage(); 861 862 for (table = wi_tables; *table != NULL; table++) 863 for (wt = *table; wt->wi_code != WI_NONE; wt++) 864 if (wt->wi_optval != NULL) { 865 switch (wt->wi_code) { 866 case WI_BOOL: 867 case WI_WORDS: 868 wi_setword(iface, wt->wi_type, 869 atoi(wt->wi_optval)); 870 break; 871 case WI_STRING: 872 wi_setstr(iface, wt->wi_type, 873 wt->wi_optval); 874 break; 875 case WI_HEXBYTES: 876 wi_sethex(iface, wt->wi_type, 877 wt->wi_optval); 878 break; 879 } 880 } 881 882 if (dumpstats) 883 wi_dumpstats(iface); 884 if (dumpinfo) 885 wi_dumpinfo(iface); 886 887 if (apscan) 888 #ifdef WI_RID_SCAN_APS 889 wi_apscan(iface); 890 #else 891 errx(1, "AP scan mode is not available."); 892 #endif 893 894 exit(0); 895 } 896