1/* 2 * Wireless Network Adapter Configuration Utility 3 * 4 * Copyright 2007, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; 8 * the contents of this file may not be disclosed to third parties, copied 9 * or duplicated in any form, in whole or in part, without the prior 10 * written permission of Broadcom Corporation. 11 * 12 * $Id: wlconf.c,v 1.1.1.1 2008/10/15 03:31:23 james26_jang Exp $ 13 */ 14 15#include <typedefs.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19#include <assert.h> 20#include <bcmnvram.h> 21#include <bcmutils.h> 22#include <bcmparams.h> 23#include <shutils.h> 24#include <wlutils.h> 25 26/* phy types */ 27#define PHY_TYPE_A 0 28#define PHY_TYPE_B 1 29#define PHY_TYPE_G 2 30#define PHY_TYPE_N 4 31#define PHY_TYPE_LP 5 32#define PHY_TYPE_NULL 0xf 33 34/* how many times to attempt to bring up a virtual i/f when 35 * we are in APSTA mode and IOVAR set of "bss" "up" returns busy 36 */ 37#define MAX_BSS_UP_RETRIES 5 38 39/* notify the average dma xfer rate (in kbps) to the driver */ 40#define AVG_DMA_XFER_RATE 120000 41 42/* parts of an idcode: */ 43#define IDCODE_MFG_MASK 0x00000fff 44#define IDCODE_MFG_SHIFT 0 45#define IDCODE_ID_MASK 0x0ffff000 46#define IDCODE_ID_SHIFT 12 47#define IDCODE_REV_MASK 0xf0000000 48#define IDCODE_REV_SHIFT 28 49 50/* 51 * Debugging Macros 52 */ 53#define WLCONF_DBG(fmt, arg...) 54#define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len)) 55#define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val)) 56#define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval)) 57#define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \ 58 param, paramlen)) 59#define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val)) 60#define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val)) 61#define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \ 62 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen)) 63#define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \ 64 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen)) 65#define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \ 66 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen)) 67#define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \ 68 bssidx, val)) 69 70#ifdef BCMWPA2 71#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK)) 72#else 73#define CHECK_PSK(mode) ((mode) & WPA_AUTH_PSK) 74#endif 75 76/* prototypes */ 77struct bsscfg_list *wlconf_get_bsscfgs(char* ifname, char* prefix); 78int wlconf(char *name); 79int wlconf_down(char *name); 80 81int wlconf_ssid(void); 82int wlconf_set_ssid(char *tmpssid); 83int wlconf_txant(char *var); 84int wlconf_antdiv(char *var); 85int wlconf_radio(char *act); 86int wlconf_auth(char *act); 87int wlconf_wsec(char *var); 88int wlconf_wpa_auth(char *var); 89int wlconf_eap(char *var); 90int wlconf_rate(char *var); 91int wlconf_led(void); 92int wlconf_set_led(char *tmpssid); 93 94static int 95wlconf_getint(char* ifname, int cmd, int *pval) 96{ 97 return wl_ioctl(ifname, cmd, pval, sizeof(int)); 98} 99 100static int 101wlconf_setint(char* ifname, int cmd, int val) 102{ 103 return wl_ioctl(ifname, cmd, &val, sizeof(int)); 104} 105 106static int 107wlconf_wds_clear(char *name) 108{ 109 struct maclist maclist; 110 int ret; 111 112 maclist.count = 0; 113 WL_IOCTL(name, WLC_SET_WDSLIST, &maclist, sizeof(maclist)); 114 115 return ret; 116} 117 118/* set WEP key */ 119static int 120wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i) 121{ 122 wl_wsec_key_t key; 123 char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX"; 124 char *keystr, hex[] = "XX"; 125 unsigned char *data = key.data; 126 int ret = 0; 127 128 memset(&key, 0, sizeof(key)); 129 key.index = i - 1; 130 sprintf(wl_key, "%skey%d", prefix, i); 131 keystr = nvram_safe_get(wl_key); 132 133 switch (strlen(keystr)) { 134 case WEP1_KEY_SIZE: 135 case WEP128_KEY_SIZE: 136 key.len = strlen(keystr); 137 strcpy((char *)key.data, keystr); 138 break; 139 case WEP1_KEY_HEX_SIZE: 140 case WEP128_KEY_HEX_SIZE: 141 key.len = strlen(keystr) / 2; 142 while (*keystr) { 143 strncpy(hex, keystr, 2); 144 *data++ = (unsigned char) strtoul(hex, NULL, 16); 145 keystr += 2; 146 } 147 break; 148 default: 149 key.len = 0; 150 break; 151 } 152 153 /* Set current WEP key */ 154 if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key)))) 155 key.flags = WL_PRIMARY_KEY; 156 157 WL_BSSIOVAR_SET(name, "wsec_key", bsscfg_idx, &key, sizeof(key)); 158 159 return ret; 160} 161 162extern struct nvram_tuple router_defaults[]; 163 164/* validate/restore all per-interface related variables */ 165static void 166wlconf_validate_all(char *prefix, bool restore) 167{ 168 struct nvram_tuple *t; 169 char tmp[100]; 170 char *v; 171 for (t = router_defaults; t->name; t++) { 172 if (!strncmp(t->name, "wl_", 3)) { 173 strcat_r(prefix, &t->name[3], tmp); 174 if (!restore && nvram_get(tmp)) 175 continue; 176 v = nvram_get(t->name); 177 nvram_set(tmp, v ? v : t->value); 178 } 179 } 180} 181 182/* restore specific per-interface variable */ 183static void 184wlconf_restore_var(char *prefix, char *name) 185{ 186 struct nvram_tuple *t; 187 char tmp[100]; 188 for (t = router_defaults; t->name; t++) { 189 if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) { 190 nvram_set(strcat_r(prefix, name, tmp), t->value); 191 break; 192 } 193 } 194} 195static int 196wlconf_akm_options(char *prefix) 197{ 198 char comb[32]; 199 char *wl_akm; 200 int akm_ret_val = 0; 201 char akm[32]; 202 char *next; 203 204 wl_akm = nvram_safe_get(strcat_r(prefix, "akm", comb)); 205 foreach(akm, wl_akm, next) { 206 if (!strcmp(akm, "wpa")) 207 akm_ret_val |= WPA_AUTH_UNSPECIFIED; 208 if (!strcmp(akm, "psk")) 209 akm_ret_val |= WPA_AUTH_PSK; 210#ifdef BCMWPA2 211 if (!strcmp(akm, "wpa2")) 212 akm_ret_val |= WPA2_AUTH_UNSPECIFIED; 213 if (!strcmp(akm, "psk2")) 214 akm_ret_val |= WPA2_AUTH_PSK; 215 if (!strcmp(akm, "brcm_psk")) 216 akm_ret_val |= BRCM_AUTH_PSK; 217#endif 218 } 219 return akm_ret_val; 220} 221 222/* Set up wsec */ 223static int 224wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx) 225{ 226 char tmp[100]; 227 int val = 0; 228 int akm_val; 229 int ret; 230 231 /* Set wsec bitvec */ 232 akm_val = wlconf_akm_options(prefix); 233 if (akm_val != 0) { 234 if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip")) 235 val = TKIP_ENABLED; 236 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes")) 237 val = AES_ENABLED; 238 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes")) 239 val = TKIP_ENABLED | AES_ENABLED; 240 } 241 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) 242 val |= WEP_ENABLED; 243 WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val); 244 /* Set wsec restrict if WSEC_ENABLED */ 245 WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0); 246 247 return 0; 248} 249 250#ifdef BCMWPA2 251static int 252wlconf_set_preauth(char *name, int bsscfg_idx, int preauth) 253{ 254 uint cap; 255 int ret; 256 257 WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint)); 258 if (ret != 0) return -1; 259 260 if (preauth) 261 cap |= WPA_CAP_WPA2_PREAUTH; 262 else 263 cap &= ~WPA_CAP_WPA2_PREAUTH; 264 265 WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap); 266 267 return ret; 268} 269#endif /* BCMWPA2 */ 270 271static void 272wlconf_set_radarthrs(char *name, char *prefix) 273{ 274 wl_radar_thr_t radar_thr; 275 int i, ret, len; 276 char nv_buf[NVRAM_MAX_VALUE_LEN], *rargs, *v, *endptr; 277 char buf[WLC_IOCTL_SMLEN]; 278 char *version = NULL, *thr0_20_lo = NULL, *thr1_20_lo = NULL, *thr0_40_lo = NULL; 279 char *thr1_40_lo = NULL, *thr0_20_hi = NULL, *thr1_20_hi = NULL, *thr0_40_hi = NULL; 280 char *thr1_40_hi = NULL; 281 char **locals[] = { &version, &thr0_20_lo, &thr1_20_lo, &thr0_40_lo, &thr1_40_lo, 282 &thr0_20_hi, &thr1_20_hi, &thr0_40_hi, &thr1_40_hi }; 283 284 rargs = nvram_safe_get(strcat_r(prefix, "radarthrs", nv_buf)); 285 if (!rargs) 286 goto err; 287 288 len = strlen(rargs); 289 if ((len > NVRAM_MAX_VALUE_LEN) || (len == 0)) 290 goto err; 291 292 memset(nv_buf, 0, sizeof(nv_buf)); 293 strncpy(nv_buf, rargs, len); 294 v = nv_buf; 295 for (i = 0; i < (sizeof(locals) / sizeof(locals[0])); i++) { 296 *locals[i] = v; 297 while (*v && *v != ' ') { 298 v++; 299 } 300 if (*v) { 301 *v = 0; 302 v++; 303 } 304 if (v >= (nv_buf + len)) /* Check for complete list, if not caught later */ 305 break; 306 } 307 308 /* Start building request */ 309 memset(buf, 0, sizeof(buf)); 310 strcpy(buf, "radarthrs"); 311 /* Retrieve radar thrs parameters */ 312 if (!version) 313 goto err; 314 radar_thr.version = atoi(version); 315 if (radar_thr.version > WL_RADAR_THR_VERSION) 316 goto err; 317 318 /* Retrieve ver 0 params */ 319 if (!thr0_20_lo) 320 goto err; 321 radar_thr.thresh0_20_lo = (uint16)strtol(thr0_20_lo, &endptr, 0); 322 if (*endptr != '\0') 323 goto err; 324 325 if (!thr1_20_lo) 326 goto err; 327 radar_thr.thresh1_20_lo = (uint16)strtol(thr1_20_lo, &endptr, 0); 328 if (*endptr != '\0') 329 goto err; 330 331 if (!thr0_40_lo) 332 goto err; 333 radar_thr.thresh0_40_lo = (uint16)strtol(thr0_40_lo, &endptr, 0); 334 if (*endptr != '\0') 335 goto err; 336 337 if (!thr1_40_lo) 338 goto err; 339 radar_thr.thresh1_40_lo = (uint16)strtol(thr1_40_lo, &endptr, 0); 340 if (*endptr != '\0') 341 goto err; 342 343 if (radar_thr.version == 0) { 344 /* 345 * Attempt a best effort update of ver 0 to ver 1 by updating 346 * the appropriate values with the specified defaults. The defaults 347 * are from the reference design. 348 */ 349 radar_thr.version = WL_RADAR_THR_VERSION; /* avoid driver rejecting it */ 350 radar_thr.thresh0_20_hi = 0x6ac; 351 radar_thr.thresh1_20_hi = 0x6cc; 352 radar_thr.thresh0_40_hi = 0x6bc; 353 radar_thr.thresh1_40_hi = 0x6e0; 354 } else { 355 /* Retrieve ver 1 params */ 356 if (!thr0_20_hi) 357 goto err; 358 radar_thr.thresh0_20_hi = (uint16)strtol(thr0_20_hi, &endptr, 0); 359 if (*endptr != '\0') 360 goto err; 361 362 if (!thr1_20_hi) 363 goto err; 364 radar_thr.thresh1_20_hi = (uint16)strtol(thr1_20_hi, &endptr, 0); 365 if (*endptr != '\0') 366 goto err; 367 368 if (!thr0_40_hi) 369 goto err; 370 radar_thr.thresh0_40_hi = (uint16)strtol(thr0_40_hi, &endptr, 0); 371 if (*endptr != '\0') 372 goto err; 373 374 if (!thr1_40_hi) 375 goto err; 376 radar_thr.thresh1_40_hi = (uint16)strtol(thr1_40_hi, &endptr, 0); 377 if (*endptr != '\0') 378 goto err; 379 } 380 381 /* Copy radar parameters into buffer and plug them to the driver */ 382 memcpy((char*)(buf + strlen(buf) + 1), (char*)&radar_thr, sizeof(wl_radar_thr_t)); 383 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); 384 385 return; 386 387err: 388 WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n"); 389 return; 390} 391 392 393/* Set up WME */ 394static void 395wlconf_set_wme(char *name, char *prefix) 396{ 397 int i, j, k; 398 int val, ret; 399 int phytype, gmode, no_ack, apsd, dp[2]; 400 edcf_acparam_t *acparams; 401 /* Pay attention to buffer length requirements when using this */ 402 char buf[WLC_IOCTL_SMLEN]; 403 char *v, *nv_value, nv[100]; 404 char nv_name[] = "%swme_%s_%s"; 405 char *ac[] = {"be", "bk", "vi", "vo"}; 406 char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first; 407 char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced, 408 &oldest_first }; 409 struct {char *req; char *str;} mode[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"}, 410 {"wme_tx_params", "txp"}}; 411 412 /* query the phy type */ 413 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); 414 /* get gmode */ 415 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", nv))); 416 417 /* WME sta setting first */ 418 for (i = 0; i < 2; i++) { 419 /* build request block */ 420 memset(buf, 0, sizeof(buf)); 421 strcpy(buf, mode[i].req); 422 /* put push wmeac params after "wme-ac" in buf */ 423 acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1); 424 dp[i] = 0; 425 for (j = 0; j < AC_COUNT; j++) { 426 /* get packed nvram parameter */ 427 snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]); 428 nv_value = nvram_safe_get(nv); 429 strcpy(nv, nv_value); 430 /* unpack it */ 431 v = nv; 432 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) { 433 *locals[k] = v; 434 while (*v && *v != ' ') 435 v++; 436 if (*v) { 437 *v = 0; 438 v++; 439 } 440 } 441 442 /* update CWmin */ 443 acparams->ECW &= ~EDCF_ECWMIN_MASK; 444 val = atoi(cwmin); 445 for (val++, k = 0; val; val >>= 1, k++); 446 acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK; 447 /* update CWmax */ 448 acparams->ECW &= ~EDCF_ECWMAX_MASK; 449 val = atoi(cwmax); 450 for (val++, k = 0; val; val >>= 1, k++); 451 acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK; 452 /* update AIFSN */ 453 acparams->ACI &= ~EDCF_AIFSN_MASK; 454 acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK; 455 /* update ac */ 456 acparams->ACI &= ~EDCF_ACI_MASK; 457 acparams->ACI |= j << EDCF_ACI_SHIFT; 458 /* update TXOP */ 459 if (phytype == PHY_TYPE_B || gmode == 0) 460 val = atoi(txop_b); 461 else 462 val = atoi(txop_ag); 463 acparams->TXOP = val / 32; 464 /* update acm */ 465 acparams->ACI &= ~EDCF_ACM_MASK; 466 val = strcmp(admin_forced, "on") ? 0 : 1; 467 acparams->ACI |= val << 4; 468 469 /* configure driver */ 470 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); 471 } 472 } 473 474 /* set no-ack */ 475 v = nvram_safe_get(strcat_r(prefix, "wme_no_ack", nv)); 476 no_ack = strcmp(v, "on") ? 0 : 1; 477 WL_IOVAR_SETINT(name, "wme_noack", no_ack); 478 479 /* set APSD */ 480 v = nvram_safe_get(strcat_r(prefix, "wme_apsd", nv)); 481 apsd = strcmp(v, "on") ? 0 : 1; 482 WL_IOVAR_SETINT(name, "wme_apsd", apsd); 483 484 /* set per-AC discard policy */ 485 strcpy(buf, "wme_dp"); 486 WL_IOVAR_SETINT(name, "wme_dp", dp[1]); 487 488 /* WME Tx parameters setting */ 489 { 490 wme_tx_params_t txparams[AC_COUNT]; 491 char *srl, *sfbl, *lrl, *lfbl, *maxrate; 492 char **locals[] = { &srl, &sfbl, &lrl, &lfbl, &maxrate }; 493 494 /* build request block */ 495 memset(txparams, 0, sizeof(txparams)); 496 497 for (j = 0; j < AC_COUNT; j++) { 498 /* get packed nvram parameter */ 499 snprintf(nv, sizeof(nv), nv_name, prefix, mode[2].str, ac[j]); 500 nv_value = nvram_safe_get(nv); 501 strcpy(nv, nv_value); 502 /* unpack it */ 503 v = nv; 504 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) { 505 *locals[k] = v; 506 while (*v && *v != ' ') 507 v++; 508 if (*v) { 509 *v = 0; 510 v++; 511 } 512 } 513 514 /* update short retry limit */ 515 txparams[j].short_retry = atoi(srl); 516 517 /* update short fallback limit */ 518 txparams[j].short_fallback = atoi(sfbl); 519 520 /* update long retry limit */ 521 txparams[j].long_retry = atoi(lrl); 522 523 /* update long fallback limit */ 524 txparams[j].long_fallback = atoi(lfbl); 525 526 /* update max rate */ 527 txparams[j].max_rate = atoi(maxrate); 528 } 529 530 /* set the WME tx parameters */ 531 WL_IOVAR_SET(name, mode[2].req, txparams, sizeof(txparams)); 532 } 533 534 return; 535} 536 537#if defined(linux) 538#include <unistd.h> 539static void 540sleep_ms(const unsigned int ms) 541{ 542 usleep(1000*ms); 543} 544#else 545#error "sleep_ms() not defined for this OS!!!" 546#endif /* defined(linux) */ 547 548/* 549* The following condition(s) must be met when Auto Channel Selection 550* is enabled. 551* - the I/F is up (change radio channel requires it is up?) 552* - the AP must not be associated (setting SSID to empty should 553* make sure it for us) 554*/ 555static uint8 556wlconf_auto_channel(char *name) 557{ 558 int chosen = 0; 559 wl_uint32_list_t request; 560 int phytype; 561 int ret; 562 int i; 563 564 /* query the phy type */ 565 WL_GETINT(name, WLC_GET_PHYTYPE, &phytype); 566 567 request.count = 0; /* let the ioctl decide */ 568 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request)); 569 if (!ret) { 570 sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750); 571 for (i = 0; i < 100; i++) { 572 WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen); 573 if (!ret) 574 break; 575 sleep_ms(100); 576 } 577 } 578 WLCONF_DBG("interface %s: channel selected %d\n", name, chosen); 579 return chosen; 580} 581 582static chanspec_t 583wlconf_auto_chanspec(char *name) 584{ 585 chanspec_t chosen = 0; 586 wl_uint32_list_t request; 587 int bandtype; 588 int ret; 589 int i; 590 591 /* query the band type */ 592 WL_GETINT(name, WLC_GET_BAND, &bandtype); 593 594 request.count = 0; /* let the ioctl decide */ 595 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request)); 596 if (!ret) { 597 sleep_ms(1000); 598 for (i = 0; i < 100; i++) { 599 WL_IOVAR_GETINT(name, "apcschspec", (void *)&chosen); 600 if (!ret) 601 break; 602 sleep_ms(100); 603 } 604 } 605 WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen); 606 return chosen; 607} 608 609/* PHY type/BAND conversion */ 610#define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G) 611/* PHY type conversion */ 612#define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \ 613 (phy) == PHY_TYPE_B ? "b" : \ 614 (phy) == PHY_TYPE_LP ? "l" : \ 615 (phy) == PHY_TYPE_G ? "g" : "n") 616#define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \ 617 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \ 618 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \ 619 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N) 620 621#define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */ 622 623struct bsscfg_info { 624 int idx; /* bsscfg index */ 625 char ifname[PREFIX_LEN]; /* OS name of interface (debug only) */ 626 char prefix[PREFIX_LEN]; /* prefix for nvram params (eg. "wl0.1_") */ 627}; 628 629struct bsscfg_list { 630 int count; 631 struct bsscfg_info bsscfgs[WL_MAXBSSCFG]; 632}; 633 634struct bsscfg_list * 635wlconf_get_bsscfgs(char* ifname, char* prefix) 636{ 637 char var[80]; 638 char tmp[100]; 639 char *next; 640 641 struct bsscfg_list *bclist; 642 struct bsscfg_info *bsscfg; 643 644 bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list)); 645 if (bclist == NULL) 646 return NULL; 647 memset(bclist, 0, sizeof(struct bsscfg_list)); 648 649 /* Set up Primary BSS Config information */ 650 bsscfg = &bclist->bsscfgs[0]; 651 bsscfg->idx = 0; 652 strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1); 653 strcpy(bsscfg->prefix, prefix); 654 bclist->count = 1; 655 656 /* additional virtual BSS Configs from wlX_vifs */ 657 foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) { 658 if (bclist->count == WL_MAXBSSCFG) { 659 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)" 660 "in nvram %s\n" 661 "while configuring interface \"%s\"\n", 662 ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var); 663 continue; 664 } 665 bsscfg = &bclist->bsscfgs[bclist->count]; 666 if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) { 667 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface " 668 "name \"%s\"\n", 669 ifname, var); 670 continue; 671 } 672 strncpy(bsscfg->ifname, var, PREFIX_LEN-1); 673 snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname); 674 bclist->count++; 675 } 676 677 return bclist; 678} 679 680static void 681wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool id_supp) 682{ 683 int i; 684 int val; 685 int ret; 686 char tmp[100]; 687 688 /* Set WSEC */ 689 /* 690 * Need to check errors (card may have changed) and change to 691 * defaults since the new chip may not support the requested 692 * encryptions after the card has been changed. 693 */ 694 if (wlconf_set_wsec(name, prefix, bsscfg_idx)) { 695 /* change nvram only, code below will pass them on */ 696 wlconf_restore_var(prefix, "auth_mode"); 697 wlconf_restore_var(prefix, "auth"); 698 /* reset wep to default */ 699 wlconf_restore_var(prefix, "crypto"); 700 wlconf_restore_var(prefix, "wep"); 701 wlconf_set_wsec(name, prefix, bsscfg_idx); 702 } 703 704 val = wlconf_akm_options(prefix); 705 /* enable in-driver wpa supplicant? */ 706 if (id_supp && (CHECK_PSK(val))) { 707 wsec_pmk_t psk; 708 char *key; 709 710 if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) && 711 (strlen(key) < WSEC_MAX_PSK_LEN)) { 712 psk.key_len = (ushort) strlen(key); 713 psk.flags = WSEC_PASSPHRASE; 714 strcpy((char *)psk.key, key); 715 WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); 716 } 717 wl_iovar_setint(name, "sup_wpa", 1); 718 } 719 WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val); 720 721 /* EAP Restrict if we have an AKM or radius authentication */ 722 val = ((val != 0) || (nvram_match(strcat_r(prefix, "auth_mode", tmp), "radius"))); 723 WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val); 724 725 /* Set WEP keys */ 726 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) { 727 for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++) 728 wlconf_set_wep_key(name, prefix, bsscfg_idx, i); 729 } 730 731 /* Set 802.11 authentication mode - open/shared */ 732 val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp))); 733 WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val); 734} 735 736/* 737 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled 738 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any 739 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off, 740 * afterburner is enabled/disabled based on the nvram settings. 741 * 742 * WME/WMM is also set in this procedure as it depends on N and afterburner. 743 * N ==> WMM is on by default 744 * N (or ampdu) ==> afterburner is off 745 * WMM ==> afterburner is off 746 * 747 * Returns whether afterburner is on in the system. 748 */ 749static int 750wlconf_aburn_ampdu_amsdu_set(char *name, char prefix[PREFIX_LEN], int nmode, int btc_mode) 751{ 752 bool ampdu_valid_option = FALSE; 753 bool amsdu_valid_option = FALSE; 754 bool aburn_valid_option = FALSE; 755 int val, aburn_option_val = OFF, ampdu_option_val = OFF, amsdu_option_val = OFF; 756 int wme_option_val = ON; /* On by default */ 757 char tmp[100], var[80], *next, *wme_val; 758 char buf[WLC_IOCTL_SMLEN]; 759 int ret; 760 761 /* First, clear WMM and afterburner settings to avoid conflicts */ 762 WL_IOVAR_SETINT(name, "wme", OFF); 763 WL_IOVAR_SETINT(name, "afterburner_override", OFF); 764 765 /* Get WME setting from NVRAM if present */ 766 wme_val = nvram_get(strcat_r(prefix, "wme", tmp)); 767 if (wme_val && !strcmp(wme_val, "off")) { 768 wme_option_val = OFF; 769 } 770 771 /* Set options based on capability */ 772 wl_iovar_get(name, "cap", (void *)tmp, 100); 773 foreach(var, tmp, next) { 774 char *nvram_str = nvram_get(strcat_r(prefix, var, buf)); 775 776 if (!nvram_str) 777 continue; 778 779 if (!strcmp(nvram_str, "on")) 780 val = ON; 781 else if (!strcmp(nvram_str, "off")) 782 val = OFF; 783 else if (!strcmp(nvram_str, "auto")) 784 val = AUTO; 785 else 786 continue; 787 788 if (btc_mode != WL_BTC_PREMPT && strncmp(var, "afterburner", sizeof(var)) == 0) { 789 aburn_valid_option = TRUE; 790 aburn_option_val = val; 791 } 792 793 if (strncmp(var, "ampdu", sizeof(var)) == 0) { 794 ampdu_valid_option = TRUE; 795 ampdu_option_val = val; 796 } 797 798 if (strncmp(var, "amsdu", sizeof(var)) == 0) { 799 amsdu_valid_option = TRUE; 800 amsdu_option_val = val; 801 } 802 } 803 804 if (nmode != OFF) { /* N-mode is ON/AUTO */ 805 806 if (aburn_valid_option) { /* Turn off afterburner in N-mode */ 807 WL_IOVAR_SETINT(name, "afterburner_override", OFF); 808 } 809 810 if (ampdu_valid_option) { 811 if (ampdu_option_val != OFF) { 812 WL_IOVAR_SETINT(name, "amsdu", OFF); 813 WL_IOVAR_SETINT(name, "ampdu", ampdu_option_val); 814 } else { 815 WL_IOVAR_SETINT(name, "ampdu", OFF); 816 } 817 } 818 819 if (amsdu_valid_option) { 820 if (amsdu_option_val != OFF) { /* AMPDU (above) has priority over AMSDU */ 821 if (ampdu_option_val == OFF) { 822 WL_IOVAR_SETINT(name, "ampdu", OFF); 823 WL_IOVAR_SETINT(name, "amsdu", amsdu_option_val); 824 } 825 } else 826 WL_IOVAR_SETINT(name, "amsdu", OFF); 827 } 828 } else { 829 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU; 830 * if WME is off, set the afterburner based on the configured nvram setting. 831 */ 832 wl_iovar_setint(name, "amsdu", OFF); 833 wl_iovar_setint(name, "ampdu", OFF); 834 if (wme_option_val != OFF) { /* Can't have afterburner with WMM */ 835 if (aburn_valid_option) { 836 WL_IOVAR_SETINT(name, "afterburner_override", OFF); 837 } 838 } else if (aburn_valid_option) { /* Okay, use NVRam setting for afterburner */ 839 WL_IOVAR_SETINT(name, "afterburner_override", aburn_option_val); 840 } 841 } 842 843 if (wme_option_val) { 844 WL_IOVAR_SETINT(name, "wme", wme_option_val); 845 wlconf_set_wme(name, prefix); 846 } 847 848 return wme_option_val; 849} 850 851#define VIFNAME_LEN 16 852 853/* configure the specified wireless interface */ 854int 855wlconf(char *name) 856{ 857 int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0; 858 int bcmerr; 859 int error_bg, error_a; 860 struct bsscfg_list *bclist = NULL; 861 struct bsscfg_info *bsscfg; 862 char tmp[100], prefix[PREFIX_LEN]; 863 char var[80], *next, phy[] = "a", *str, *addr = NULL; 864 /* Pay attention to buffer length requirements when using this */ 865 char buf[WLC_IOCTL_SMLEN]; 866 char *country; 867 wlc_rev_info_t rev; 868 channel_info_t ci; 869 struct maclist *maclist; 870 struct ether_addr *ea; 871 wlc_ssid_t ssid; 872 wl_rateset_t rs; 873 unsigned int i; 874 char eaddr[32]; 875 int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0; 876 char country_code[4]; 877 int nas_will_run = 0; 878 char *ba; 879#ifdef BCMWPA2 880 char *preauth; 881 int set_preauth; 882#endif 883 int ii; 884 int wlunit = -1; 885 int wlsubunit = -1; 886 int wl_ap_build = 0; /* wl compiled with AP capabilities */ 887 char cap[WLC_IOCTL_SMLEN]; 888 char caps[WLC_IOCTL_SMLEN]; 889 int btc_mode; 890 uint32 leddc; 891 uint nbw = WL_CHANSPEC_BW_20; 892 int nmode = OFF; /* 802.11n support */ 893 char vif_addr[WLC_IOCTL_SMLEN]; 894 int max_no_vifs = 0; 895 int wme_global; 896 int max_assoc = -1; 897 bool ure_enab = FALSE; 898 bool radar_enab = FALSE; 899 900 /* wlconf doesn't work for virtual i/f, so if we are given a 901 * virtual i/f return 0 if that interface is in it's parent's "vifs" 902 * list otherwise return -1 903 */ 904 if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0) 905 { 906 if (wlsubunit >= 0) 907 { 908 /* we have been given a virtual i/f, 909 * is it in it's parent i/f's virtual i/f list? 910 */ 911 sprintf(tmp, "wl%d_vifs", wlunit); 912 913 if (strstr(nvram_safe_get(tmp), name) == NULL) 914 return -1; /* config error */ 915 else 916 return 0; /* okay */ 917 } 918 } 919 else 920 { 921 return -1; 922 } 923 924 /* clean up tmp */ 925 memset(tmp, 0, sizeof(tmp)); 926 927 /* because of ifdefs in wl driver, when we don't have AP capabilities we 928 * can't use the same iovars to configure the wl. 929 * so we use "wl_ap_build" to help us know how to configure the driver 930 */ 931 if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN)) 932 return -1; 933 934 foreach(cap, caps, next) { 935 if (!strcmp(cap, "ap")) { 936 wl_ap_build = 1; 937 } 938 else if (!strcmp(cap, "mbss16")) 939 max_no_vifs = 16; 940 else if (!strcmp(cap, "mbss4")) 941 max_no_vifs = 4; 942 } 943 944 /* Check interface (fail silently for non-wl interfaces) */ 945 if ((ret = wl_probe(name))) 946 return ret; 947 948 /* Get MAC address */ 949 (void) wl_hwaddr(name, (uchar *)buf); 950 memcpy(vif_addr, buf, ETHER_ADDR_LEN); 951 952 /* Get instance */ 953 WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit)); 954 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 955 956 /* Restore defaults if per-interface parameters do not exist */ 957 restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp)); 958 wlconf_validate_all(prefix, restore_defaults); 959 nvram_set(strcat_r(prefix, "ifname", tmp), name); 960 nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr)); 961 snprintf(buf, sizeof(buf), "%d", unit); 962 nvram_set(strcat_r(prefix, "unit", tmp), buf); 963 964 965 /* Bring the interface down */ 966 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); 967 968 /* Disable all BSS Configs */ 969 for (i = 0; i < WL_MAXBSSCFG; i++) { 970 struct {int bsscfg_idx; int enable;} setbuf; 971 setbuf.bsscfg_idx = i; 972 setbuf.enable = 0; 973 974 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf)); 975 if (ret) { 976 wl_iovar_getint(name, "bcmerror", &bcmerr); 977 /* fail quietly on a range error since the driver may 978 * support fewer bsscfgs than we are prepared to configure 979 */ 980 if (bcmerr == BCME_RANGE) 981 break; 982 } 983 if (ret) 984 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0" 985 " (down) failed, ret = %d, bcmerr = %d\n", 986 __LINE__, name, i, ret, bcmerr); 987 } 988 989 /* Get the list of BSS Configs */ 990 bclist = wlconf_get_bsscfgs(name, prefix); 991 if (bclist == NULL) { 992 ret = -1; 993 goto exit; 994 } 995 996 997 /* create a wlX.Y_ifname nvram setting */ 998 for (i = 1; i < bclist->count; i++) { 999 bsscfg = &bclist->bsscfgs[i]; 1000#if defined(linux) 1001 strcpy(var, bsscfg->ifname); 1002#endif 1003 nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var); 1004 } 1005 1006 /* If ure_disable is not present or is 1, ure is not enabled; 1007 * that is, if it is present and 0, ure is enabled. 1008 */ 1009 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */ 1010 ure_enab = TRUE; 1011 } 1012 if (wl_ap_build) { 1013 /* Enable MBSS mode if appropriate */ 1014 if (!ure_enab) { 1015 WL_IOVAR_SETINT(name, "mbss", (bclist->count > 1)); 1016 } 1017 1018 /* 1019 * Set SSID for each BSS Config 1020 */ 1021 for (i = 0; i < bclist->count; i++) { 1022 bsscfg = &bclist->bsscfgs[i]; 1023 strcat_r(bsscfg->prefix, "ssid", tmp); 1024 ssid.SSID_len = strlen(nvram_safe_get(tmp)); 1025 if (ssid.SSID_len > sizeof(ssid.SSID)) 1026 ssid.SSID_len = sizeof(ssid.SSID); 1027 strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len); 1028 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) " 1029 "with SSID \"%s\"\n", name, bsscfg->idx, 1030 bsscfg->ifname, nvram_safe_get(tmp)); 1031 WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, 1032 sizeof(ssid)); 1033 } 1034 } 1035 1036 /* Create addresses for VIFs */ 1037 if (!ure_enab) { 1038 /* set local bit for our MBSS vif base */ 1039 ETHER_SET_LOCALADDR(vif_addr); 1040 1041 /* construct and set other wlX.Y_hwaddr */ 1042 for (i = 1; i < max_no_vifs; i++) { 1043 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i); 1044 addr = nvram_safe_get(tmp); 1045 if (!strcmp(addr, "")) { 1046 vif_addr[5] = (vif_addr[5] & ~(max_no_vifs-1)) 1047 | ((max_no_vifs-1) & (vif_addr[5]+1)); 1048 1049 nvram_set(tmp, ether_etoa((uchar *)vif_addr, 1050 eaddr)); 1051 } 1052 } 1053 /* The addresses are available in NVRAM, so set them */ 1054 for (i = 1; i < max_no_vifs; i++) { 1055 snprintf(tmp, sizeof(tmp), "wl%d.%d_bss_enabled", 1056 unit, i); 1057 if (!strcmp(nvram_safe_get(tmp), "1")) { 1058 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", 1059 unit, i); 1060 ether_atoe(nvram_safe_get(tmp), eaddr); 1061 WL_BSSIOVAR_SET(name, "cur_etheraddr", i, 1062 eaddr, ETHER_ADDR_LEN); 1063 } 1064 } 1065 } else { /* URE is enabled */ 1066 /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */ 1067 snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit); 1068 WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr, 1069 ETHER_ADDR_LEN); 1070 nvram_set(tmp, ether_etoa((uchar *)vif_addr, eaddr)); 1071 } 1072 1073 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */ 1074 str = nvram_safe_get(strcat_r(prefix, "mode", tmp)); 1075 ap = (!strcmp(str, "") || !strcmp(str, "ap")); 1076 apsta = (!strcmp(str, "apsta") || 1077 ((!strcmp(str, "sta") || !strcmp(str, "wet")) && 1078 bclist->count > 1)); 1079 sta = (!strcmp(str, "sta") && bclist->count == 1); 1080 wds = !strcmp(str, "wds"); 1081 wet = !strcmp(str, "wet"); 1082 mac_spoof = !strcmp(str, "mac_spoof"); 1083 1084 /* Set AP mode */ 1085 val = (ap || apsta || wds) ? 1 : 0; 1086 WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val)); 1087 1088 WL_IOVAR_SETINT(name, "apsta", apsta); 1089 1090 /* Set mode: WET */ 1091 if (wet) 1092 WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet)); 1093 1094 if (mac_spoof) { 1095 sta = 1; 1096 WL_IOVAR_SETINT(name, "mac_spoof", 1); 1097 } 1098 1099 /* For STA configurations, configure association retry time. 1100 * Use specified time (capped), or mode-specific defaults. 1101 */ 1102 if (sta || wet || apsta) { 1103 char *retry_time = nvram_safe_get(strcat_r(prefix, "sta_retry_time", tmp)); 1104 val = atoi(retry_time); 1105 WL_IOVAR_SETINT(name, "sta_retry_time", val); 1106 } 1107 1108 /* Retain remaining WET effects only if not APSTA */ 1109 wet &= !apsta; 1110 1111 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */ 1112 val = 1; 1113 if (wet || sta) 1114 val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp))); 1115 WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val)); 1116 1117 /* Set The AP MAX Associations Limit */ 1118 if (ap | apsta) { 1119 max_assoc = val = atoi(nvram_safe_get(strcat_r(prefix, "maxassoc", tmp))); 1120 if (val > 0) { 1121 WL_IOVAR_SETINT(name, "maxassoc", val); 1122 } else { /* Get value from driver if not in nvram */ 1123 WL_IOVAR_GETINT(name, "maxassoc", &max_assoc); 1124 } 1125 } 1126 1127 for (i = 0; i < bclist->count; i++) { 1128 char *subprefix; 1129 bsscfg = &bclist->bsscfgs[i]; 1130 1131#ifdef BCMWPA2 1132 /* XXXMBSS: The note about setting preauth now does not seem right. 1133 * NAS brings the BSS up if it runs, so setting the preauth value 1134 * will make it in the bcn/prb. If that is right, we can move this 1135 * chunk out of wlconf. 1136 */ 1137 /* 1138 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down 1139 * if we do it in the NAS we need to bring down the interface and up to make 1140 * it affect in the beacons 1141 */ 1142 if (ap || (apsta && bsscfg->idx != 0)) { 1143 set_preauth = 1; 1144 preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp)); 1145 if (strlen (preauth) != 0) { 1146 set_preauth = atoi(preauth); 1147 } 1148 wlconf_set_preauth(name, bsscfg->idx, set_preauth); 1149 } 1150#endif /* BCMWPA2 */ 1151 1152 subprefix = apsta ? prefix : bsscfg->prefix; 1153 1154 if (ap || (apsta && bsscfg->idx != 0)) { 1155 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "bss_maxassoc", tmp))); 1156 if (val > 0) { 1157 WL_BSSIOVAR_SETINT(name, "bss_maxassoc", bsscfg->idx, val); 1158 } else if (max_assoc > 0) { /* Set maxassoc same as global if not set */ 1159 snprintf(var, sizeof(var), "%d", max_assoc); 1160 nvram_set(tmp, var); 1161 } 1162 } 1163 1164 /* Set network type */ 1165 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "closed", tmp))); 1166 WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val); 1167 1168 /* Set the ap isolate mode */ 1169 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "ap_isolate", tmp))); 1170 WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val); 1171 } 1172 1173 /* Set up the country code */ 1174 (void) strcat_r(prefix, "country_code", tmp); 1175 country = nvram_get(tmp); 1176 if (country && country[0] != '\0') { 1177 strncpy(country_code, country, sizeof(country_code)); 1178 WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1); 1179 } else { 1180 /* Get the default country code if undefined */ 1181 WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code)); 1182 1183 /* Add the new NVRAM variable */ 1184 nvram_set("wl_country_code", country_code); 1185 (void) strcat_r(prefix, "country_code", tmp); 1186 nvram_set(tmp, country_code); 1187 } 1188 1189 /* Change LED Duty Cycle */ 1190 leddc = (uint32)strtoul(nvram_safe_get(strcat_r(prefix, "leddc", tmp)), NULL, 16); 1191 if (leddc) 1192 WL_IOVAR_SETINT(name, "leddc", leddc); 1193 1194 /* Enable or disable the radio */ 1195 val = nvram_match(strcat_r(prefix, "radio", tmp), "0"); 1196 val += WL_RADIO_SW_DISABLE << 16; 1197 WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val)); 1198 1199 /* Get supported phy types */ 1200 WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var)); 1201 nvram_set(strcat_r(prefix, "phytypes", tmp), var); 1202 1203 /* Get radio IDs */ 1204 *(next = buf) = '\0'; 1205 for (i = 0; i < strlen(var); i++) { 1206 /* Switch to band */ 1207 phy[0] = var[i]; 1208 val = WLCONF_STR2PHYTYPE(phy); 1209 if (val == PHY_TYPE_N) { 1210 WL_GETINT(name, WLC_GET_BAND, &val); 1211 } else 1212 val = WLCONF_PHYTYPE2BAND(val); 1213 WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val)); 1214 /* Get radio ID on this band */ 1215 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 1216 next += sprintf(next, "%sBCM%X", i ? " " : "", 1217 (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT); 1218 } 1219 nvram_set(strcat_r(prefix, "radioids", tmp), buf); 1220 1221 /* Set band */ 1222 str = nvram_get(strcat_r(prefix, "phytype", tmp)); 1223 val = WLCONF_STR2PHYTYPE(str); 1224 /* For NPHY use band value from NVRAM */ 1225 if (val == PHY_TYPE_N) { 1226 str = nvram_get(strcat_r(prefix, "nband", tmp)); 1227 if (str) 1228 val = atoi(str); 1229 else { 1230 WL_GETINT(name, WLC_GET_BAND, &val); 1231 } 1232 } else 1233 val = WLCONF_PHYTYPE2BAND(val); 1234 1235 WL_SETINT(name, WLC_SET_BAND, val); 1236 1237 /* Check errors (card may have changed) */ 1238 if (ret) { 1239 /* default band to the first band in band list */ 1240 phy[0] = var[0]; 1241 val = WLCONF_STR2PHYTYPE(phy); 1242 val = WLCONF_PHYTYPE2BAND(val); 1243 WL_SETINT(name, WLC_SET_BAND, val); 1244 } 1245 1246 /* Store the resolved bandtype */ 1247 bandtype = val; 1248 1249 /* Get current core revision */ 1250 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 1251 snprintf(buf, sizeof(buf), "%d", rev.corerev); 1252 nvram_set(strcat_r(prefix, "corerev", tmp), buf); 1253 1254 /* Get current phy type */ 1255 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); 1256 snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype)); 1257 nvram_set(strcat_r(prefix, "phytype", tmp), buf); 1258 1259 /* Setup regulatory mode */ 1260 strcat_r(prefix, "reg_mode", tmp); 1261 if (nvram_match(tmp, "off")) { 1262 val = 0; 1263 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); 1264 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); 1265 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); 1266 } else if (nvram_match(tmp, "h")) { 1267 val = 0; 1268 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); 1269 val = 1; 1270 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); 1271 radar_enab = TRUE; 1272 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); 1273 1274 /* Set the CAC parameters */ 1275 val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_preism", tmp))); 1276 wl_iovar_setint(name, "dfs_preism", val); 1277 val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_postism", tmp))); 1278 wl_iovar_setint(name, "dfs_postism", val); 1279 val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp))); 1280 WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val)); 1281 1282 } else if (nvram_match(tmp, "d")) { 1283 val = 0; 1284 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); 1285 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); 1286 val = 1; 1287 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); 1288 } 1289 1290 /* set bandwidth capability for nphy and calculate nbw */ 1291 if (phytype == PHY_TYPE_N) { 1292 /* Get the user nmode setting now */ 1293 nmode = AUTO; /* enable by default for NPHY */ 1294 /* Set n mode */ 1295 strcat_r(prefix, "nmode", tmp); 1296 if (nvram_match(tmp, "0")) 1297 nmode = OFF; 1298 1299 val = (nmode != OFF) ? atoi(nvram_safe_get(strcat_r(prefix, "nbw_cap", tmp))) : 1300 WLC_N_BW_20ALL; 1301 1302 WL_IOVAR_SETINT(name, "nmode", (uint32)nmode); 1303 WL_IOVAR_SETINT(name, "mimo_bw_cap", val); 1304 1305 if (((bandtype == WLC_BAND_2G) && (val == WLC_N_BW_40ALL)) || 1306 ((bandtype == WLC_BAND_5G) && 1307 (val == WLC_N_BW_40ALL || val == WLC_N_BW_20IN2G_40IN5G))) 1308 nbw = WL_CHANSPEC_BW_40; 1309 else 1310 nbw = WL_CHANSPEC_BW_20; 1311 } 1312 1313 /* Set channel before setting gmode or rateset */ 1314 /* Manual Channel Selection - when channel # is not 0 */ 1315 val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))); 1316 if (val && phytype != PHY_TYPE_N) { 1317 WL_SETINT(name, WLC_SET_CHANNEL, val); 1318 if (ret) { 1319 /* Use current channel (card may have changed) */ 1320 WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci)); 1321 snprintf(buf, sizeof(buf), "%d", ci.target_channel); 1322 nvram_set(strcat_r(prefix, "channel", tmp), buf); 1323 } 1324 } else if (val && phytype == PHY_TYPE_N) { 1325 chanspec_t chanspec = 0; 1326 uint channel; 1327 uint nctrlsb = WL_CHANSPEC_CTL_SB_NONE; 1328 1329 channel = val; 1330 1331 /* Get Ctrl SB for 40MHz channel */ 1332 if (nbw == WL_CHANSPEC_BW_40) { 1333 str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp)); 1334 1335 /* Adjust the channel to be center channel */ 1336 if (!strcmp(str, "lower")) { 1337 nctrlsb = WL_CHANSPEC_CTL_SB_LOWER; 1338 channel = channel + 2; 1339 } else if (!strcmp(str, "upper")) { 1340 nctrlsb = WL_CHANSPEC_CTL_SB_UPPER; 1341 channel = channel - 2; 1342 } 1343 } 1344 1345 /* band | BW | CTRL SB | Channel */ 1346 chanspec |= ((bandtype << WL_CHANSPEC_BAND_SHIFT) | 1347 (nbw | nctrlsb | channel)); 1348 1349 WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec); 1350 } 1351 1352 /* Set up number of Tx and Rx streams */ 1353 if (phytype == PHY_TYPE_N) { 1354 int count; 1355 int streams; 1356 1357 wl_iovar_getint(name, "txchain_cnt", &count); 1358 /* update NVRAM with capabilities */ 1359 snprintf(var, sizeof(var), "%d", count); 1360 nvram_set(strcat_r(prefix, "txchain_cnt", tmp), var); 1361 1362 /* Verify that there is an NVRAM param for txstreams, if not create it and 1363 * set it to txchain_cnt 1364 */ 1365 streams = atoi(nvram_safe_get(strcat_r(prefix, "txstreams", tmp))); 1366 if (streams == 0) { 1367 /* invalid - NVRAM needs to be fixed/initialized */ 1368 nvram_set(strcat_r(prefix, "txstreams", tmp), var); 1369 streams = count; 1370 } 1371 /* Apply user configured txstreams, use 1 if user disabled nmode */ 1372 if (nmode == OFF) 1373 streams = 1; 1374 WL_IOVAR_SETINT(name, "txstreams", streams); 1375 1376 wl_iovar_getint(name, "rxchain_cnt", &count); 1377 /* update NVRAM with capabilities */ 1378 snprintf(var, sizeof(var), "%d", count); 1379 nvram_set(strcat_r(prefix, "rxchain_cnt", tmp), var); 1380 1381 /* Verify that there is an NVRAM param for rxstreams, if not create it and 1382 * set it to txchain_cnt 1383 */ 1384 streams = atoi(nvram_safe_get(strcat_r(prefix, "rxstreams", tmp))); 1385 if (streams == 0) { 1386 /* invalid - NVRAM needs to be fixed/initialized */ 1387 nvram_set(strcat_r(prefix, "rxstreams", tmp), var); 1388 streams = count; 1389 } 1390 1391 /* Apply user configured rxstreams, use 1 if user disabled nmode */ 1392 if (nmode == OFF) 1393 streams = 1; 1394 WL_IOVAR_SETINT(name, "rxstreams", streams); 1395 } 1396 1397 /* Reset to hardware rateset (band may have changed) */ 1398 WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t)); 1399 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t)); 1400 1401 /* Set gmode */ 1402 if (bandtype == WLC_BAND_2G) { 1403 int override = WLC_G_PROTECTION_OFF; 1404 int control = WLC_G_PROTECTION_CTL_OFF; 1405 1406 /* Set gmode */ 1407 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp))); 1408 WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode)); 1409 1410 /* Set gmode protection override and control algorithm */ 1411 strcat_r(prefix, "gmode_protection", tmp); 1412 if (nvram_match(tmp, "auto")) { 1413 override = WLC_G_PROTECTION_AUTO; 1414 control = WLC_G_PROTECTION_CTL_OVERLAP; 1415 } 1416 WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override)); 1417 WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control)); 1418 } 1419 1420 /* Set nmode_protection */ 1421 if (phytype == PHY_TYPE_N) { 1422 int override = WLC_PROTECTION_OFF; 1423 int control = WLC_PROTECTION_CTL_OFF; 1424 1425 /* Set n protection override and control algorithm */ 1426 strcat_r(prefix, "nmode_protection", tmp); 1427 1428 if (nvram_match(tmp, "auto")) { 1429 override = WLC_PROTECTION_AUTO; 1430 control = WLC_PROTECTION_CTL_OVERLAP; 1431 } 1432 1433 WL_IOVAR_SETINT(name, "nmode_protection_override", 1434 (uint32)override); 1435 WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control)); 1436 } 1437 1438 /* Set 802.11n required */ 1439 if (nmode != OFF) { 1440 uint32 nreqd = OFF; /* default */ 1441 1442 strcat_r(prefix, "nreqd", tmp); 1443 1444 if (nvram_match(tmp, "1")) 1445 nreqd = ON; 1446 1447 WL_IOVAR_SETINT(name, "nreqd", nreqd); 1448 } 1449 1450 /* Set vlan_prio_mode */ 1451 { 1452 uint32 mode = OFF; /* default */ 1453 1454 strcat_r(prefix, "vlan_prio_mode", tmp); 1455 1456 if (nvram_match(tmp, "on")) 1457 mode = ON; 1458 1459 WL_IOVAR_SETINT(name, "vlan_mode", mode); 1460 } 1461 1462 /* Get bluetooth coexistance(BTC) mode */ 1463 btc_mode = atoi(nvram_safe_get(strcat_r(prefix, "btc_mode", tmp))); 1464 1465 /* Set the afterburner, AMPDU and AMSDU options based on the N-mode */ 1466 wme_global = wlconf_aburn_ampdu_amsdu_set(name, prefix, nmode, btc_mode); 1467 1468 /* Now that wme_global is known, check per-BSS disable settings */ 1469 for (i = 0; i < bclist->count; i++) { 1470 char *subprefix; 1471 bsscfg = &bclist->bsscfgs[i]; 1472 1473 subprefix = apsta ? prefix : bsscfg->prefix; 1474 1475 /* For each BSS, check WME; make sure wme is set properly for this interface */ 1476 strcat_r(subprefix, "wme", tmp); 1477 nvram_set(tmp, wme_global ? "on" : "off"); 1478 1479 str = nvram_safe_get(strcat_r(bsscfg->prefix, "wme_bss_disable", tmp)); 1480 val = (str[0] == '1') ? 1 : 0; 1481 WL_BSSIOVAR_SETINT(name, "wme_bss_disable", bsscfg->idx, val); 1482 } 1483 1484 1485 /* Get current rateset (gmode may have changed) */ 1486 WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof(wl_rateset_t)); 1487 1488 strcat_r(prefix, "rateset", tmp); 1489 if (nvram_match(tmp, "all")) { 1490 /* Make all rates basic */ 1491 for (i = 0; i < rs.count; i++) 1492 rs.rates[i] |= 0x80; 1493 } else if (nvram_match(tmp, "12")) { 1494 /* Make 1 and 2 basic */ 1495 for (i = 0; i < rs.count; i++) { 1496 if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4) 1497 rs.rates[i] |= 0x80; 1498 else 1499 rs.rates[i] &= ~0x80; 1500 } 1501 } 1502 1503 /* Set BTC mode */ 1504 if (!wl_iovar_setint(name, "btc_mode", btc_mode)) { 1505 if (btc_mode == WL_BTC_PREMPT) { 1506 wl_rateset_t rs_tmp = rs; 1507 /* remove 1Mbps and 2 Mbps from rateset */ 1508 for (i = 0, rs.count = 0; i < rs_tmp.count; i++) { 1509 if ((rs_tmp.rates[i] & 0x7f) == 2 || (rs_tmp.rates[i] & 0x7f) == 4) 1510 continue; 1511 rs.rates[rs.count++] = rs_tmp.rates[i]; 1512 } 1513 } 1514 } 1515 1516 /* Set rateset */ 1517 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t)); 1518 1519 /* Allow short preamble override for b cards */ 1520 if (phytype == PHY_TYPE_B || 1521 (phytype == PHY_TYPE_G && (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) { 1522 strcat_r(prefix, "plcphdr", tmp); 1523 if (nvram_match(tmp, "long")) 1524 val = WLC_PLCP_AUTO; 1525 else 1526 val = WLC_PLCP_SHORT; 1527 WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val)); 1528 } 1529 1530 /* Set rate in 500 Kbps units */ 1531 val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000; 1532 1533 /* Convert Auto mcsidx to Auto rate */ 1534 if (phytype == PHY_TYPE_N) { 1535 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp))); 1536 1537 /* -1 mcsidx used to designate AUTO rate */ 1538 if (mcsidx == -1) 1539 val = 0; 1540 } 1541 1542 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */ 1543 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4)) 1544 /* Must b/g band. Set to 5.5Mbps */ 1545 val = 11; 1546 1547 /* it is band-blind. try both band */ 1548 error_bg = wl_iovar_setint(name, "bg_rate", val); 1549 error_a = wl_iovar_setint(name, "a_rate", val); 1550 1551 if (error_bg && error_a) { 1552 /* both failed. Try default rate (card may have changed) */ 1553 val = 0; 1554 1555 error_bg = wl_iovar_setint(name, "bg_rate", val); 1556 error_a = wl_iovar_setint(name, "a_rate", val); 1557 1558 snprintf(buf, sizeof(buf), "%d", val); 1559 nvram_set(strcat_r(prefix, "rate", tmp), buf); 1560 } 1561 1562 /* check if nrate needs to be applied */ 1563 if (nmode != OFF) { 1564 uint32 nrate = 0; 1565 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp))); 1566 bool ismcs = (mcsidx >= 0); 1567 1568 /* mcsidx of 32 is valid only for 40 Mhz */ 1569 if (mcsidx == 32 && nbw == WL_CHANSPEC_BW_20) { 1570 mcsidx = -1; 1571 ismcs = FALSE; 1572 nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1"); 1573 } 1574 1575 /* Use nrate iovar only for MCS rate. */ 1576 if (ismcs) { 1577 nrate |= NRATE_MCS_INUSE; 1578 nrate |= mcsidx & NRATE_RATE_MASK; 1579 1580 WL_IOVAR_SETINT(name, "nrate", nrate); 1581 } 1582 } 1583 1584 /* Set multicast rate in 500 Kbps units */ 1585 val = atoi(nvram_safe_get(strcat_r(prefix, "mrate", tmp))) / 500000; 1586 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */ 1587 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4)) 1588 /* Must b/g band. Set to 5.5Mbps */ 1589 val = 11; 1590 1591 /* it is band-blind. try both band */ 1592 error_bg = wl_iovar_setint(name, "bg_mrate", val); 1593 error_a = wl_iovar_setint(name, "a_mrate", val); 1594 1595 if (error_bg && error_a) { 1596 /* Try default rate (card may have changed) */ 1597 val = 0; 1598 1599 wl_iovar_setint(name, "bg_mrate", val); 1600 wl_iovar_setint(name, "a_mrate", val); 1601 1602 snprintf(buf, sizeof(buf), "%d", val); 1603 nvram_set(strcat_r(prefix, "mrate", tmp), buf); 1604 } 1605 1606 /* Set fragmentation threshold */ 1607 val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp))); 1608 wl_iovar_setint(name, "fragthresh", val); 1609 1610 /* Set RTS threshold */ 1611 val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp))); 1612 wl_iovar_setint(name, "rtsthresh", val); 1613 1614 /* Set DTIM period */ 1615 val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp))); 1616 WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val)); 1617 1618 /* Set beacon period */ 1619 val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp))); 1620 WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val)); 1621 1622 /* Set framebursting mode */ 1623 if (btc_mode == WL_BTC_PREMPT) 1624 val = FALSE; 1625 else 1626 val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on"); 1627 WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val)); 1628 1629 /* Set RIFS mode based on framebursting */ 1630 if (phytype == PHY_TYPE_N) { 1631 char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp)); 1632 if (!strcmp(nvram_str, "on")) 1633 wl_iovar_setint(name, "rifs", ON); 1634 else if (!strcmp(nvram_str, "off")) 1635 wl_iovar_setint(name, "rifs", OFF); 1636 } 1637 1638 /* Override BA mode only if set to on/off */ 1639 ba = nvram_safe_get(strcat_r(prefix, "ba", tmp)); 1640 if (!strcmp(ba, "on")) 1641 wl_iovar_setint(name, "ba", ON); 1642 else if (!strcmp(ba, "off")) 1643 wl_iovar_setint(name, "ba", OFF); 1644 1645 if (phytype == PHY_TYPE_N) { 1646 val = AVG_DMA_XFER_RATE; 1647 wl_iovar_set(name, "avg_dma_xfer_rate", &val, sizeof(val)); 1648 } 1649 1650 /* Bring the interface back up */ 1651 WL_IOCTL(name, WLC_UP, NULL, 0); 1652 1653 /* Set antenna */ 1654 val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp))); 1655 WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val)); 1656 1657 /* Set radar parameters if it is enabled */ 1658 if (radar_enab) { 1659 wlconf_set_radarthrs(name, prefix); 1660 } 1661 1662 /* Auto Channel Selection - when channel # is 0 in AP mode 1663 * 1664 * The following condition(s) must be met in order for 1665 * Auto Channel Selection to work. 1666 * - the I/F must be up for the channel scan 1667 * - the AP must not be supporting a BSS (all BSS Configs must be disabled) 1668 */ 1669 if (ap || apsta) { 1670 if (!(val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))))) { 1671 if (phytype == PHY_TYPE_N) { 1672 chanspec_t chanspec = wlconf_auto_chanspec(name); 1673 if (chanspec != 0) 1674 WL_IOVAR_SETINT(name, "chanspec", chanspec); 1675 } 1676 else { 1677 /* select a channel */ 1678 val = wlconf_auto_channel(name); 1679 /* switch to the selected channel */ 1680 if (val != 0) 1681 WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val)); 1682 } 1683 /* set the auto channel scan timer in the driver when in auto mode */ 1684 val = 15; /* 15 minutes for now */ 1685 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val)); 1686 } 1687 else { 1688 /* reset the channel scan timer in the driver when not in auto mode */ 1689 val = 0; 1690 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val)); 1691 } 1692 } 1693 1694 /* Security settings for each BSS Configuration */ 1695 for (i = 0; i < bclist->count; i++) { 1696 bsscfg = &bclist->bsscfgs[i]; 1697 wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, mac_spoof); 1698 } 1699 1700 /* AP only config */ 1701 if (ap || apsta || wds) { 1702 /* Set lazy WDS mode */ 1703 val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp))); 1704 WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val)); 1705 1706 /* Set the WDS list */ 1707 maclist = (struct maclist *) buf; 1708 maclist->count = 0; 1709 ea = maclist->ea; 1710 foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) { 1711 if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)]))) 1712 break; 1713 ether_atoe(var, ea->octet); 1714 maclist->count++; 1715 ea++; 1716 } 1717 WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf)); 1718 1719 /* Set WDS link detection timeout */ 1720 val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp))); 1721 wl_iovar_setint(name, "wdstimeout", val); 1722 1723 if (wds) { 1724 wl_iovar_setint(name, "radio_init", 1); 1725 } 1726 } 1727 1728 /* 1729 * Finally enable BSS Configs or Join BSS 1730 * 1731 * AP: Enable BSS Config to bring AP up only when nas will not run 1732 * STA: Join the BSS regardless. 1733 */ 1734 for (i = 0; i < bclist->count; i++) { 1735 struct {int bsscfg_idx; int enable;} setbuf; 1736 char vifname[VIFNAME_LEN]; 1737 char *name_ptr = name; 1738 1739 setbuf.bsscfg_idx = bclist->bsscfgs[i].idx; 1740 setbuf.enable = 0; 1741 1742 bsscfg = &bclist->bsscfgs[i]; 1743 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) { 1744 setbuf.enable = 1; 1745 } 1746 1747 /* Set the MAC list */ 1748 maclist = (struct maclist *)buf; 1749 maclist->count = 0; 1750 if (!nvram_match(strcat_r(bsscfg->prefix, "macmode", tmp), "disabled")) { 1751 ea = maclist->ea; 1752 foreach(var, nvram_safe_get(strcat_r(bsscfg->prefix, "maclist", tmp)), 1753 next) { 1754 if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)]))) 1755 break; 1756 if (ether_atoe(var, ea->octet)) { 1757 maclist->count++; 1758 ea++; 1759 } 1760 } 1761 } 1762 1763 if (setbuf.bsscfg_idx == 0) { 1764 name_ptr = name; 1765 } else { /* Non-primary BSS; changes name syntax */ 1766 char tmp[VIFNAME_LEN]; 1767 int len; 1768 1769 /* Remove trailing _ if present */ 1770 memset(tmp, 0, sizeof(tmp)); 1771 strncpy(tmp, bsscfg->prefix, VIFNAME_LEN - 1); 1772 if (((len = strlen(tmp)) > 0) && (tmp[len - 1] == '_')) { 1773 tmp[len - 1] = 0; 1774 } 1775 nvifname_to_osifname(tmp, vifname, VIFNAME_LEN); 1776 name_ptr = vifname; 1777 } 1778 1779 WL_IOCTL(name_ptr, WLC_SET_MACLIST, buf, sizeof(buf)); 1780 1781 /* Set macmode for each VIF */ 1782 (void) strcat_r(bsscfg->prefix, "macmode", tmp); 1783 1784 if (nvram_match(tmp, "deny")) 1785 val = WLC_MACMODE_DENY; 1786 else if (nvram_match(tmp, "allow")) 1787 val = WLC_MACMODE_ALLOW; 1788 else 1789 val = WLC_MACMODE_DISABLED; 1790 1791 WL_IOCTL(name_ptr, WLC_SET_MACMODE, &val, sizeof(val)); 1792 1793 /* NAS runs if we have an AKM or radius authentication */ 1794 nas_will_run = wlconf_akm_options(bclist->bsscfgs[i].prefix) || 1795 nvram_match(strcat_r(bclist->bsscfgs[i].prefix, "auth_mode", tmp), 1796 "radius"); 1797 1798 if (((ap || apsta) && !nas_will_run) || sta || wet) { 1799 for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) { 1800 if (wl_ap_build) { 1801 WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf)); 1802 } 1803 else { 1804 strcat_r(prefix, "ssid", tmp); 1805 ssid.SSID_len = strlen(nvram_safe_get(tmp)); 1806 if (ssid.SSID_len > sizeof(ssid.SSID)) 1807 ssid.SSID_len = sizeof(ssid.SSID); 1808 strncpy((char *)ssid.SSID, nvram_safe_get(tmp), 1809 ssid.SSID_len); 1810 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); 1811 } 1812 if (apsta && (ret != 0)) 1813 sleep_ms(1000); 1814 else 1815 break; 1816 } 1817 } 1818 } 1819 1820 ret = 0; 1821exit: 1822 if (bclist != NULL) 1823 free(bclist); 1824 1825 return ret; 1826} 1827 1828int 1829wlconf_down(char *name) 1830{ 1831 int val, ret = 0; 1832 int i; 1833 int wlsubunit; 1834 int bcmerr; 1835 struct {int bsscfg_idx; int enable;} setbuf; 1836 int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */ 1837 char cap[WLC_IOCTL_SMLEN]; 1838 char caps[WLC_IOCTL_SMLEN]; 1839 char *next; 1840 wlc_ssid_t ssid; 1841 1842 /* wlconf doesn't work for virtual i/f */ 1843 if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) { 1844 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name); 1845 return 0; 1846 } 1847 1848 /* Check interface (fail silently for non-wl interfaces) */ 1849 if ((ret = wl_probe(name))) 1850 return ret; 1851 1852 /* because of ifdefs in wl driver, when we don't have AP capabilities we 1853 * can't use the same iovars to configure the wl. 1854 * so we use "wl_ap_build" to help us know how to configure the driver 1855 */ 1856 if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN)) 1857 return -1; 1858 1859 foreach(cap, caps, next) { 1860 if (!strcmp(cap, "ap")) { 1861 wl_ap_build = 1; 1862 } 1863 } 1864 1865 if (wl_ap_build) { 1866 /* Bring down the interface */ 1867 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); 1868 1869 /* Disable all BSS Configs */ 1870 for (i = 0; i < WL_MAXBSSCFG; i++) { 1871 setbuf.bsscfg_idx = i; 1872 setbuf.enable = 0; 1873 1874 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf)); 1875 if (ret) { 1876 wl_iovar_getint(name, "bcmerror", &bcmerr); 1877 /* fail quietly on a range error since the driver may 1878 * support fewer bsscfgs than we are prepared to configure 1879 */ 1880 if (bcmerr == BCME_RANGE) 1881 break; 1882 } 1883 } 1884 } 1885 else { 1886 WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val)); 1887 if (val) { 1888 /* Nuke SSID */ 1889 ssid.SSID_len = 0; 1890 ssid.SSID[0] = '\0'; 1891 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); 1892 1893 /* Bring down the interface */ 1894 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); 1895 } 1896 } 1897 1898 /* Nuke the WDS list */ 1899 wlconf_wds_clear(name); 1900 1901 return 0; 1902} 1903 1904int 1905wlconf_ssid(void) 1906{ 1907// struct bsscfg_info *bsscfg; 1908 wlc_ssid_t ssid; 1909 char name[32]; 1910// char ssid[256]; 1911 int ret; 1912 1913 1914 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 1915// printf("name=%s\n",name); 1916 ssid.SSID_len = 0; 1917 ssid.SSID[0] = '\0'; 1918 1919 WL_IOCTL(name, WLC_GET_SSID, &ssid, sizeof(ssid)); 1920 1921 printf("Current SSID:\"%s\"\n", ssid.SSID); 1922// printf("wlconfig(%s): configuring bsscfg #%d (%s) with SSID \"%s\"\n", 1923// name, bsscfg->idx, bsscfg->ifname, nvram_safe_get(tmp)); 1924// WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, sizeof(ssid)); 1925 return 0; 1926} 1927 1928int 1929wlconf_set_ssid(char *tmpssid) 1930{ 1931 wlc_ssid_t ssid; 1932 char name[32]; 1933 int ret; 1934 1935 ssid.SSID_len = 0; 1936 ssid.SSID[0] = '\0'; 1937 1938// sprintf(ssid.SSID, "%s", tmpssid); 1939 strncpy((char *)ssid.SSID, tmpssid, strlen(tmpssid)); 1940 ssid.SSID[strlen(tmpssid)+1] = '\0'; 1941 ssid.SSID_len = strlen (tmpssid); 1942 1943// printf("ssid.SSID=%s, tmpssid=%s, strlen=%d, SSID_LEN=%d\n", ssid.SSID, tmpssid, strlen(tmpssid), ssid.SSID_len); 1944 1945 1946 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 1947// printf("name=%s\n!",name); 1948// printf("tmpssid=%s!, length=%d\n", ssid.SSID, ssid.SSID_len); 1949 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); 1950// printf("SSID=%s!\n", ssid.SSID); 1951 return 0; 1952} 1953 1954int 1955wlconf_txant(char *var) 1956{ 1957 char name[32]; 1958 int ret; 1959 int val; 1960 1961 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 1962 val = atoi(var); 1963// printf("val = %d, var = %s!\n", val, var); 1964 WL_IOCTL (name, WLC_SET_TXANT, &val, sizeof(val)); 1965 printf("%d\n", val); 1966 return 0; 1967} 1968 1969int 1970wlconf_antdiv(char *var) 1971{ 1972 char name[32]; 1973 int ret; 1974 int val; 1975 1976 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 1977 val = atoi(var); 1978// printf("val = %d, var = %s!\n", val, var); 1979 WL_IOCTL (name, WLC_SET_ANTDIV, &val, sizeof(val)); 1980 printf("%d\n", val); 1981 1982 return 0; 1983} 1984 1985int 1986wlconf_radio(char *act) 1987{ 1988 char name[32]; 1989 int ret, val; 1990 1991 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 1992 if (!strcmp(act, "on")) 1993 val = 0; 1994 else 1995 val = 1; 1996 1997 val += WL_RADIO_SW_DISABLE << 16; 1998 WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val)); 1999 printf("%d\n", val); 2000 2001 return 0; 2002} 2003 2004int 2005wlconf_auth(char *act) 2006{ 2007 char name[32]; 2008 int ret, val; 2009 2010 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2011 val = atoi(act); 2012 WL_IOCTL(name, WLC_SET_AUTH, &val, sizeof(val)); 2013 printf("%d\n", val); 2014 2015 return 0; 2016} 2017 2018int 2019wlconf_wsec(char *var) 2020{ 2021 char name[32]; 2022 int ret, val; 2023 2024 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2025 val = atoi(var); 2026 WL_IOCTL(name, WLC_SET_WSEC, &val, sizeof(val)); 2027 printf("%d\n", val); 2028 2029 return 0; 2030} 2031 2032int 2033wlconf_wpa_auth(char *var) 2034{ 2035 char name[32]; 2036 int ret, val; 2037 2038 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2039 val = atoi(var); 2040 WL_IOCTL(name, WLC_SET_WPA_AUTH, &val, sizeof(val)); 2041 printf("%d\n", val); 2042 2043 return 0; 2044} 2045 2046int 2047wlconf_eap(char *var) 2048{ 2049 char name[32]; 2050 int ret, val; 2051 2052 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2053 if (!strcmp (var, "on")) 2054 val = 1; 2055 else 2056 val = 0; 2057// val = atoi(var); 2058 WL_IOCTL(name, WLC_SET_EAP_RESTRICT, &val, sizeof(val)); 2059 printf("%d\n", val); 2060 2061 return 0; 2062} 2063 2064int 2065wlconf_rate(char *var) 2066{ 2067 char name[32]; 2068 int ret, ret2, val; 2069 2070 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2071 val = atoi(var) *2; 2072// WL_IOCTL(name, WLC_SET_RATE, &val, sizeof(val)); 2073 ret = wl_iovar_setint(name, "bg_rate", val); 2074 ret2 = wl_iovar_setint(name, "bg_mrate", val); 2075 printf("%d Mbps\n", val/2); 2076 2077 return 0; 2078} 2079 2080int 2081wlconf_led(void) 2082{ 2083// struct bsscfg_info *bsscfg; 2084// wlc_ssid_t ssid; 2085 char name[32]; 2086 char led[256]; 2087 int ret; 2088 2089 2090 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2091// printf("name=%s\n",name); 2092// ssid.SSID_len = 0; 2093 led[0] = '\0'; 2094 2095 WL_IOCTL(name, WLC_GET_LED, &led, sizeof(led)); 2096 2097 printf("LED:\"%s\"\n", led); 2098// printf("wlconfig(%s): configuring bsscfg #%d (%s) with SSID \"%s\"\n", 2099// name, bsscfg->idx, bsscfg->ifname, nvram_safe_get(tmp)); 2100// WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, sizeof(ssid)); 2101 return 0; 2102} 2103 2104int 2105wlconf_set_led(char *led) 2106{ 2107// wlc_ssid_t ssid; 2108 char name[32]; 2109 int ret; 2110 2111// ssid.SSID_len = 0; 2112// ssid.SSID[0] = '\0'; 2113 2114// sprintf(ssid.SSID, "%s", tmpssid); 2115// strncpy((char *)ssid.SSID, tmpssid, strlen(tmpssid)); 2116// ssid.SSID[strlen(tmpssid)+1] = '\0'; 2117// ssid.SSID_len = strlen (tmpssid); 2118 2119// printf("ssid.SSID=%s, tmpssid=%s, strlen=%d, SSID_LEN=%d\n", ssid.SSID, tmpssid, strlen(tmpssid), ssid.SSID_len); 2120 2121 2122 sprintf(name, "%s", nvram_safe_get("wl0_ifname")); 2123// printf("name=%s\n!",name); 2124// printf("tmpssid=%s!, length=%d\n", ssid.SSID, ssid.SSID_len); 2125 WL_IOCTL(name, WLC_SET_LED, &led, sizeof(led)); 2126 printf("LED=%s!\n", led); 2127 return 0; 2128} 2129 2130#if defined(linux) 2131int 2132main(int argc, char *argv[]) 2133{ 2134 /* Check parameters and branch based on action */ 2135 if (argc == 3 && !strcmp(argv[2], "up")) 2136 return wlconf(argv[1]); 2137 else if (argc == 3 && !strcmp(argv[2], "down")) 2138 return wlconf_down(argv[1]); 2139#if 0 2140 else { 2141 fprintf(stderr, "Usage: wlconf <ifname> up|down\n"); 2142 return -1; 2143 } 2144#endif 2145 else if (!strcmp(argv[1], "ssid")){ 2146 if (argc == 2) 2147 return wlconf_ssid(); 2148 else if (argc == 3) 2149 return wlconf_set_ssid(argv[2]); 2150 else { 2151 fprintf(stderr, "Usage: wlconf ssid (<name>) to show|set ssid\n"); 2152 return -1; 2153 } 2154 } 2155 else if (!strcmp (argv[1], "txant")){ 2156 if (argc == 3) 2157 return wlconf_txant(argv[2]); 2158 else { 2159 fprintf(stderr, "Usage: wlconf txant <val>\n"); 2160 return 1; 2161 } 2162 } 2163 else if (!strcmp (argv[1], "antdiv")){ 2164 if (argc == 3) 2165 return wlconf_antdiv(argv[2]); 2166 else { 2167 fprintf(stderr, "Usage: wlconf antdiv <val>\n"); 2168 return -1; 2169 } 2170 } 2171 else if (!strcmp (argv[1], "auth")){ 2172 if (argc == 3 && ( !strcmp (argv[2], "0") || !strcmp(argv[2], "1") )) 2173 return wlconf_auth(argv[2]); 2174 else { 2175 fprintf(stderr, "Usage: wlconf auth 0|1. 0:OpenSystem 1:SharedKey\n"); 2176 return -1; 2177 } 2178 } 2179 else if (!strcmp (argv[1], "wsec")){ 2180 if (argc == 3 ) 2181 return wlconf_wsec(argv[2]); 2182 else { 2183 fprintf(stderr, "Usage: wlconf wsec <val> \n" 2184 "\t1:WEP 2:TKIP 4:AES 8:WSEC IN Software 0x80: FIPS enabled\n"); 2185 return -1; 2186 } 2187 } 2188 else if (!strcmp (argv[1], "wpa_auth")){ 2189 if (argc == 3 ) 2190 return wlconf_wpa_auth(argv[2]); 2191 else { 2192 fprintf(stderr, "Usage: wlconf wpa_auth <val>\n" 2193 "\t1:WPA-NONE 2:WPA-802.1x 4:WPA-PSK\n" 2194 "\t64:WPA2-802.1x 128:WPA2-PSK 0:disable\n"); 2195 return -1; 2196 } 2197 } 2198 else if (!strcmp (argv[1], "eap")){ 2199 if (argc == 3 && (!strcmp (argv[2], "on") || !strcmp(argv[2], "off"))) 2200 return wlconf_eap(argv[2]); 2201 else { 2202 fprintf(stderr, "Usage: wlconf eap on|off\n"); 2203 return -1; 2204 } 2205 } 2206 else if (!strcmp (argv[1], "rate")){ 2207 if (argc == 3 ) 2208 return wlconf_rate(argv[2]); 2209 else { 2210 fprintf(stderr, "Usage: wlconf rate <rate>\n"); 2211 return -1; 2212 } 2213 } 2214 else if (!strcmp(argv[1], "led")){ 2215 if (argc == 2) 2216 return wlconf_led(); 2217 else if (argc == 3) 2218 return wlconf_set_led(argv[2]); 2219 else { 2220 fprintf(stderr, "Usage: wlconf led (<value>) to show|set led\n"); 2221 return -1; 2222 } 2223 } 2224 else if (!strcmp (argv[1], "radio")){ 2225 if (argc == 3 && (!strcmp (argv[2], "on") || !strcmp(argv[2], "off"))) 2226 return wlconf_radio(argv[2]); 2227 else { 2228 fprintf(stderr, "Usage: wlconf radio on|off\n"); 2229 return -1; 2230 } 2231 } 2232 else { 2233 fprintf(stderr, "Usage: wlconf and one of:\n" 2234 "\t<interface> up|down\n" 2235 "\tssid <name>\n" 2236 "\ttxant <val>\n" 2237 "\tantdiv <val>\n" 2238 "\tradio on|off\n" 2239 "\tauth <0|1>\n" 2240 "\twsec on|off\n" 2241 "\twpa_auth on|off\n" 2242 "\teap on|off\n" 2243 "\trate <rate>\n" 2244 ); 2245 } 2246} 2247#endif 2248