1/* 2 * wlc - Broadcom Wireless Driver Control Utility 3 * 4 * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <sys/types.h> 18#include <sys/stat.h> 19#include <unistd.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <fcntl.h> 24#include <glob.h> 25#include <ctype.h> 26 27#include <typedefs.h> 28#include <wlutils.h> 29#include <proto/802.11.h> 30 31#define VERSION "0.1" 32#define BUFSIZE 8192 33#define PTABLE_MAGIC 0xbadc0ded 34#define PTABLE_SLT1 1 35#define PTABLE_SLT2 2 36#define PTABLE_ACKW 3 37#define PTABLE_ADHM 4 38#define PTABLE_END 0xffffffff 39 40/* 41 * Copy each token in wordlist delimited by space into word 42 * Taken from Broadcom shutils.h 43 */ 44#define foreach(word, wordlist, next) \ 45 for (next = &wordlist[strspn(wordlist, " ")], \ 46 strncpy(word, next, sizeof(word)), \ 47 word[strcspn(word, " ")] = '\0', \ 48 word[sizeof(word) - 1] = '\0', \ 49 next = strchr(next, ' '); \ 50 strlen(word); \ 51 next = next ? &next[strspn(next, " ")] : "", \ 52 strncpy(word, next, sizeof(word)), \ 53 word[strcspn(word, " ")] = '\0', \ 54 word[sizeof(word) - 1] = '\0', \ 55 next = strchr(next, ' ')) 56 57static char wlbuf[8192]; 58static char interface[16] = "wl0"; 59static unsigned long kmem_offset = 0; 60static int vif = 0, debug = 1, fromstdin = 0; 61 62typedef enum { 63 NONE = 0x00, 64 65 /* types */ 66 PARAM_TYPE = 0x00f, 67 INT = 0x001, 68 STRING = 0x002, 69 MAC = 0x003, 70 71 /* options */ 72 PARAM_OPTIONS = 0x0f0, 73 NOARG = 0x010, 74 75 /* modes */ 76 PARAM_MODE = 0xf00, 77 GET = 0x100, 78 SET = 0x200, 79} wlc_param; 80 81struct wlc_call { 82 const char *name; 83 wlc_param param; 84 int (*handler)(wlc_param param, void *data, void *value); 85 union { 86 int num; 87 char *str; 88 void *ptr; 89 } data; 90 const char *desc; 91}; 92 93/* can't use the system include because of the stupid broadcom header files */ 94extern struct ether_addr *ether_aton(const char *asc); 95static inline int my_ether_ntoa(unsigned char *ea, char *buf) 96{ 97 return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 98 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); 99} 100 101static int wlc_ioctl(wlc_param param, void *data, void *value) 102{ 103 unsigned int *var = ((unsigned int *) data); 104 unsigned int ioc = *var; 105 106 if (param & NOARG) { 107 return wl_ioctl(interface, ioc, NULL, 0); 108 } 109 switch(param & PARAM_TYPE) { 110 case MAC: 111 return wl_ioctl(interface, ((param & SET) ? (ioc) : (ioc >> 16)) & 0xffff, value, 6); 112 case INT: 113 return wl_ioctl(interface, ((param & SET) ? (ioc) : (ioc >> 16)) & 0xffff, value, sizeof(int)); 114 case STRING: 115 return wl_ioctl(interface, ((param & SET) ? (ioc) : (ioc >> 16)) & 0xffff, value, BUFSIZE); 116 } 117 return 0; 118} 119 120static int wlc_iovar(wlc_param param, void *data, void *value) 121{ 122 int *val = (int *) value; 123 char *iov = *((char **) data); 124 int ret = 0; 125 126 if (param & SET) { 127 switch(param & PARAM_TYPE) { 128 case INT: 129 ret = wl_iovar_setint(interface, iov, *val); 130 break; 131 case MAC: 132 ret = wl_iovar_set(interface, iov, value, 6); 133 break; 134 } 135 } 136 if (param & GET) { 137 switch(param & PARAM_TYPE) { 138 case INT: 139 ret = wl_iovar_get(interface, iov, val, sizeof(int)); 140 break; 141 case MAC: 142 ret = wl_iovar_get(interface, iov, value, 6); 143 break; 144 } 145 } 146 147 return ret; 148} 149 150static int wlc_bssiovar(wlc_param param, void *data, void *value) 151{ 152 int *val = (int *) value; 153 char *iov = *((char **) data); 154 int ret = 0; 155 156 if (param & SET) { 157 switch(param & PARAM_TYPE) { 158 case INT: 159 ret = wl_bssiovar_setint(interface, iov, vif, *val); 160 } 161 } 162 if (param & GET) { 163 switch(param & PARAM_TYPE) { 164 case INT: 165 ret = wl_bssiovar_get(interface, iov, vif, val, sizeof(int)); 166 } 167 } 168 169 return ret; 170} 171 172static int wlc_vif_enabled(wlc_param param, void *data, void *value) 173{ 174 int *val = (int *) value; 175 int buf[3]; 176 int ret = 0; 177 178 sprintf((char *) buf, "bss"); 179 buf[1] = vif; 180 if (param & SET) { 181 buf[2] = (*val ? 1 : 0); 182 ret = wl_ioctl(interface, WLC_SET_VAR, buf, sizeof(buf)); 183 } else if (param & GET) { 184 ret = wl_ioctl(interface, WLC_GET_VAR, buf, sizeof(buf)); 185 *val = buf[0]; 186 } 187 188 return ret; 189} 190 191static int wlc_ssid(wlc_param param, void *data, void *value) 192{ 193 int ret = -1, ret2 = -1; 194 char *dest = (char *) value; 195 wlc_ssid_t ssid; 196 197 if ((param & PARAM_MODE) == GET) { 198 ret = wl_bssiovar_get(interface, "ssid", vif, &ssid, sizeof(ssid)); 199 200 if (ret) 201 /* if we can't get the ssid through the bssiovar, try WLC_GET_SSID */ 202 ret = wl_ioctl(interface, WLC_GET_SSID, &ssid, sizeof(ssid)); 203 204 if (!ret) { 205 memcpy(dest, ssid.SSID, ssid.SSID_len); 206 dest[ssid.SSID_len] = 0; 207 } 208 } else if ((param & PARAM_MODE) == SET) { 209 strncpy(ssid.SSID, value, 32); 210 ssid.SSID_len = strlen(value); 211 212 if (ssid.SSID_len > 32) 213 ssid.SSID_len = 32; 214 215 if (vif == 0) { 216 /* for the main interface, also try the WLC_SET_SSID call */ 217 ret2 = wl_ioctl(interface, WLC_SET_SSID, &ssid, sizeof(ssid)); 218 } 219 220 ret = wl_bssiovar_set(interface, "ssid", vif, &ssid, sizeof(ssid)); 221 ret = (!ret2 ? 0 : ret); 222 } 223 224 return ret; 225} 226 227static int wlc_int(wlc_param param, void *data, void *value) 228{ 229 int *var = *((int **) data); 230 int *val = (int *) value; 231 232 if ((param & PARAM_MODE) == SET) { 233 *var = *val; 234 } else if ((param & PARAM_MODE) == GET) { 235 *val = *var; 236 } 237 238 return 0; 239} 240 241static int wlc_flag(wlc_param param, void *data, void *value) 242{ 243 int *var = *((int **) data); 244 245 *var = 1; 246 247 return 0; 248} 249 250static int wlc_string(wlc_param param, void *data, void *value) 251{ 252 char *var = *((char **) data); 253 254 if ((param & PARAM_MODE) == GET) { 255 strcpy(value, var); 256 } 257 258 return 0; 259} 260 261static int wlc_afterburner(wlc_param param, void *data, void *value) 262{ 263 int *val = (int *) value; 264 int ret = 0; 265 266 if ((param & PARAM_MODE) == GET) { 267 ret = wl_iovar_get(interface, "afterburner", val, sizeof(int)); 268 } else { 269 wl_iovar_setint(interface, "wlfeatureflag", (*val ? 3 : 0)); 270 ret = wl_iovar_setint(interface, "afterburner", (*val ? 1 : 0)); 271 wl_iovar_setint(interface, "afterburner_override", *val); 272 } 273 274 return ret; 275} 276 277static int wlc_maclist(wlc_param param, void *data, void *value) 278{ 279 unsigned int *var = ((unsigned int *) data); 280 unsigned int ioc = *var; 281 int limit = (sizeof(wlbuf) - 4) / sizeof(struct ether_addr); 282 struct maclist *list = (struct maclist *) wlbuf; 283 char *str = (char *) value; 284 char astr[30], *p; 285 struct ether_addr *addr; 286 int isset = 0; 287 int ret; 288 289 if ((param & PARAM_MODE) == GET) { 290 list->count = limit; 291 ret = wl_ioctl(interface, (ioc >> 16) & 0xffff, wlbuf, sizeof(wlbuf)); 292 293 if (!ret) 294 while (list->count) { 295 str += sprintf(str, "%s", ((((char *) value) == str) ? "" : " ")); 296 str += my_ether_ntoa((unsigned char *) &list->ea[list->count-- - 1], str); 297 } 298 299 return ret; 300 } else { 301 while (*str && isspace(*str)) 302 *str++; 303 304 if (*str == '+') { 305 str++; 306 307 list->count = limit; 308 if (wl_ioctl(interface, (ioc >> 16) & 0xffff, wlbuf, sizeof(wlbuf)) == 0) 309 isset = 1; 310 311 while (*str && isspace(*str)) 312 str++; 313 } 314 315 if (!isset) 316 memset(wlbuf, 0, sizeof(wlbuf)); 317 318 foreach(astr, str, p) { 319 if (list->count >= limit) 320 break; 321 322 if ((addr = ether_aton(astr)) != NULL) 323 memcpy(&list->ea[list->count++], addr, sizeof(struct ether_addr)); 324 } 325 326 return wl_ioctl(interface, ioc & 0xffff, wlbuf, sizeof(wlbuf)); 327 } 328} 329 330static int wlc_radio(wlc_param param, void *data, void *value) 331{ 332 int *val = (int *) value; 333 int ret; 334 335 if ((param & PARAM_MODE) == GET) { 336 ret = wl_ioctl(interface, WLC_GET_RADIO, val, sizeof(int)); 337 *val = ((*val & 1) ? 0 : 1); 338 } else { 339 *val = (1 << 16) | (*val ? 0 : 1); 340 ret = wl_ioctl(interface, WLC_SET_RADIO, val, sizeof(int)); 341 } 342 343 return ret; 344} 345 346static int wlc_wsec_key(wlc_param param, void *null, void *value) 347{ 348 wl_wsec_key_t wsec_key; 349 unsigned char *index = value; 350 unsigned char *key; 351 unsigned char *data; 352 unsigned char hex[3]; 353 354 if ((param & PARAM_MODE) != SET) 355 return 0; 356 357 memset(&wsec_key, 0, sizeof(wsec_key)); 358 if (index[0] == '=') { 359 wsec_key.flags = WL_PRIMARY_KEY; 360 index++; 361 } 362 363 if ((index[0] < '1') || (index[0] > '4') || (index[1] != ',')) 364 return -1; 365 366 key = index + 2; 367 if (strncmp(key, "d:", 2) == 0) { /* delete key */ 368 } else if (strncmp(key, "s:", 2) == 0) { /* ascii key */ 369 key += 2; 370 wsec_key.len = strlen(key); 371 372 if ((wsec_key.len != 5) && (wsec_key.len != 13)) 373 return -1; 374 375 strcpy(wsec_key.data, key); 376 } else { /* hex key */ 377 wsec_key.len = strlen(key); 378 if ((wsec_key.len != 10) && (wsec_key.len != 26)) 379 return -1; 380 381 wsec_key.len /= 2; 382 data = wsec_key.data; 383 hex[2] = 0; 384 do { 385 hex[0] = *(key++); 386 hex[1] = *(key++); 387 *(data++) = (unsigned char) strtoul(hex, NULL, 16); 388 } while (*key != 0); 389 } 390 391 return wl_bssiovar_set(interface, "wsec_key", vif, &wsec_key, sizeof(wsec_key)); 392} 393 394static int wlc_cap(wlc_param param, void *data, void *value) 395{ 396 char *iov = *((char **) data); 397 398 if (param & GET) 399 return wl_iovar_get(interface, iov, value, BUFSIZE); 400 401 return -1; 402} 403 404static int wlc_bssmax(wlc_param param, void *data, void *value) 405{ 406 int *val = (int *) value; 407 char *iov = *((char **) data); 408 int ret = -1; 409 410 if (param & GET) { 411 ret = wl_iovar_get(interface, iov, wlbuf, BUFSIZE); 412 if (!ret) { 413 if (strstr(wlbuf, "mbss4")) 414 *val = 4; 415 else if (strstr(wlbuf, "mbss16")) 416 *val = 16; 417 else 418 *val = 1; 419 } 420 } 421 422 return ret; 423} 424 425static inline int cw2ecw(int cw) 426{ 427 int i; 428 for (cw++, i = 0; cw; i++) cw >>=1; 429 return i - 1; 430} 431 432static int wlc_wme_ac(wlc_param param, void *data, void *value) 433{ 434 char *type = *((char **) data); 435 char *settings = (char *) value; 436 char cmd[100], *p, *val; 437 edcf_acparam_t params[AC_COUNT]; 438 int ret; 439 int intval; 440 int cur = -1; 441 char *buf = wlbuf; 442 443 if ((param & PARAM_MODE) != SET) 444 return -1; 445 446 memset(params, 0, sizeof(params)); 447 ret = wl_iovar_get(interface, type, params, sizeof(params)); 448 memset(buf, 0, BUFSIZE); 449 strcpy(buf, type); 450 buf += strlen(buf) + 1; 451 452 foreach(cmd, settings, p) { 453 val = strchr(cmd, '='); 454 if (val == NULL) { 455 if (strcmp(cmd, "be") == 0) 456 cur = AC_BE; 457 else if (strcmp(cmd, "bk") == 0) 458 cur = AC_BK; 459 else if (strcmp(cmd, "vi") == 0) 460 cur = AC_VI; 461 else if (strcmp(cmd, "vo") == 0) 462 cur = AC_VO; 463 else 464 return -1; 465 466 /* just in case */ 467 params[cur].ACI = (params[cur].ACI & (0x3 << 5)) | (cur << 5); 468 } else { 469 *(val++) = 0; 470 471 intval = strtoul(val, NULL, 10); 472 if (strcmp(cmd, "cwmin") == 0) 473 params[cur].ECW = (params[cur].ECW & ~(0xf)) | cw2ecw(intval); 474 else if (strcmp(cmd, "ecwmin") == 0) 475 params[cur].ECW = (params[cur].ECW & ~(0xf)) | (intval & 0xf); 476 else if (strcmp(cmd, "cwmax") == 0) 477 params[cur].ECW = (params[cur].ECW & ~(0xf << 4)) | (cw2ecw(intval) << 4); 478 else if (strcmp(cmd, "ecwmax") == 0) 479 params[cur].ECW = (params[cur].ECW & ~(0xf << 4)) | ((intval & 0xf) << 4); 480 else if (strcmp(cmd, "aifsn") == 0) 481 params[cur].ACI = (params[cur].ACI & ~(0xf)) | (intval & 0xf); 482 else if (strcmp(cmd, "txop") == 0) 483 params[cur].TXOP = intval >> 5; 484 else if (strcmp(cmd, "force") == 0) 485 params[cur].ACI = (params[cur].ACI & ~(1 << 4)) | ((intval) ? (1 << 4) : 0); 486 else return -1; 487 488 memcpy(buf, ¶ms[cur], sizeof(edcf_acparam_t)); 489 wl_ioctl(interface, WLC_SET_VAR, wlbuf, BUFSIZE); 490 } 491 } 492 return ret; 493} 494 495static int wlc_ifname(wlc_param param, void *data, void *value) 496{ 497 char *val = (char *) value; 498 int ret = 0; 499 500 if (param & SET) { 501 if (strlen(val) < 16) 502 strcpy(interface, val); 503 else ret = -1; 504 } 505 if (param & GET) { 506 strcpy(val, interface); 507 } 508 509 return ret; 510} 511 512static int wlc_wdsmac(wlc_param param, void *data, void *value) 513{ 514 unsigned char mac[6]; 515 int ret = 0; 516 517 ret = wl_ioctl(interface, WLC_WDS_GET_REMOTE_HWADDR, &mac, 6); 518 if (ret == 0) 519 my_ether_ntoa(mac, value); 520 521 return ret; 522} 523 524static int wlc_pmk(wlc_param param, void *data, void *value) 525{ 526 int ret = -1; 527 char *str = (char *) value; 528 wsec_pmk_t pmk; 529 530 /* driver doesn't support GET */ 531 532 if ((param & PARAM_MODE) == SET) { 533 strncpy(pmk.key, str, WSEC_MAX_PSK_LEN); 534 pmk.key_len = strlen(str); 535 536 if (pmk.key_len > WSEC_MAX_PSK_LEN) 537 pmk.key_len = WSEC_MAX_PSK_LEN; 538 539 pmk.flags = WSEC_PASSPHRASE; 540 541 ret = wl_ioctl(interface, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); 542 } 543 544 return ret; 545} 546 547static const struct wlc_call wlc_calls[] = { 548 { 549 .name = "version", 550 .param = STRING|NOARG, 551 .handler = wlc_string, 552 .data.str = VERSION, 553 .desc = "Version of this program" 554 }, 555 { 556 .name = "debug", 557 .param = INT, 558 .handler = wlc_int, 559 .data.ptr = &debug, 560 .desc = "wlc debug level" 561 }, 562 { 563 .name = "stdin", 564 .param = NOARG, 565 .handler = wlc_flag, 566 .data.ptr = &fromstdin, 567 .desc = "Accept input from stdin" 568 }, 569 { 570 .name = "ifname", 571 .param = STRING, 572 .handler = wlc_ifname, 573 .desc = "interface to send commands to" 574 }, 575 { 576 .name = "up", 577 .param = NOARG, 578 .handler = wlc_ioctl, 579 .data.num = WLC_UP, 580 .desc = "Bring the interface up" 581 }, 582 { 583 .name = "down", 584 .param = NOARG, 585 .handler = wlc_ioctl, 586 .data.num = WLC_DOWN, 587 .desc = "Bring the interface down" 588 }, 589 { 590 .name = "radio", 591 .param = INT, 592 .handler = wlc_radio, 593 .desc = "Radio enabled flag" 594 }, 595 { 596 .name = "ap", 597 .param = INT, 598 .handler = wlc_ioctl, 599 .data.num = ((WLC_GET_AP << 16) | WLC_SET_AP), 600 .desc = "Access Point mode" 601 }, 602 { 603 .name = "mssid", 604 .param = INT, 605 .handler = wlc_iovar, 606 .data.str = "mbss", 607 .desc = "Multi-ssid mode" 608 }, 609 { 610 .name = "apsta", 611 .param = INT, 612 .handler = wlc_iovar, 613 .data.str = "apsta", 614 .desc = "AP+STA mode" 615 }, 616 { 617 .name = "infra", 618 .param = INT, 619 .handler = wlc_ioctl, 620 .data.num = ((WLC_GET_INFRA << 16) | WLC_SET_INFRA), 621 .desc = "Infrastructure mode" 622 }, 623 { 624 .name = "wet", 625 .param = INT, 626 .handler = wlc_ioctl, 627 .data.num = ((WLC_GET_WET << 16) | WLC_SET_WET), 628 .desc = "Wireless repeater mode", 629 }, 630 { 631 .name = "statimeout", 632 .param = INT, 633 .handler = wlc_iovar, 634 .data.str = "sta_retry_time", 635 .desc = "STA connection timeout" 636 }, 637 { 638 .name = "country", 639 .param = STRING, 640 .handler = wlc_ioctl, 641 .data.num = ((WLC_GET_COUNTRY << 16) | WLC_SET_COUNTRY), 642 .desc = "Country code" 643 }, 644 { 645 .name = "channel", 646 .param = INT, 647 .handler = wlc_ioctl, 648 .data.num = ((WLC_GET_CHANNEL << 16) | WLC_SET_CHANNEL), 649 .desc = "Channel", 650 }, 651 { 652 .name = "vlan_mode", 653 .param = INT, 654 .handler = wlc_bssiovar, 655 .data.str = "vlan_mode", 656 .desc = "Parse 802.1Q tags", 657 }, 658 { 659 .name = "vif", 660 .param = INT, 661 .handler = wlc_int, 662 .data.ptr = &vif, 663 .desc = "Current vif index" 664 }, 665 { 666 .name = "enabled", 667 .param = INT, 668 .handler = wlc_vif_enabled, 669 .desc = "vif enabled flag" 670 }, 671 { 672 .name = "ssid", 673 .param = STRING, 674 .handler = wlc_ssid, 675 .desc = "Interface ESSID" 676 }, 677 { 678 .name = "closed", 679 .param = INT, 680 .handler = wlc_bssiovar, 681 .data.str = "closednet", 682 .desc = "Hidden ESSID flag" 683 }, 684 { 685 .name = "wsec", 686 .param = INT, 687 .handler = wlc_bssiovar, 688 .data.str = "wsec", 689 .desc = "Security mode flags" 690 }, 691 { 692 .name = "wepkey", 693 .param = STRING, 694 .handler = wlc_wsec_key, 695 .desc = "Set/Remove WEP keys" 696 }, 697 { 698 .name = "wepauth", 699 .param = INT, 700 .handler = wlc_ioctl, 701 .data.num = ((WLC_GET_AUTH << 16) | WLC_SET_AUTH), 702 .desc = "WEP authentication type. 0 = OpenSystem, 1 = SharedKey" 703 }, 704 { 705 .name = "wsec_restrict", 706 .param = INT, 707 .handler = wlc_bssiovar, 708 .data.str = "wsec_restrict", 709 .desc = "Drop unencrypted traffic" 710 }, 711 { 712 .name = "eap_restrict", 713 .param = INT, 714 .handler = wlc_bssiovar, 715 .data.str = "eap_restrict", 716 .desc = "Only allow 802.1X traffic until 802.1X authorized" 717 }, 718 { 719 .name = "wpa_auth", 720 .param = INT, 721 .handler = wlc_bssiovar, 722 .data.str = "wpa_auth", 723 .desc = "WPA authentication modes" 724 }, 725 { 726 .name = "ap_isolate", 727 .param = INT, 728 .handler = wlc_bssiovar, 729 .data.str = "ap_isolate", 730 .desc = "Isolate connected clients" 731 }, 732 { 733 .name = "supplicant", 734 .param = INT, 735 .handler = wlc_iovar, 736 .data.str = "sup_wpa", 737 .desc = "Built-in WPA supplicant" 738 }, 739 { 740 .name = "passphrase", 741 .param = STRING, 742 .handler = wlc_pmk, 743 .desc = "Passphrase for built-in WPA supplicant", 744 }, 745 { 746 .name = "maxassoc", 747 .param = INT, 748 .handler = wlc_iovar, 749 .data.str = "maxassoc", 750 .desc = "Max. number of associated clients", 751 }, 752 { 753 .name = "wme", 754 .param = INT, 755 .handler = wlc_iovar, 756 .data.str = "wme", 757 .desc = "WME enabled" 758 }, 759 { 760 .name = "wme_ac_ap", 761 .param = STRING, 762 .handler = wlc_wme_ac, 763 .data.str = "wme_ac_ap", 764 .desc = "Set WME AC options for AP mode", 765 }, 766 { 767 .name = "wme_ac_sta", 768 .param = STRING, 769 .handler = wlc_wme_ac, 770 .data.str = "wme_ac_sta", 771 .desc = "Set WME AC options for STA mode", 772 }, 773 { 774 .name = "wme_noack", 775 .param = INT, 776 .handler = wlc_iovar, 777 .data.str = "wme_noack", 778 .desc = "WME ACK disable request", 779 }, 780 { 781 .name = "802.11d", 782 .param = INT, 783 .handler = wlc_ioctl, 784 .data.num = ((WLC_GET_REGULATORY << 16) | WLC_SET_REGULATORY), 785 .desc = "Enable/disable 802.11d regulatory management", 786 }, 787 { 788 .name = "802.11h", 789 .param = INT, 790 .handler = wlc_ioctl, 791 .data.num = ((WLC_GET_SPECT_MANAGMENT << 16) | WLC_SET_SPECT_MANAGMENT), 792 .desc = "Enable/disable 802.11h spectrum management", 793 }, 794 { 795 .name = "fragthresh", 796 .param = INT, 797 .handler = wlc_iovar, 798 .data.str = "fragthresh", 799 .desc = "Fragmentation threshold", 800 }, 801 { 802 .name = "rtsthresh", 803 .param = INT, 804 .handler = wlc_iovar, 805 .data.str = "rtsthresh", 806 .desc = "RTS threshold" 807 }, 808 { 809 .name = "slottime", 810 .param = INT, 811 .handler = wlc_iovar, 812 .data.str = "acktiming", 813 .desc = "Slot time" 814 }, 815 { 816 .name = "rxant", 817 .param = INT, 818 .handler = wlc_ioctl, 819 .data.num = ((WLC_GET_ANTDIV << 16) | WLC_SET_ANTDIV), 820 .desc = "Rx antenna selection" 821 }, 822 { 823 .name = "txant", 824 .param = INT, 825 .handler = wlc_ioctl, 826 .data.num = ((WLC_GET_TXANT << 16) | WLC_SET_TXANT), 827 .desc = "Tx antenna selection" 828 }, 829 { 830 .name = "dtim", 831 .param = INT, 832 .handler = wlc_ioctl, 833 .data.num = ((WLC_GET_DTIMPRD << 16) | WLC_SET_DTIMPRD), 834 .desc = "DTIM period", 835 }, 836 { 837 .name = "bcn", 838 .param = INT, 839 .handler = wlc_ioctl, 840 .data.num = ((WLC_GET_BCNPRD << 16) | WLC_SET_BCNPRD), 841 .desc = "Beacon interval" 842 }, 843 { 844 .name = "frameburst", 845 .param = INT, 846 .handler = wlc_ioctl, 847 .data.num = ((WLC_GET_FAKEFRAG << 16) | WLC_SET_FAKEFRAG), 848 .desc = "Framebursting" 849 }, 850 { 851 .name = "monitor", 852 .param = INT, 853 .handler = wlc_ioctl, 854 .data.num = ((WLC_GET_MONITOR << 16) | WLC_SET_MONITOR), 855 .desc = "Monitor mode" 856 }, 857 { 858 .name = "passive_scan", 859 .param = INT, 860 .handler = wlc_ioctl, 861 .data.num = ((WLC_GET_PASSIVE_SCAN << 16) | WLC_SET_PASSIVE_SCAN), 862 .desc = "Passive scan mode" 863 }, 864 { 865 .name = "macfilter", 866 .param = INT, 867 .handler = wlc_ioctl, 868 .data.num = ((WLC_GET_MACMODE << 16) | WLC_SET_MACMODE), 869 .desc = "MAC filter mode (0:disabled, 1:deny, 2:allow)" 870 }, 871 { 872 .name = "maclist", 873 .param = STRING, 874 .data.num = ((WLC_GET_MACLIST << 16) | WLC_SET_MACLIST), 875 .handler = wlc_maclist, 876 .desc = "MAC filter list" 877 }, 878 { 879 .name = "autowds", 880 .param = INT, 881 .handler = wlc_ioctl, 882 .data.num = ((WLC_GET_LAZYWDS << 16) | WLC_SET_LAZYWDS), 883 .desc = "Automatic WDS" 884 }, 885 { 886 .name = "wds", 887 .param = STRING, 888 .data.num = ((WLC_GET_WDSLIST << 16) | WLC_SET_WDSLIST), 889 .handler = wlc_maclist, 890 .desc = "WDS connection list" 891 }, 892 { 893 .name = "wdstimeout", 894 .param = INT, 895 .handler = wlc_iovar, 896 .data.str = "wdstimeout", 897 .desc = "WDS link detection timeout" 898 }, 899 { 900 .name = "wdsmac", 901 .param = STRING|NOARG, 902 .handler = wlc_wdsmac, 903 .desc = "MAC of the remote WDS endpoint (only with wds0.* interfaces)" 904 }, 905 { 906 .name = "afterburner", 907 .param = INT, 908 .handler = wlc_afterburner, 909 .desc = "Broadcom Afterburner" 910 }, 911 { 912 .name = "ibss_merge", 913 .param = INT, 914 .handler = wlc_iovar, 915 .data.str = "ibss_coalesce_allowed", 916 .desc = "Allow IBSS merges" 917 }, 918 { 919 .name = "bssid", 920 .param = MAC, 921 .handler = wlc_ioctl, 922 .data.num = ((WLC_GET_BSSID << 16) | WLC_SET_BSSID), 923 .desc = "BSSID" 924 }, 925 { 926 .name = "cur_etheraddr", 927 .param = MAC, 928 .handler = wlc_iovar, 929 .data.str = "cur_etheraddr", 930 .desc = "Current MAC Address" 931 }, 932 { 933 .name = "default_bssid", 934 .param = MAC, 935 .handler = wlc_iovar, 936 .data.str = "perm_etheraddr", 937 .desc = "Default BSSID (read-only)" 938 }, 939 { 940 .name = "assoclist", 941 .param = STRING, 942 .data.num = (WLC_GET_ASSOCLIST << 16), 943 .handler = wlc_maclist, 944 .desc = "MACs of associated stations" 945 }, 946 { 947 .name = "gmode", 948 .param = INT, 949 .data.num = ((WLC_GET_GMODE << 16) | WLC_SET_GMODE), 950 .handler = wlc_ioctl, 951 .desc = "G Mode" 952 }, 953 { 954 .name = "phytype", 955 .param = INT, 956 .data.num = (WLC_GET_PHYTYPE << 16), 957 .handler = wlc_ioctl, 958 .desc = "PHY Type (read-only)" 959 }, 960 { 961 .name = "nmode", 962 .param = INT, 963 .handler = wlc_iovar, 964 .data.str = "nmode", 965 .desc = "N Mode" 966 }, 967 { 968 .name = "nreqd", 969 .param = INT, 970 .handler = wlc_iovar, 971 .data.str = "nreqd", 972 .desc = "N Mode required" 973 }, 974 { 975 .name = "chanspec", 976 .param = INT, 977 .handler = wlc_iovar, 978 .data.str = "chanspec", 979 .desc = "Channel Spec (See bcmwifi.h)" 980 }, 981 { 982 .name = "band", 983 .param = INT, 984 .data.num = ((WLC_GET_BAND << 16) | WLC_SET_BAND), 985 .handler = wlc_ioctl, 986 .desc = "Band (0=auto, 1=5Ghz, 2=2.4GHz)" 987 }, 988 { 989 .name = "cap", 990 .param = STRING|NOARG, 991 .handler = wlc_cap, 992 .data.str = "cap", 993 .desc = "Capabilities" 994 }, 995 { 996 .name = "bssmax", 997 .param = INT|NOARG, 998 .handler = wlc_bssmax, 999 .data.str = "cap", 1000 .desc = "Number of VIF's supported" 1001 }, 1002 { 1003 .name = "leddc", 1004 .param = INT, 1005 .handler = wlc_iovar, 1006 .data.str = "leddc", 1007 .desc = "LED Duty Cycle" 1008 }, 1009 1010}; 1011#define wlc_calls_size (sizeof(wlc_calls) / sizeof(struct wlc_call)) 1012 1013static void usage(char *cmd) 1014{ 1015 int i; 1016 fprintf(stderr, "Usage: %s <command> [<argument> ...]\n" 1017 "\n" 1018 "Available commands:\n", cmd); 1019 for (i = 0; i < wlc_calls_size; i++) { 1020 fprintf(stderr, "\t%-16s\t%s\n", wlc_calls[i].name ?: "", wlc_calls[i].desc ?: ""); 1021 } 1022 fprintf(stderr, "\n"); 1023 exit(1); 1024} 1025 1026static int do_command(const struct wlc_call *cmd, char *arg) 1027{ 1028 static char buf[BUFSIZE]; 1029 int set; 1030 int ret = 0; 1031 char *format, *end; 1032 int intval; 1033 void *ptr = (void *) buf; 1034 1035 if (debug >= 10) { 1036 fprintf(stderr, "do_command %-16s\t'%s'\n", cmd->name, arg); 1037 } 1038 1039 if ((arg == NULL) && ((cmd->param & PARAM_TYPE) != NONE)) { 1040 set = 0; 1041 ret = cmd->handler(cmd->param | GET, (void *) &cmd->data, (void *) buf); 1042 if (ret == 0) { 1043 switch(cmd->param & PARAM_TYPE) { 1044 case INT: 1045 intval = *((int *) buf); 1046 1047 if (intval > 65535) 1048 format = "0x%08x\n"; 1049 else if (intval > 255) 1050 format = "0x%04x\n"; 1051 else 1052 format = "%d\n"; 1053 1054 fprintf(stdout, format, intval); 1055 break; 1056 case STRING: 1057 fprintf(stdout, "%s\n", buf); 1058 break; 1059 case MAC: 1060 my_ether_ntoa(buf, buf + 6); 1061 fprintf(stdout, "%s\n", buf + 6); 1062 break; 1063 } 1064 } 1065 } else { /* SET */ 1066 set = 1; 1067 switch(cmd->param & PARAM_TYPE) { 1068 case INT: 1069 intval = strtoul(arg, &end, 0); 1070 if (end && !(*end)) { 1071 memcpy(buf, &intval, sizeof(intval)); 1072 } else { 1073 fprintf(stderr, "%s: Invalid argument\n", cmd->name); 1074 return -1; 1075 } 1076 break; 1077 case STRING: 1078 strncpy(buf, arg, BUFSIZE); 1079 buf[BUFSIZE - 1] = 0; 1080 break; 1081 case MAC: 1082 ptr = ether_aton(arg); 1083 if (!ptr) { 1084 fprintf(stderr, "%s: Invalid mac address '%s'\n", cmd->name, arg); 1085 return -1; 1086 } 1087 break; 1088 } 1089 1090 ret = cmd->handler(cmd->param | SET, (void *) &cmd->data, ptr); 1091 } 1092 1093 if ((debug > 0) && (ret != 0)) 1094 fprintf(stderr, "Command '%s %s' failed: %d\n", (set == 1 ? "set" : "get"), cmd->name, ret); 1095 1096 return ret; 1097} 1098 1099static struct wlc_call *find_cmd(char *name) 1100{ 1101 int found = 0, i = 0; 1102 1103 while (!found && (i < wlc_calls_size)) { 1104 if (strcmp(name, wlc_calls[i].name) == 0) 1105 found = 1; 1106 else 1107 i++; 1108 } 1109 1110 return (struct wlc_call *) (found ? &wlc_calls[i] : NULL); 1111} 1112 1113int main(int argc, char **argv) 1114{ 1115 static char buf[BUFSIZE]; 1116 char *s, *s2; 1117 char *cmd = argv[0]; 1118 struct wlc_call *call; 1119 int ret = 0; 1120 1121 if (argc < 2) 1122 usage(argv[0]); 1123 1124 for(interface[2] = '0'; (interface[2] < '3') && (wl_probe(interface) != 0); interface[2]++); 1125 if (interface[2] == '3') { 1126 fprintf(stderr, "No Broadcom wl interface found!\n"); 1127 return -1; 1128 } 1129 1130 argv++; 1131 argc--; 1132 while ((argc > 0) && (argv[0] != NULL)) { 1133 if ((call = find_cmd(argv[0])) == NULL) { 1134 fprintf(stderr, "Invalid command: %s\n\n", argv[0]); 1135 usage(cmd); 1136 } 1137 if ((argc > 1) && (!(call->param & NOARG))) { 1138 ret = do_command(call, argv[1]); 1139 argv += 2; 1140 argc -= 2; 1141 } else { 1142 ret = do_command(call, NULL); 1143 argv++; 1144 argc--; 1145 } 1146 } 1147 1148 while (fromstdin && !feof(stdin)) { 1149 *buf = 0; 1150 fgets(buf, BUFSIZE - 1, stdin); 1151 1152 if (*buf == 0) 1153 continue; 1154 1155 if ((s = strchr(buf, '\r')) != NULL) 1156 *s = 0; 1157 if ((s = strchr(buf, '\n')) != NULL) 1158 *s = 0; 1159 1160 s = buf; 1161 while (isspace(*s)) 1162 s++; 1163 1164 if (!*s) 1165 continue; 1166 1167 if ((s2 = strchr(s, ' ')) != NULL) 1168 *(s2++) = 0; 1169 1170 while (s2 && isspace(*s2)) 1171 s2++; 1172 1173 if ((call = find_cmd(s)) == NULL) { 1174 fprintf(stderr, "Invalid command: %s\n", s); 1175 ret = -1; 1176 } else 1177 ret = do_command(call, ((call->param & NOARG) ? NULL : s2)); 1178 } 1179 1180 return ret; 1181} 1182