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