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