1 /* $NetBSD: wiconfig.c,v 1.40 2007/06/08 21:47:20 sborrill 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.40 2007/06/08 21:47:20 sborrill 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 int 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_checkwifi __P((char *)); 116 static void wi_dumpinfo __P((char *)); 117 static void wi_printkeys __P((struct wi_req *)); 118 static void wi_printvendor __P((struct wi_req *)); 119 static void wi_dumpstats __P((char *)); 120 static void usage __P((void)); 121 static struct wi_table * 122 wi_optlookup __P((struct wi_table *, int)); 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] = htole16(0x3fff); /* 1 bit per channel, 1-14 */ 184 wreq.wi_val[1] = htole16(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 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 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 int wi_getval(iface, wreq) 289 char *iface; 290 struct wi_req *wreq; 291 { 292 struct ifreq ifr; 293 int s, error; 294 295 error = 0; 296 bzero((char *)&ifr, sizeof(ifr)); 297 298 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 299 ifr.ifr_data = (caddr_t)wreq; 300 301 s = socket(AF_INET, SOCK_DGRAM, 0); 302 303 if (s == -1) 304 err(1, "socket"); 305 306 if (ioctl(s, SIOCGWAVELAN, &ifr) == -1) { 307 warn("SIOCGWAVELAN(wreq %04x)", wreq->wi_type); 308 error = 1; 309 } 310 311 close(s); 312 313 return error; 314 } 315 316 static void wi_setval(iface, wreq) 317 char *iface; 318 struct wi_req *wreq; 319 { 320 struct ifreq ifr; 321 int s; 322 323 bzero((char *)&ifr, sizeof(ifr)); 324 325 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 326 ifr.ifr_data = (caddr_t)wreq; 327 328 s = socket(AF_INET, SOCK_DGRAM, 0); 329 330 if (s == -1) 331 err(1, "socket"); 332 333 if (ioctl(s, SIOCSWAVELAN, &ifr) == -1) 334 err(1, "SIOCSWAVELAN"); 335 336 close(s); 337 338 return; 339 } 340 341 void wi_printstr(wreq) 342 struct wi_req *wreq; 343 { 344 char *ptr; 345 int i; 346 347 if (wreq->wi_type == WI_RID_SERIALNO) { 348 ptr = (char *)&wreq->wi_val; 349 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) { 350 if (ptr[i] == '\0') 351 ptr[i] = ' '; 352 } 353 } else { 354 int len = le16toh(wreq->wi_val[0]); 355 356 ptr = (char *)&wreq->wi_val[1]; 357 for (i = 0; i < len; i++) { 358 if (ptr[i] == '\0') 359 ptr[i] = ' '; 360 } 361 } 362 363 ptr[i] = '\0'; 364 printf("[ %s ]", ptr); 365 366 return; 367 } 368 369 void wi_setstr(iface, code, str) 370 char *iface; 371 int code; 372 char *str; 373 { 374 struct wi_req wreq; 375 376 bzero((char *)&wreq, sizeof(wreq)); 377 378 if (strlen(str) > 30) 379 errx(1, "string too long"); 380 381 wreq.wi_type = code; 382 wreq.wi_len = 18; 383 wreq.wi_val[0] = htole16(strlen(str)); 384 bcopy(str, (char *)&wreq.wi_val[1], strlen(str)); 385 386 wi_setval(iface, &wreq); 387 388 return; 389 } 390 391 void wi_setbytes(iface, code, bytes, len) 392 char *iface; 393 int code; 394 char *bytes; 395 int len; 396 { 397 struct wi_req wreq; 398 399 bzero((char *)&wreq, sizeof(wreq)); 400 401 wreq.wi_type = code; 402 wreq.wi_len = (len / 2) + 1; 403 bcopy(bytes, (char *)&wreq.wi_val[0], len); 404 405 wi_setval(iface, &wreq); 406 407 return; 408 } 409 410 void wi_setword(iface, code, word) 411 char *iface; 412 int code; 413 int word; 414 { 415 struct wi_req wreq; 416 417 bzero((char *)&wreq, sizeof(wreq)); 418 419 wreq.wi_type = code; 420 wreq.wi_len = 2; 421 wreq.wi_val[0] = htole16(word); 422 423 wi_setval(iface, &wreq); 424 425 return; 426 } 427 428 void wi_sethex(iface, code, str) 429 char *iface; 430 int code; 431 char *str; 432 { 433 struct ether_addr *addr; 434 435 addr = ether_aton(str); 436 if (addr == NULL) 437 errx(1, "badly formatted address"); 438 439 wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN); 440 441 return; 442 } 443 444 static void wi_printkeys(wreq) 445 struct wi_req *wreq; 446 { 447 int i, j, bn; 448 struct wi_key *k; 449 struct wi_ltv_keys *keys; 450 char *ptr; 451 452 keys = (struct wi_ltv_keys *)wreq; 453 454 for (i = 0, bn = 0; i < 4; i++, bn = 0) { 455 k = &keys->wi_keys[i]; 456 ptr = (char *)k->wi_keydat; 457 for (j = 0; j < le16toh(k->wi_keylen); j++) { 458 if (!isprint((unsigned char) ptr[j])) { 459 bn = 1; 460 break; 461 } 462 } 463 464 if (bn) { 465 printf("[ 0x"); 466 for (j = 0; j < le16toh(k->wi_keylen); j++) 467 printf("%02x", ((unsigned char *) ptr)[j]); 468 printf(" ]"); 469 } else { 470 ptr[j] = '\0'; 471 printf("[ %s ]", ptr); 472 } 473 } 474 475 return; 476 }; 477 478 void wi_printvendor(wreq) 479 struct wi_req *wreq; 480 { 481 /* id 482 * vendor 483 * firmware major 484 * minor 485 */ 486 #define WI_RID_STA_IDENTITY_LUCENT 0x1 487 #define WI_RID_STA_IDENTITY_PRISMII 0x2 488 #define WI_RID_STA_IDENTITY_SAMSUNG 0x3 489 #define WI_RID_STA_IDENTITY_DLINK 0x6 490 491 const char *vendor = "Unknown"; 492 493 if (wreq->wi_len < 4) 494 return; 495 496 switch (le16toh(wreq->wi_val[1])) { 497 case WI_RID_STA_IDENTITY_LUCENT: 498 vendor = "Lucent"; 499 break; 500 case WI_RID_STA_IDENTITY_PRISMII: 501 vendor = "generic PRISM II"; 502 break; 503 case WI_RID_STA_IDENTITY_SAMSUNG: 504 vendor = "Samsung"; 505 break; 506 case WI_RID_STA_IDENTITY_DLINK: 507 vendor = "D-Link"; 508 break; 509 } 510 printf("[ %s ID: %d version: %d.%d ]", vendor, le16toh(wreq->wi_val[0]), 511 le16toh(wreq->wi_val[2]), le16toh(wreq->wi_val[3])); 512 return; 513 } 514 515 void wi_printwords(wreq) 516 struct wi_req *wreq; 517 { 518 int i; 519 520 printf("[ "); 521 for (i = 0; i < wreq->wi_len - 1; i++) 522 printf("%d ", le16toh(wreq->wi_val[i])); 523 printf("]"); 524 525 return; 526 } 527 528 void wi_printbool(wreq) 529 struct wi_req *wreq; 530 { 531 if (le16toh(wreq->wi_val[0])) 532 printf("[ On ]"); 533 else 534 printf("[ Off ]"); 535 536 return; 537 } 538 539 void wi_printhex(wreq) 540 struct wi_req *wreq; 541 { 542 int i; 543 unsigned char *c; 544 545 c = (unsigned char *)&wreq->wi_val; 546 547 printf("[ "); 548 for (i = 0; i < (wreq->wi_len - 1) * 2; i++) { 549 printf("%02x", c[i]); 550 if (i < ((wreq->wi_len - 1) * 2) - 1) 551 printf(":"); 552 } 553 554 printf(" ]"); 555 return; 556 } 557 558 void wi_printbits(wreq) 559 struct wi_req *wreq; 560 { 561 int i; 562 int bits = le16toh(wreq->wi_val[0]); 563 564 printf("["); 565 for (i = 0; i < 16; i++) { 566 if (bits & 0x1) { 567 printf(" %d", i+1); 568 } 569 bits >>= 1; 570 } 571 printf(" ]"); 572 return; 573 } 574 575 static struct wi_table wi_table[] = { 576 { WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" }, 577 { WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t", 578 's', "station name" }, 579 { WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t" }, 580 { WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" }, 581 { WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t" }, 582 { WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" }, 583 { WI_RID_CHANNEL_LIST, WI_BITS, "Channel list:\t\t\t\t" }, 584 { WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t" }, 585 { WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" }, 586 { WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" }, 587 { WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" }, 588 { WI_RID_PORTTYPE, WI_WORDS, "Port type:\t\t\t\t" }, 589 { WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t", 590 'm', "MAC address" }, 591 { WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t" }, 592 { WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"}, 593 { WI_RID_CUR_BEACON_INT, WI_WORDS, "Beacon Interval (current) [msec]:\t"}, 594 { WI_RID_MAX_DATALEN, WI_WORDS, "Maximum data length:\t\t\t", 595 'd', "maximum data length" }, 596 { WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t", 597 'r', "RTS threshold" }, 598 { WI_RID_FRAG_THRESH, WI_WORDS, "fragmentation threshold:\t\t", 599 'g', "fragmentation threshold" }, 600 { WI_RID_DBM_ADJUST, WI_WORDS, "RSSI -> dBm adjustment:\t\t\t" }, 601 { WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t" }, 602 { WI_RID_MICROWAVE_OVEN, WI_WORDS, "Microwave oven robustness:\t\t", 603 'M', "microwave oven robustness enabled" }, 604 { WI_RID_ROAMING_MODE, WI_WORDS, "Roaming mode(1:firm,3:disable):\t\t", 605 'R', "roaming mode" }, 606 { WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t", 607 'a', "system scale" }, 608 { WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t" }, 609 { WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time (msec):\t\t\t" }, 610 { WI_RID_STA_IDENTITY, WI_VENDOR, "Vendor info:\t\t\t\t" }, 611 { 0, WI_NONE } 612 }; 613 614 static struct wi_table wi_crypt_table[] = { 615 { WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t" }, 616 { WI_RID_CNFAUTHMODE, WI_WORDS, "Authentication type \n(1=OpenSys, 2=Shared Key):\t\t", 617 'A', "authentication type" }, 618 { WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" }, 619 { WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" }, 620 { 0, WI_NONE } 621 }; 622 623 static struct wi_table *wi_tables[] = { 624 wi_table, 625 wi_crypt_table, 626 NULL 627 }; 628 629 static struct wi_table * 630 wi_optlookup(table, opt) 631 struct wi_table *table; 632 int opt; 633 { 634 struct wi_table *wt; 635 636 for (wt = table; wt->wi_type != 0; wt++) 637 if (wt->wi_opt == opt) 638 return (wt); 639 return (NULL); 640 } 641 642 static void wi_checkwifi(iface) 643 char *iface; 644 { 645 struct ifreq ifr; 646 struct ieee80211_nwid nwid; 647 int s; 648 649 bzero((char *)&ifr, sizeof(ifr)); 650 651 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 652 ifr.ifr_data = (void *)&nwid; 653 654 s = socket(AF_INET, SOCK_DGRAM, 0); 655 656 if (s == -1) 657 err(1, "socket"); 658 659 /* Choice of ioctl inspired by ifconfig/ieee80211.c */ 660 if (ioctl(s, SIOCG80211NWID, &ifr) == -1) 661 err(1, "SIOCG80211NWID"); 662 663 close(s); 664 } 665 666 static void wi_dumpinfo(iface) 667 char *iface; 668 { 669 struct wi_req wreq; 670 int i, has_wep; 671 struct wi_table *w; 672 673 bzero((char *)&wreq, sizeof(wreq)); 674 675 wreq.wi_len = WI_MAX_DATALEN; 676 wreq.wi_type = WI_RID_WEP_AVAIL; 677 678 wi_getval(iface, &wreq); 679 has_wep = le16toh(wreq.wi_val[0]); 680 681 w = wi_table; 682 683 for (i = 0; w[i].wi_code != WI_NONE; i++) { 684 bzero((char *)&wreq, sizeof(wreq)); 685 686 wreq.wi_len = WI_MAX_DATALEN; 687 wreq.wi_type = w[i].wi_type; 688 689 printf("%s", w[i].wi_label); 690 if (wi_getval(iface, &wreq)) { 691 printf("[ Unknown ]\n"); 692 continue; 693 } 694 switch (w[i].wi_code) { 695 case WI_STRING: 696 wi_printstr(&wreq); 697 break; 698 case WI_WORDS: 699 wi_printwords(&wreq); 700 break; 701 case WI_BOOL: 702 wi_printbool(&wreq); 703 break; 704 case WI_HEXBYTES: 705 wi_printhex(&wreq); 706 break; 707 case WI_BITS: 708 wi_printbits(&wreq); 709 break; 710 case WI_VENDOR: 711 wi_printvendor(&wreq); 712 break; 713 default: 714 break; 715 } 716 printf("\n"); 717 } 718 719 if (has_wep) { 720 w = wi_crypt_table; 721 for (i = 0; w[i].wi_code != WI_NONE; i++) { 722 bzero((char *)&wreq, sizeof(wreq)); 723 724 wreq.wi_len = WI_MAX_DATALEN; 725 wreq.wi_type = w[i].wi_type; 726 727 wi_getval(iface, &wreq); 728 printf("%s", w[i].wi_label); 729 switch (w[i].wi_code) { 730 case WI_STRING: 731 wi_printstr(&wreq); 732 break; 733 case WI_WORDS: 734 if (wreq.wi_type == WI_RID_TX_CRYPT_KEY) 735 wreq.wi_val[0] = 736 htole16(le16toh(wreq.wi_val[0]) + 1); 737 wi_printwords(&wreq); 738 break; 739 case WI_BOOL: 740 wi_printbool(&wreq); 741 break; 742 case WI_HEXBYTES: 743 wi_printhex(&wreq); 744 break; 745 case WI_KEYSTRUCT: 746 wi_printkeys(&wreq); 747 break; 748 default: 749 break; 750 } 751 printf("\n"); 752 } 753 } 754 755 return; 756 } 757 758 static void wi_dumpstats(iface) 759 char *iface; 760 { 761 struct wi_req wreq; 762 struct wi_counters *c; 763 764 bzero((char *)&wreq, sizeof(wreq)); 765 wreq.wi_len = WI_MAX_DATALEN; 766 wreq.wi_type = WI_RID_IFACE_STATS; 767 768 wi_getval(iface, &wreq); 769 770 c = (struct wi_counters *)&wreq.wi_val; 771 772 /* XXX native byte order */ 773 printf("Transmitted unicast frames:\t\t%d\n", 774 c->wi_tx_unicast_frames); 775 printf("Transmitted multicast frames:\t\t%d\n", 776 c->wi_tx_multicast_frames); 777 printf("Transmitted fragments:\t\t\t%d\n", 778 c->wi_tx_fragments); 779 printf("Transmitted unicast octets:\t\t%d\n", 780 c->wi_tx_unicast_octets); 781 printf("Transmitted multicast octets:\t\t%d\n", 782 c->wi_tx_multicast_octets); 783 printf("Single transmit retries:\t\t%d\n", 784 c->wi_tx_single_retries); 785 printf("Multiple transmit retries:\t\t%d\n", 786 c->wi_tx_multi_retries); 787 printf("Transmit retry limit exceeded:\t\t%d\n", 788 c->wi_tx_retry_limit); 789 printf("Transmit discards:\t\t\t%d\n", 790 c->wi_tx_discards); 791 printf("Transmit discards due to wrong SA:\t%d\n", 792 c->wi_tx_discards_wrong_sa); 793 printf("Received unicast frames:\t\t%d\n", 794 c->wi_rx_unicast_frames); 795 printf("Received multicast frames:\t\t%d\n", 796 c->wi_rx_multicast_frames); 797 printf("Received fragments:\t\t\t%d\n", 798 c->wi_rx_fragments); 799 printf("Received unicast octets:\t\t%d\n", 800 c->wi_rx_unicast_octets); 801 printf("Received multicast octets:\t\t%d\n", 802 c->wi_rx_multicast_octets); 803 printf("Receive FCS errors:\t\t\t%d\n", 804 c->wi_rx_fcs_errors); 805 printf("Receive discards due to no buffer:\t%d\n", 806 c->wi_rx_discards_nobuf); 807 printf("Can't decrypt WEP frame:\t\t%d\n", 808 c->wi_rx_WEP_cant_decrypt); 809 printf("Received message fragments:\t\t%d\n", 810 c->wi_rx_msg_in_msg_frags); 811 printf("Received message bad fragments:\t\t%d\n", 812 c->wi_rx_msg_in_bad_msg_frags); 813 814 return; 815 } 816 817 static void 818 usage() 819 { 820 821 fprintf(stderr, 822 "usage: %s interface [-Dho] [-A 1|2] [-a access point density]\n" 823 " [-d max data length] [-g fragmentation threshold] [-M 0|1]\n" 824 " [-m MAC address] [-R 1|3] [-r RTS threshold] [-s station name]\n" 825 , 826 getprogname()); 827 exit(1); 828 } 829 830 int main(argc, argv) 831 int argc; 832 char *argv[]; 833 { 834 struct wi_table *wt, **table; 835 char *iface; 836 int ch, dumpinfo, dumpstats, apscan; 837 838 #define SET_OPERAND(opr, desc) do { \ 839 if ((opr) == NULL) \ 840 (opr) = optarg; \ 841 else \ 842 warnx("%s is already specified to %s", \ 843 desc, (opr)); \ 844 } while (0) 845 846 dumpinfo = 1; 847 dumpstats = 0; 848 apscan = 0; 849 iface = NULL; 850 851 if (argc > 1 && argv[1][0] != '-') { 852 iface = argv[1]; 853 optind++; 854 } 855 856 while ((ch = getopt(argc, argv, 857 "a:d:g:hi:m:or:s:A:M:R:D")) != -1) { 858 if (ch != 'i') 859 dumpinfo = 0; 860 /* 861 * Lookup generic options and remember operand if found. 862 */ 863 wt = NULL; /* XXXGCC -Wuninitialized */ 864 for (table = wi_tables; *table != NULL; table++) 865 if ((wt = wi_optlookup(*table, ch)) != NULL) { 866 SET_OPERAND(wt->wi_optval, wt->wi_desc); 867 break; 868 } 869 if (wt == NULL) 870 /* 871 * Handle special options. 872 */ 873 switch (ch) { 874 case 'o': 875 dumpstats = 1; 876 break; 877 case 'i': 878 SET_OPERAND(iface, "interface"); 879 break; 880 case 'D': 881 apscan = 1; 882 break; 883 case 'h': 884 default: 885 usage(); 886 break; 887 } 888 } 889 890 if (iface == NULL) 891 usage(); 892 893 /* Check interface is wireless. Will not return on error */ 894 wi_checkwifi(iface); 895 896 for (table = wi_tables; *table != NULL; table++) 897 for (wt = *table; wt->wi_code != WI_NONE; wt++) 898 if (wt->wi_optval != NULL) { 899 switch (wt->wi_code) { 900 case WI_BOOL: 901 case WI_WORDS: 902 wi_setword(iface, wt->wi_type, 903 atoi(wt->wi_optval)); 904 break; 905 case WI_STRING: 906 wi_setstr(iface, wt->wi_type, 907 wt->wi_optval); 908 break; 909 case WI_HEXBYTES: 910 wi_sethex(iface, wt->wi_type, 911 wt->wi_optval); 912 break; 913 } 914 } 915 916 if (dumpstats) 917 wi_dumpstats(iface); 918 if (dumpinfo) 919 wi_dumpinfo(iface); 920 921 if (apscan) 922 #ifdef WI_RID_SCAN_APS 923 wi_apscan(iface); 924 #else 925 errx(1, "AP scan mode is not available."); 926 #endif 927 928 exit(0); 929 } 930