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