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