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