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