1/* 2 * Wireless Network Adapter Configuration Utility 3 * 4 * Copyright (C) 2015, 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 515105 2014-11-13 06:54:30Z $ 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 <bcmdevs.h> 24#include <shutils.h> 25#include <wlutils.h> 26#include <wlioctl.h> 27#include <proto/802.1d.h> 28#include <bcmconfig.h> 29#include <bcmwifi_channels.h> 30#include <netconf.h> 31#include <nvparse.h> 32#include <arpa/inet.h> 33 34#if defined(linux) 35#include <sys/utsname.h> 36#endif 37 38/* phy types */ 39#define PHY_TYPE_A 0 40#define PHY_TYPE_B 1 41#define PHY_TYPE_G 2 42#define PHY_TYPE_N 4 43#define PHY_TYPE_LP 5 44#define PHY_TYPE_SSN 6 45#define PHY_TYPE_HT 7 46#define PHY_TYPE_LCN 8 47#define PHY_TYPE_AC 11 48#define PHY_TYPE_NULL 0xf 49 50/* how many times to attempt to bring up a virtual i/f when 51 * we are in APSTA mode and IOVAR set of "bss" "up" returns busy 52 */ 53#define MAX_BSS_UP_RETRIES 5 54 55/* notify the average dma xfer rate (in kbps) to the driver */ 56#define AVG_DMA_XFER_RATE 120000 57 58/* parts of an idcode: */ 59#define IDCODE_MFG_MASK 0x00000fff 60#define IDCODE_MFG_SHIFT 0 61#define IDCODE_ID_MASK 0x0ffff000 62#define IDCODE_ID_SHIFT 12 63#define IDCODE_REV_MASK 0xf0000000 64#define IDCODE_REV_SHIFT 28 65 66/* 67 * Debugging Macros 68 */ 69#ifdef BCMDBG 70#define WLCONF_DBG(fmt, arg...) printf("%s: "fmt, __FUNCTION__ , ## arg) 71#define WL_IOCTL(ifname, cmd, buf, len) \ 72 if ((ret = wl_ioctl(ifname, cmd, buf, len))) \ 73 fprintf(stderr, "%s:%d:(%s): %s failed, err = %d\n", \ 74 __FUNCTION__, __LINE__, ifname, #cmd, ret); 75#define WL_SETINT(ifname, cmd, val) \ 76 if ((ret = wlconf_setint(ifname, cmd, val))) \ 77 fprintf(stderr, "%s:%d:(%s): setting %s to %d (0x%x) failed, err = %d\n", \ 78 __FUNCTION__, __LINE__, ifname, #cmd, (int)val, (unsigned int)val, ret); 79#define WL_GETINT(ifname, cmd, pval) \ 80 if ((ret = wlconf_getint(ifname, cmd, pval))) \ 81 fprintf(stderr, "%s:%d:(%s): getting %s failed, err = %d\n", \ 82 __FUNCTION__, __LINE__, ifname, #cmd, ret); 83#define WL_IOVAR_SET(ifname, iovar, param, paramlen) \ 84 if ((ret = wl_iovar_set(ifname, iovar, param, paramlen))) \ 85 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" failed, err = %d\n", \ 86 __FUNCTION__, __LINE__, ifname, iovar, ret); 87#define WL_IOVAR_GET(ifname, iovar, param, paramlen) \ 88 if ((ret = wl_iovar_get(ifname, iovar, param, paramlen))) \ 89 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \ 90 __FUNCTION__, __LINE__, ifname, iovar, ret); 91#define WL_IOVAR_SETINT(ifname, iovar, val) \ 92 if ((ret = wl_iovar_setint(ifname, iovar, val))) \ 93 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" to 0x%x failed, err = %d\n", \ 94 __FUNCTION__, __LINE__, ifname, iovar, (unsigned int)val, ret); 95#define WL_IOVAR_GETINT(ifname, iovar, val) \ 96 if ((ret = wl_iovar_getint(ifname, iovar, val))) \ 97 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \ 98 __FUNCTION__, __LINE__, ifname, iovar, ret); 99#define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \ 100 if ((ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))) \ 101 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \ 102 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret); 103#define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \ 104 if ((ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))) \ 105 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \ 106 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret); 107#define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \ 108 if ((ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))) \ 109 fprintf(stderr, "%s:%d:(%s): getting bsscfg #%d iovar \"%s\" failed, err = %d\n", \ 110 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret); 111#define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) \ 112 if ((ret = wl_bssiovar_setint(ifname, iovar, bssidx, val))) \ 113 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" " \ 114 "to val 0x%x failed, err = %d\n", \ 115 __FUNCTION__, __LINE__, ifname, bssidx, iovar, (unsigned int)val, ret); 116#else 117#define WLCONF_DBG(fmt, arg...) 118#define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len)) 119#define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val)) 120#define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval)) 121#define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \ 122 param, paramlen)) 123#define WL_IOVAR_GET(ifname, iovar, param, paramlen) (ret = wl_iovar_get(ifname, iovar, \ 124 param, paramlen)) 125#define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val)) 126#define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val)) 127#define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \ 128 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen)) 129#define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \ 130 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen)) 131#define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \ 132 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen)) 133#define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \ 134 bssidx, val)) 135#endif /* BCMDBG */ 136 137#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK)) 138 139/* prototypes */ 140struct bsscfg_list *wlconf_get_bsscfgs(char* ifname, char* prefix); 141int wlconf(char *name); 142int wlconf_down(char *name); 143 144static int 145wlconf_getint(char* ifname, int cmd, int *pval) 146{ 147 return wl_ioctl(ifname, cmd, pval, sizeof(int)); 148} 149 150static int 151wlconf_setint(char* ifname, int cmd, int val) 152{ 153 return wl_ioctl(ifname, cmd, &val, sizeof(int)); 154} 155 156static int 157wlconf_wds_clear(char *name) 158{ 159 struct maclist maclist; 160 int ret; 161 162 maclist.count = 0; 163 WL_IOCTL(name, WLC_SET_WDSLIST, &maclist, sizeof(maclist)); 164 165 return ret; 166} 167 168/* set WEP key */ 169static int 170wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i) 171{ 172 wl_wsec_key_t key; 173 char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX"; 174 char *keystr, hex[] = "XX"; 175 unsigned char *data = key.data; 176 int ret = 0; 177 178 memset(&key, 0, sizeof(key)); 179 key.index = i - 1; 180 sprintf(wl_key, "%skey%d", prefix, i); 181 keystr = nvram_safe_get(wl_key); 182 183 switch (strlen(keystr)) { 184 case WEP1_KEY_SIZE: 185 case WEP128_KEY_SIZE: 186 key.len = strlen(keystr); 187 strcpy((char *)key.data, keystr); 188 break; 189 case WEP1_KEY_HEX_SIZE: 190 case WEP128_KEY_HEX_SIZE: 191 key.len = strlen(keystr) / 2; 192 while (*keystr) { 193 strncpy(hex, keystr, 2); 194 *data++ = (unsigned char) strtoul(hex, NULL, 16); 195 keystr += 2; 196 } 197 break; 198 default: 199 key.len = 0; 200 break; 201 } 202 203 /* Set current WEP key */ 204 if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key)))) 205 key.flags = WL_PRIMARY_KEY; 206 207 WL_BSSIOVAR_SET(name, "wsec_key", bsscfg_idx, &key, sizeof(key)); 208 209 return ret; 210} 211 212static int 213wlconf_akm_options(char *prefix) 214{ 215 char comb[32]; 216 char *wl_akm; 217 int akm_ret_val = 0; 218 char akm[32]; 219 char *next; 220 221 wl_akm = nvram_safe_get(strcat_r(prefix, "akm", comb)); 222 foreach(akm, wl_akm, next) { 223 if (!strcmp(akm, "wpa")) 224 akm_ret_val |= WPA_AUTH_UNSPECIFIED; 225 if (!strcmp(akm, "psk")) 226 akm_ret_val |= WPA_AUTH_PSK; 227 if (!strcmp(akm, "wpa2")) 228 akm_ret_val |= WPA2_AUTH_UNSPECIFIED; 229 if (!strcmp(akm, "psk2")) 230 akm_ret_val |= WPA2_AUTH_PSK; 231 if (!strcmp(akm, "brcm_psk")) 232 akm_ret_val |= BRCM_AUTH_PSK; 233 } 234 return akm_ret_val; 235} 236 237/* Set up wsec */ 238static int 239wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx) 240{ 241 char tmp[100]; 242 int val = 0; 243 int akm_val; 244 int ret; 245 246 /* Set wsec bitvec */ 247 akm_val = wlconf_akm_options(prefix); 248 if (akm_val != 0) { 249 if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip")) 250 val = TKIP_ENABLED; 251 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes")) 252 val = AES_ENABLED; 253 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes")) 254 val = TKIP_ENABLED | AES_ENABLED; 255 } 256 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) 257 val |= WEP_ENABLED; 258 WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val); 259 /* Set wsec restrict if WSEC_ENABLED */ 260 WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0); 261 262 return 0; 263} 264 265static int 266wlconf_set_preauth(char *name, int bsscfg_idx, int preauth) 267{ 268 uint cap; 269 int ret; 270 271 WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint)); 272 if (ret != 0) return -1; 273 274 if (preauth) 275 cap |= WPA_CAP_WPA2_PREAUTH; 276 else 277 cap &= ~WPA_CAP_WPA2_PREAUTH; 278 279 WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap); 280 281 return ret; 282} 283 284static void 285wlconf_set_radarthrs(char *name, char *prefix) 286{ 287 wl_radar_thr_t radar_thr; 288 int i, ret, len; 289 char nv_buf[NVRAM_MAX_VALUE_LEN], *rargs, *v, *endptr; 290 char buf[WLC_IOCTL_SMLEN]; 291 292 char *version = NULL; 293 char *thr0_20_lo = NULL, *thr1_20_lo = NULL; 294 char *thr0_40_lo = NULL, *thr1_40_lo = NULL; 295 char *thr0_80_lo = NULL, *thr1_80_lo = NULL; 296 char *thr0_20_hi = NULL, *thr1_20_hi = NULL; 297 char *thr0_40_hi = NULL, *thr1_40_hi = NULL; 298 char *thr0_80_hi = NULL, *thr1_80_hi = NULL; 299 300 char **locals[] = { &version, &thr0_20_lo, &thr1_20_lo, &thr0_40_lo, &thr1_40_lo, 301 &thr0_80_lo, &thr1_80_lo, &thr0_20_hi, &thr1_20_hi, 302 &thr0_40_hi, &thr1_40_hi, &thr0_80_hi, &thr1_80_hi }; 303 304 rargs = nvram_safe_get(strcat_r(prefix, "radarthrs", nv_buf)); 305 if (!rargs) 306 goto err; 307 308 len = strlen(rargs); 309 if ((len > NVRAM_MAX_VALUE_LEN) || (len == 0)) 310 goto err; 311 312 memset(nv_buf, 0, sizeof(nv_buf)); 313 strncpy(nv_buf, rargs, len); 314 v = nv_buf; 315 for (i = 0; i < (sizeof(locals) / sizeof(locals[0])); i++) { 316 *locals[i] = v; 317 while (*v && *v != ' ') { 318 v++; 319 } 320 if (*v) { 321 *v = 0; 322 v++; 323 } 324 if (v >= (nv_buf + len)) /* Check for complete list, if not caught later */ 325 break; 326 } 327 328 /* Start building request */ 329 memset(buf, 0, sizeof(buf)); 330 strcpy(buf, "radarthrs"); 331 /* Retrieve radar thrs parameters */ 332 if (!version) 333 goto err; 334 radar_thr.version = atoi(version); 335 if (radar_thr.version > WL_RADAR_THR_VERSION) 336 goto err; 337 338 /* Retrieve ver 0 params */ 339 if (!thr0_20_lo) 340 goto err; 341 radar_thr.thresh0_20_lo = (uint16)strtol(thr0_20_lo, &endptr, 0); 342 if (*endptr != '\0') 343 goto err; 344 345 if (!thr1_20_lo) 346 goto err; 347 radar_thr.thresh1_20_lo = (uint16)strtol(thr1_20_lo, &endptr, 0); 348 if (*endptr != '\0') 349 goto err; 350 351 if (!thr0_40_lo) 352 goto err; 353 radar_thr.thresh0_40_lo = (uint16)strtol(thr0_40_lo, &endptr, 0); 354 if (*endptr != '\0') 355 goto err; 356 357 if (!thr1_40_lo) 358 goto err; 359 radar_thr.thresh1_40_lo = (uint16)strtol(thr1_40_lo, &endptr, 0); 360 if (*endptr != '\0') 361 goto err; 362 363 if (!thr0_80_lo) 364 goto err; 365 radar_thr.thresh0_80_lo = (uint16)strtol(thr0_80_lo, &endptr, 0); 366 if (*endptr != '\0') 367 goto err; 368 369 if (!thr1_80_lo) 370 goto err; 371 radar_thr.thresh1_80_lo = (uint16)strtol(thr1_80_lo, &endptr, 0); 372 if (*endptr != '\0') 373 goto err; 374 375 376 if (radar_thr.version == 0) { 377 /* 378 * Attempt a best effort update of ver 0 to ver 1 by updating 379 * the appropriate values with the specified defaults. The defaults 380 * are from the reference design. 381 */ 382 radar_thr.version = WL_RADAR_THR_VERSION; /* avoid driver rejecting it */ 383 radar_thr.thresh0_20_hi = 0x6ac; 384 radar_thr.thresh1_20_hi = 0x6cc; 385 radar_thr.thresh0_40_hi = 0x6bc; 386 radar_thr.thresh1_40_hi = 0x6e0; 387 radar_thr.thresh0_80_hi = 0x6b0; 388 radar_thr.thresh1_80_hi = 0x30; 389 } else { 390 /* Retrieve ver 1 params */ 391 if (!thr0_20_hi) 392 goto err; 393 radar_thr.thresh0_20_hi = (uint16)strtol(thr0_20_hi, &endptr, 0); 394 if (*endptr != '\0') 395 goto err; 396 397 if (!thr1_20_hi) 398 goto err; 399 radar_thr.thresh1_20_hi = (uint16)strtol(thr1_20_hi, &endptr, 0); 400 if (*endptr != '\0') 401 goto err; 402 403 if (!thr0_40_hi) 404 goto err; 405 radar_thr.thresh0_40_hi = (uint16)strtol(thr0_40_hi, &endptr, 0); 406 if (*endptr != '\0') 407 goto err; 408 409 if (!thr1_40_hi) 410 goto err; 411 radar_thr.thresh1_40_hi = (uint16)strtol(thr1_40_hi, &endptr, 0); 412 if (*endptr != '\0') 413 goto err; 414 415 if (!thr0_80_hi) 416 goto err; 417 radar_thr.thresh0_80_hi = (uint16)strtol(thr0_80_hi, &endptr, 0); 418 if (*endptr != '\0') 419 goto err; 420 421 if (!thr1_80_hi) 422 goto err; 423 radar_thr.thresh1_80_hi = (uint16)strtol(thr1_80_hi, &endptr, 0); 424 if (*endptr != '\0') 425 goto err; 426 427 } 428 429 /* Copy radar parameters into buffer and plug them to the driver */ 430 memcpy((char*)(buf + strlen(buf) + 1), (char*)&radar_thr, sizeof(wl_radar_thr_t)); 431 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); 432 433 return; 434 435err: 436 WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n"); 437 return; 438} 439 440/* 441 * This allows phy antenna selection to be retrieved from NVRAM 442 */ 443static void 444wlconf_set_antsel(char *name, char *prefix) 445{ 446 int i, j, len, argc, ret; 447 char buf[WLC_IOCTL_SMLEN]; 448 wlc_antselcfg_t val = { {0}, 0}; 449 char *argv[ANT_SELCFG_MAX] = {}; 450 char nv_buf[NVRAM_MAX_VALUE_LEN], *argstr, *v, *endptr; 451 452 argstr = nvram_safe_get(strcat_r(prefix, "phy_antsel", nv_buf)); 453 if (!argstr) { 454 return; 455 } 456 len = strlen(argstr); 457 if ((len == 0) || (len > NVRAM_MAX_VALUE_LEN)) { 458 return; 459 } 460 461 memset(nv_buf, 0, sizeof(nv_buf)); 462 strncpy(nv_buf, argstr, len); 463 v = nv_buf; 464 for (argc = 0; argc < ANT_SELCFG_MAX; ) { 465 argv[argc++] = v; 466 while (*v && *v != ' ') { 467 v++; 468 } 469 if (*v) { 470 *v = 0; 471 v++; 472 } 473 if (v >= (nv_buf + len)) { 474 break; 475 } 476 } 477 if ((argc != 1) && (argc != ANT_SELCFG_MAX)) { 478 WLCONF_DBG("phy_antsel requires 1 or %d arguments\n", ANT_SELCFG_MAX); 479 return; 480 } 481 482 memset(buf, 0, sizeof(buf)); 483 strcpy(buf, "phy_antsel"); 484 for (i = 0, j = 0; i < ANT_SELCFG_MAX; i++) { 485 val.ant_config[i] = (uint8)strtol(argv[j], &endptr, 0); 486 if (*endptr != '\0') { 487 WLCONF_DBG("Invalid antsel argument\n"); 488 return; 489 } 490 if (argc > 1) { 491 /* ANT_SELCFG_MAX argument format */ 492 j++; 493 } 494 } 495 496 /* Copy antsel parameters into buffer and plug them to the driver */ 497 memcpy((char*)(buf + strlen(buf) + 1), (char*)&val, sizeof(wlc_antselcfg_t)); 498 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); 499 500 return; 501} 502 503 504 505static void 506wlconf_set_current_txparam_into_nvram(char *name, char *prefix) 507{ 508 int ret, aci; 509 wme_tx_params_t txparams[AC_COUNT]; 510 char *nv[] = {"wme_txp_be", "wme_txp_bk", "wme_txp_vi", "wme_txp_vo"}; 511 char data[50], tmp[50]; 512 513 /* get the WME tx parameters */ 514 WL_IOVAR_GET(name, "wme_tx_params", txparams, sizeof(txparams)); 515 516 /* Set nvram accordingly */ 517 for (aci = 0; aci < AC_COUNT; aci++) { 518 sprintf(data, "%d %d %d %d %d", txparams[aci].short_retry, 519 txparams[aci].short_fallback, 520 txparams[aci].long_retry, 521 txparams[aci].long_fallback, 522 txparams[aci].max_rate); 523 524 nvram_set(strcat_r(prefix, nv[aci], tmp), data); 525 } 526} 527 528/* Set up WME */ 529static void 530wlconf_set_wme(char *name, char *prefix) 531{ 532 int i, j, k; 533 int val, ret; 534 int phytype, gmode, no_ack, apsd, dp[2]; 535 edcf_acparam_t *acparams; 536 /* Pay attention to buffer length requirements when using this */ 537 char buf[WLC_IOCTL_SMLEN*2]; 538 char *v, *nv_value, nv[100]; 539 char nv_name[] = "%swme_%s_%s"; 540 char *ac[] = {"be", "bk", "vi", "vo"}; 541 char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first; 542 char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced, 543 &oldest_first }; 544 struct {char *req; char *str;} mode[] = {{"wme_ac_ap", "ap"}, {"wme_ac_sta", "sta"}, 545 {"wme_tx_params", "txp"}}; 546 547 /* query the phy type */ 548 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); 549 /* get gmode */ 550 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", nv))); 551 552 /* WME sta setting first */ 553 for (i = 0; i < 2; i++) { 554 /* build request block */ 555 memset(buf, 0, sizeof(buf)); 556 strcpy(buf, mode[i].req); 557 /* put push wmeac params after "wme-ac" in buf */ 558 acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1); 559 dp[i] = 0; 560 for (j = 0; j < AC_COUNT; j++) { 561 /* get packed nvram parameter */ 562 snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]); 563 nv_value = nvram_safe_get(nv); 564 strcpy(nv, nv_value); 565 /* unpack it */ 566 v = nv; 567 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) { 568 *locals[k] = v; 569 while (*v && *v != ' ') 570 v++; 571 if (*v) { 572 *v = 0; 573 v++; 574 } 575 } 576 577 /* update CWmin */ 578 acparams->ECW &= ~EDCF_ECWMIN_MASK; 579 val = atoi(cwmin); 580 for (val++, k = 0; val; val >>= 1, k++); 581 acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK; 582 /* update CWmax */ 583 acparams->ECW &= ~EDCF_ECWMAX_MASK; 584 val = atoi(cwmax); 585 for (val++, k = 0; val; val >>= 1, k++); 586 acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK; 587 /* update AIFSN */ 588 acparams->ACI &= ~EDCF_AIFSN_MASK; 589 acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK; 590 /* update ac */ 591 acparams->ACI &= ~EDCF_ACI_MASK; 592 acparams->ACI |= j << EDCF_ACI_SHIFT; 593 /* update TXOP */ 594 if (phytype == PHY_TYPE_B || gmode == 0) 595 val = atoi(txop_b); 596 else 597 val = atoi(txop_ag); 598 acparams->TXOP = val / 32; 599 /* update acm */ 600 acparams->ACI &= ~EDCF_ACM_MASK; 601 val = strcmp(admin_forced, "on") ? 0 : 1; 602 acparams->ACI |= val << 4; 603 604 /* configure driver */ 605 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf)); 606 } 607 } 608 609 /* set no-ack */ 610 v = nvram_safe_get(strcat_r(prefix, "wme_no_ack", nv)); 611 no_ack = strcmp(v, "on") ? 0 : 1; 612 WL_IOVAR_SETINT(name, "wme_noack", no_ack); 613 614 /* set APSD */ 615 v = nvram_safe_get(strcat_r(prefix, "wme_apsd", nv)); 616 apsd = strcmp(v, "on") ? 0 : 1; 617 WL_IOVAR_SETINT(name, "wme_apsd", apsd); 618 619 /* set per-AC discard policy */ 620 strcpy(buf, "wme_dp"); 621 WL_IOVAR_SETINT(name, "wme_dp", dp[1]); 622 623 /* WME Tx parameters setting */ 624 { 625 wme_tx_params_t txparams[AC_COUNT]; 626 char *srl, *sfbl, *lrl, *lfbl, *maxrate; 627 char **locals[] = { &srl, &sfbl, &lrl, &lfbl, &maxrate }; 628 629 /* build request block */ 630 memset(txparams, 0, sizeof(txparams)); 631 632 for (j = 0; j < AC_COUNT; j++) { 633 /* get packed nvram parameter */ 634 snprintf(nv, sizeof(nv), nv_name, prefix, mode[2].str, ac[j]); 635 nv_value = nvram_safe_get(nv); 636 strcpy(nv, nv_value); 637 /* unpack it */ 638 v = nv; 639 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) { 640 *locals[k] = v; 641 while (*v && *v != ' ') 642 v++; 643 if (*v) { 644 *v = 0; 645 v++; 646 } 647 } 648 649 /* update short retry limit */ 650 txparams[j].short_retry = atoi(srl); 651 652 /* update short fallback limit */ 653 txparams[j].short_fallback = atoi(sfbl); 654 655 /* update long retry limit */ 656 txparams[j].long_retry = atoi(lrl); 657 658 /* update long fallback limit */ 659 txparams[j].long_fallback = atoi(lfbl); 660 661 /* update max rate */ 662 txparams[j].max_rate = atoi(maxrate); 663 } 664 665 /* set the WME tx parameters */ 666 WL_IOVAR_SET(name, mode[2].req, txparams, sizeof(txparams)); 667 } 668 669 return; 670} 671 672#if defined(linux) || defined(__NetBSD__) 673#include <unistd.h> 674static void 675sleep_ms(const unsigned int ms) 676{ 677 usleep(1000*ms); 678} 679#elif defined(__ECOS) 680static void 681sleep_ms(const unsigned int ms) 682{ 683 cyg_tick_count_t ostick; 684 685 ostick = ms / 10; 686 cyg_thread_delay(ostick); 687} 688#else 689#error "sleep_ms() not defined for this OS!!!" 690#endif /* defined(linux) */ 691 692/* 693* The following condition(s) must be met when Auto Channel Selection 694* is enabled. 695* - the I/F is up (change radio channel requires it is up?) 696* - the AP must not be associated (setting SSID to empty should 697* make sure it for us) 698*/ 699static uint8 700wlconf_auto_channel(char *name) 701{ 702 int chosen = 0; 703 wl_uint32_list_t request; 704 int phytype; 705 int ret; 706 int i; 707 708 /* query the phy type */ 709 WL_GETINT(name, WLC_GET_PHYTYPE, &phytype); 710 711 request.count = 0; /* let the ioctl decide */ 712 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request)); 713 if (!ret) { 714 sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750); 715 for (i = 0; i < 100; i++) { 716 WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen); 717 if (!ret) 718 break; 719 sleep_ms(100); 720 } 721 } 722 WLCONF_DBG("interface %s: channel selected %d\n", name, chosen); 723 return chosen; 724} 725 726static chanspec_t 727wlconf_auto_chanspec(char *name) 728{ 729 chanspec_t chosen = 0; 730 int temp = 0; 731 wl_uint32_list_t request; 732 int ret; 733 int i; 734 735 request.count = 0; /* let the ioctl decide */ 736 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request)); 737 if (!ret) { 738 /* this time needs to be < 1000 to prevent mpc kicking in for 2nd radio */ 739 sleep_ms(500); 740 for (i = 0; i < 100; i++) { 741 WL_IOVAR_GETINT(name, "apcschspec", &temp); 742 if (!ret) 743 break; 744 sleep_ms(100); 745 } 746 } 747 748 chosen = (chanspec_t) temp; 749 WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen); 750 return chosen; 751} 752 753/* PHY type/BAND conversion */ 754#define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G) 755/* PHY type conversion */ 756#define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \ 757 (phy) == PHY_TYPE_B ? "b" : \ 758 (phy) == PHY_TYPE_LP ? "l" : \ 759 (phy) == PHY_TYPE_G ? "g" : \ 760 (phy) == PHY_TYPE_SSN ? "s" : \ 761 (phy) == PHY_TYPE_HT ? "h" : \ 762 (phy) == PHY_TYPE_AC ? "v" : \ 763 (phy) == PHY_TYPE_LCN ? "c" : "n") 764#define WLCONF_STR2PHYTYPE(ch) ((ch) == 'a' ? PHY_TYPE_A : \ 765 (ch) == 'b' ? PHY_TYPE_B : \ 766 (ch) == 'l' ? PHY_TYPE_LP : \ 767 (ch) == 'g' ? PHY_TYPE_G : \ 768 (ch) == 's' ? PHY_TYPE_SSN : \ 769 (ch) == 'h' ? PHY_TYPE_HT : \ 770 (ch) == 'v' ? PHY_TYPE_AC : \ 771 (ch) == 'c' ? PHY_TYPE_LCN : PHY_TYPE_N) 772 773#define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */ 774 775#define WLCONF_PHYTYPE_11N(phy) ((phy) == PHY_TYPE_N || (phy) == PHY_TYPE_SSN || \ 776 (phy) == PHY_TYPE_LCN || (phy) == PHY_TYPE_HT || \ 777 (phy) == PHY_TYPE_AC) 778 779struct bsscfg_info { 780 int idx; /* bsscfg index */ 781 char ifname[PREFIX_LEN]; /* OS name of interface (debug only) */ 782 char prefix[PREFIX_LEN]; /* prefix for nvram params (eg. "wl0.1_") */ 783}; 784 785struct bsscfg_list { 786 int count; 787 struct bsscfg_info bsscfgs[WL_MAXBSSCFG]; 788}; 789 790struct bsscfg_list * 791wlconf_get_bsscfgs(char* ifname, char* prefix) 792{ 793 char var[80]; 794 char tmp[100]; 795 char *next; 796 797 struct bsscfg_list *bclist; 798 struct bsscfg_info *bsscfg; 799 800 bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list)); 801 if (bclist == NULL) 802 return NULL; 803 memset(bclist, 0, sizeof(struct bsscfg_list)); 804 805 /* Set up Primary BSS Config information */ 806 bsscfg = &bclist->bsscfgs[0]; 807 bsscfg->idx = 0; 808 strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1); 809 strcpy(bsscfg->prefix, prefix); 810 bclist->count = 1; 811 812 /* additional virtual BSS Configs from wlX_vifs */ 813 foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) { 814 if (bclist->count == WL_MAXBSSCFG) { 815 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)" 816 "in nvram %s\n" 817 "while configuring interface \"%s\"\n", 818 ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var); 819 continue; 820 } 821 bsscfg = &bclist->bsscfgs[bclist->count]; 822 if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) { 823 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface " 824 "name \"%s\"\n", 825 ifname, var); 826 continue; 827 } 828 strncpy(bsscfg->ifname, var, PREFIX_LEN-1); 829 snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname); 830 bclist->count++; 831 } 832 833 return bclist; 834} 835 836static void 837wlconf_config_join_pref(char *name, int bsscfg_idx, int auth_val) 838{ 839 int ret = 0, i = 0; 840 841 if ((auth_val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) || 842 CHECK_PSK(auth_val)) { 843 uchar pref[] = { 844 /* WPA pref, 14 tuples */ 845 0x02, 0xaa, 0x00, 0x0e, 846 /* WPA2 AES (unicast) AES (multicast) */ 847 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x04, 848 /* WPA AES (unicast) AES (multicast) */ 849 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x04, 850 /* WPA2 AES (unicast) TKIP (multicast) */ 851 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x02, 852 /* WPA AES (unicast) TKIP (multicast) */ 853 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x02, 854 /* WPA2 AES (unicast) WEP-40 (multicast) */ 855 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x01, 856 /* WPA AES (unicast) WEP-40 (multicast) */ 857 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x01, 858 /* WPA2 AES (unicast) WEP-128 (multicast) */ 859 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x05, 860 /* WPA AES (unicast) WEP-128 (multicast) */ 861 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x05, 862 /* WPA2 TKIP (unicast) TKIP (multicast) */ 863 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x02, 864 /* WPA TKIP (unicast) TKIP (multicast) */ 865 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x02, 866 /* WPA2 TKIP (unicast) WEP-40 (multicast) */ 867 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x01, 868 /* WPA TKIP (unicast) WEP-40 (multicast) */ 869 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x01, 870 /* WPA2 TKIP (unicast) WEP-128 (multicast) */ 871 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x05, 872 /* WPA TKIP (unicast) WEP-128 (multicast) */ 873 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x05, 874 /* RSSI pref */ 875 0x01, 0x02, 0x00, 0x00, 876 }; 877 878 if (CHECK_PSK(auth_val)) { 879 for (i = 0; i < pref[3]; i ++) 880 pref[7 + i * 12] = 0x02; 881 } 882 883 WL_BSSIOVAR_SET(name, "join_pref", bsscfg_idx, pref, sizeof(pref)); 884 } 885 886} 887 888static void 889wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool id_supp, 890 bool check_join_pref) 891{ 892 int i; 893 int val; 894 int ret; 895 char tmp[100]; 896 bool need_join_pref = FALSE; 897#define AUTOWPA(cfg) ((cfg) == (WPA_AUTH_PSK | WPA2_AUTH_PSK)) 898 899 /* Set WSEC */ 900 /* 901 * Need to check errors (card may have changed) and change to 902 * defaults since the new chip may not support the requested 903 * encryptions after the card has been changed. 904 */ 905 if (wlconf_set_wsec(name, prefix, bsscfg_idx)) { 906 /* change nvram only, code below will pass them on */ 907 nvram_restore_var(prefix, "auth_mode"); 908 nvram_restore_var(prefix, "auth"); 909 /* reset wep to default */ 910 nvram_restore_var(prefix, "crypto"); 911 nvram_restore_var(prefix, "wep"); 912 wlconf_set_wsec(name, prefix, bsscfg_idx); 913 } 914 915 val = wlconf_akm_options(prefix); 916 if (!nvram_match(strcat_r(prefix, "mode", tmp), "ap")) 917 need_join_pref = (check_join_pref || id_supp) && AUTOWPA(val); 918 919 if (need_join_pref) 920 wlconf_config_join_pref(name, bsscfg_idx, val); 921 922 /* enable in-driver wpa supplicant? */ 923 if (id_supp && (CHECK_PSK(val))) { 924 wsec_pmk_t psk; 925 char *key; 926 927 if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) && 928 (strlen(key) < WSEC_MAX_PSK_LEN)) { 929 psk.key_len = (ushort) strlen(key); 930 psk.flags = WSEC_PASSPHRASE; 931 strcpy((char *)psk.key, key); 932 WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); 933 } 934 wl_iovar_setint(name, "sup_wpa", 1); 935 } 936 937 if (!need_join_pref) 938 WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val); 939 940 /* EAP Restrict if we have an AKM or radius authentication */ 941 val = ((val != 0) || (nvram_match(strcat_r(prefix, "auth_mode", tmp), "radius"))); 942 WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val); 943 944 /* Set WEP keys */ 945 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) { 946 for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++) 947 wlconf_set_wep_key(name, prefix, bsscfg_idx, i); 948 } 949 950 /* Set 802.11 authentication mode - open/shared */ 951 val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp))); 952 WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val); 953#ifdef MFP 954 /* Set MFP */ 955 val = WPA_AUTH_DISABLED; 956 WL_BSSIOVAR_GET(name, "wpa_auth", bsscfg_idx, &val, sizeof(val)); 957 if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { 958 val = atoi(nvram_safe_get(strcat_r(prefix, "mfp", tmp))); 959 WL_BSSIOVAR_SETINT(name, "mfp", bsscfg_idx, val); 960 } 961#endif 962} 963 964static void 965wlconf_set_ampdu_retry_limit(char *name, char *prefix) 966{ 967 int i, j, ret, nv_len; 968 struct ampdu_retry_tid retry_limit; 969 char *nv_name[2] = {"ampdu_rtylimit_tid", "ampdu_rr_rtylimit_tid"}; 970 char *iov_name[2] = {"ampdu_retry_limit_tid", "ampdu_rr_retry_limit_tid"}; 971 char *retry, *v, *nv_value, nv[100], tmp[100]; 972 973 /* Get packed AMPDU (rr) retry limit per-tid from NVRAM if present */ 974 for (i = 0; i < 2; i++) { 975 nv_value = nvram_safe_get(strcat_r(prefix, nv_name[i], tmp)); 976 nv_len = strlen(nv_value); 977 strcpy(nv, nv_value); 978 979 /* unpack it */ 980 v = nv; 981 for (j = 0; nv_len >= 0 && j < NUMPRIO; j++) { 982 retry = v; 983 while (*v && *v != ' ') { 984 v++; 985 nv_len--; 986 } 987 if (*v) { 988 *v = 0; 989 v++; 990 nv_len--; 991 } 992 /* set the AMPDU retry limit per-tid */ 993 retry_limit.tid = j; 994 retry_limit.retry = atoi(retry); 995 WL_IOVAR_SET(name, iov_name[i], &retry_limit, sizeof(retry_limit)); 996 } 997 } 998 999 return; 1000} 1001 1002/* 1003 * When N-mode is ON, AMPDU, AMSDU are enabled/disabled 1004 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any 1005 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off. 1006 * 1007 * WME/WMM is also set in this procedure as it depends on N. 1008 * N ==> WMM is on by default 1009 * 1010 * Returns WME setting. 1011 */ 1012static int 1013wlconf_ampdu_amsdu_set(char *name, char prefix[PREFIX_LEN], int nmode, int btc_mode, int ap) 1014{ 1015 bool ampdu_valid_option = FALSE; 1016 bool amsdu_valid_option = FALSE; 1017 int val, ampdu_option_val = OFF, amsdu_option_val = OFF; 1018 int rx_amsdu_in_ampdu_option_val = OFF; 1019 int wme_option_val = ON; /* On by default */ 1020 char caps[WLC_IOCTL_MEDLEN], var[80], *next, *wme_val; 1021 char buf[WLC_IOCTL_SMLEN]; 1022 int len = (sizeof("amsdu") - 1); 1023 int ret, phytype; 1024 wlc_rev_info_t rev; 1025#ifdef linux 1026 struct utsname unamebuf; 1027 1028 uname(&unamebuf); 1029#endif 1030 1031 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 1032 1033 WL_GETINT(name, WLC_GET_PHYTYPE, &phytype); 1034 1035 /* First, clear WMM settings to avoid conflicts */ 1036 WL_IOVAR_SETINT(name, "wme", OFF); 1037 1038 /* Get WME setting from NVRAM if present */ 1039 wme_val = nvram_get(strcat_r(prefix, "wme", caps)); 1040 if (wme_val && !strcmp(wme_val, "off")) { 1041 wme_option_val = OFF; 1042 } 1043 1044 /* Set options based on capability */ 1045 wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)); 1046 foreach(var, caps, next) { 1047 char *nvram_str; 1048 bool amsdu = 0; 1049 1050 /* Check for the capabilitiy 'amsdutx' */ 1051 if (strncmp(var, "amsdutx", sizeof(var)) == 0) { 1052 var[len] = '\0'; 1053 amsdu = 1; 1054 } 1055 nvram_str = nvram_get(strcat_r(prefix, var, buf)); 1056 if (!nvram_str) 1057 continue; 1058 1059 if (!strcmp(nvram_str, "on")) 1060 val = ON; 1061 else if (!strcmp(nvram_str, "off")) 1062 val = OFF; 1063 else if (!strcmp(nvram_str, "auto")) 1064 val = AUTO; 1065 else 1066 continue; 1067 1068 if (strncmp(var, "ampdu", sizeof(var)) == 0) { 1069 ampdu_valid_option = TRUE; 1070 ampdu_option_val = val; 1071 } 1072 1073 if (amsdu) { 1074 amsdu_valid_option = TRUE; 1075 amsdu_option_val = val; 1076 1077 nvram_str = nvram_get(strcat_r(prefix, "rx_amsdu_in_ampdu", buf)); 1078 if (nvram_str) { 1079 if (!strcmp(nvram_str, "on")) 1080 rx_amsdu_in_ampdu_option_val = ON; 1081 else if (!strcmp(nvram_str, "auto")) 1082 rx_amsdu_in_ampdu_option_val = AUTO; 1083 } 1084 1085 /* 1086 * Some tests show problems when AMSDU is enabled on TX 1087 * side together with ps-pretend. 1088 * Ps-pretend is used on AP only. 1089 * Let's disable AMSDU downstream unconditionally 1090 * in devicemode=1. 1091 * When ps-pretend be OK with AMSDU, below statement 1092 * need to be removed. 1093 */ 1094 if (ap && !strcmp(nvram_safe_get("devicemode"), "1")) { 1095 amsdu_option_val = OFF; 1096 } 1097 } 1098 } 1099 1100 if (nmode != OFF) { /* N-mode is ON/AUTO */ 1101 if (ampdu_valid_option) { 1102 if (ampdu_option_val != OFF) { 1103 WL_IOVAR_SETINT(name, "amsdu", OFF); 1104 WL_IOVAR_SETINT(name, "ampdu", ampdu_option_val); 1105 } else { 1106 WL_IOVAR_SETINT(name, "ampdu", OFF); 1107 } 1108 1109 wlconf_set_ampdu_retry_limit(name, prefix); 1110 1111#ifdef linux 1112 /* For MIPS routers set the num mpdu per ampdu limit to 32. We observed 1113 * that having this value at 32 helps with bi-di thru'put as well. 1114 */ 1115 if ((phytype == PHY_TYPE_AC) && 1116 (strncmp(unamebuf.machine, "mips", 4) == 0)) { 1117#ifndef __CONFIG_USBAP__ 1118 WL_IOVAR_SETINT(name, "ampdu_mpdu", 32); 1119#endif /* __CONFIG_USBAP__ */ 1120 } 1121#endif /* linux */ 1122 } 1123 1124 if (amsdu_valid_option) { 1125 if (amsdu_option_val != OFF) { /* AMPDU (above) has priority over AMSDU */ 1126 if (rev.corerev >= 40) { 1127 WL_IOVAR_SETINT(name, "amsdu", amsdu_option_val); 1128 } else if (ampdu_option_val == OFF) { 1129 WL_IOVAR_SETINT(name, "ampdu", OFF); 1130 WL_IOVAR_SETINT(name, "amsdu", amsdu_option_val); 1131 } 1132 } else 1133 WL_IOVAR_SETINT(name, "amsdu", OFF); 1134 } 1135 1136 WL_IOVAR_SETINT(name, "rx_amsdu_in_ampdu", rx_amsdu_in_ampdu_option_val); 1137 } else { 1138 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU; 1139 */ 1140 wl_iovar_setint(name, "amsdu", OFF); 1141 wl_iovar_setint(name, "ampdu", OFF); 1142 } 1143 1144 if (wme_option_val) { 1145 WL_IOVAR_SETINT(name, "wme", wme_option_val); 1146 wlconf_set_wme(name, prefix); 1147 } 1148 1149 return wme_option_val; 1150} 1151 1152/* Get configured bandwidth cap. */ 1153static int 1154wlconf_bw_cap(char *prefix, int bandtype) 1155{ 1156 char *str, tmp[100]; 1157 int bw_cap = WLC_BW_CAP_20MHZ; 1158 1159 if ((str = nvram_get(strcat_r(prefix, "bw_cap", tmp))) != NULL) 1160 bw_cap = atoi(str); 1161 else { 1162 /* Backward compatibility. Map to bandwidth cap bitmap values. */ 1163 int val = atoi(nvram_safe_get(strcat_r(prefix, "nbw_cap", tmp))); 1164 1165 if (((bandtype == WLC_BAND_2G) && (val == WLC_N_BW_40ALL)) || 1166 ((bandtype == WLC_BAND_5G) && 1167 (val == WLC_N_BW_40ALL || val == WLC_N_BW_20IN2G_40IN5G))) 1168 bw_cap = WLC_BW_CAP_40MHZ; 1169 else 1170 bw_cap = WLC_BW_CAP_20MHZ; 1171 } 1172 1173 return bw_cap; 1174} 1175 1176/* Set up TxBF. Called when i/f is down. */ 1177static void wlconf_set_txbf(char *name, char *prefix) 1178{ 1179 char *str, tmp[100]; 1180 wlc_rev_info_t rev; 1181 uint32 txbf_bfe_cap = 0; 1182 uint32 txbf_bfr_cap = 0; 1183 uint32 txbf_imp = 0; 1184 int ret = 0; 1185 1186 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 1187 1188 if (rev.corerev < 40) return; /* TxBF unsupported */ 1189 1190 if ((str = nvram_get(strcat_r(prefix, "txbf_bfr_cap", tmp))) != NULL) { 1191 txbf_bfr_cap = atoi(str); 1192 1193 if (txbf_bfr_cap) { 1194 /* Turning TxBF on (order matters) */ 1195 WL_IOVAR_SETINT(name, "txbf_bfr_cap", 1); 1196 WL_IOVAR_SETINT(name, "txbf", 1); 1197 } else { 1198 /* Similarly, turning TxBF off in reverse order */ 1199 WL_IOVAR_SETINT(name, "txbf", 0); 1200 WL_IOVAR_SETINT(name, "txbf_bfr_cap", 0); 1201 } 1202 } 1203 1204 if ((str = nvram_get(strcat_r(prefix, "txbf_bfe_cap", tmp))) != NULL) { 1205 txbf_bfe_cap = atoi(str); 1206 1207 WL_IOVAR_SETINT(name, "txbf_bfe_cap", txbf_bfe_cap ? 1 : 0); 1208 } 1209 1210 if ((str = nvram_get(strcat_r(prefix, "txbf_imp", tmp))) != NULL) { 1211 txbf_imp = atoi(str); 1212 1213 WL_IOVAR_SETINT(name, "txbf_imp", txbf_imp); 1214 } 1215} 1216 1217/* Set up TxBF timer. Called when i/f is up. */ 1218static void wlconf_set_txbf_timer(char *name, char *prefix) 1219{ 1220 char *str, tmp[100]; 1221 wlc_rev_info_t rev; 1222 uint32 txbf_timer = 0; 1223 int ret = 0; 1224 1225 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 1226 1227 if (rev.corerev < 40) return; /* TxBF unsupported */ 1228 1229 if ((str = nvram_get(strcat_r(prefix, "txbf_timer", tmp))) != NULL) { 1230 txbf_timer = (uint32) atoi(str); 1231 WL_IOVAR_SETINT(name, "txbf_timer", txbf_timer); 1232 } 1233} 1234 1235/* Apply Traffic Management filter settings stored in NVRAM */ 1236static void 1237trf_mgmt_settings(char *prefix, bool dwm_supported) 1238{ 1239 char buffer[sizeof(trf_mgmt_filter_t)*(MAX_NUM_TRF_MGMT_RULES+1)]; 1240 char iobuff[sizeof(trf_mgmt_filter_t)*(MAX_NUM_TRF_MGMT_RULES+1)+32]; 1241 int i, filterlen, ret = 0; 1242 trf_mgmt_config_t trf_mgmt_config; 1243 trf_mgmt_filter_list_t *trf_mgmt_filter_list; 1244 netconf_trmgmt_t nettrm; 1245 trf_mgmt_filter_t *trfmgmt; 1246 char *wlifname; 1247 struct in_addr ipaddr, ipmask; 1248 char nvram_ifname[32]; 1249 bool tm_filters_configured = FALSE; 1250 /* DWM variables */ 1251 bool dwm_filters_configured = FALSE; 1252 char dscp_filter_buffer[sizeof(trf_mgmt_filter_t)*(MAX_NUM_TRF_MGMT_DWM_RULES)]; 1253 char dscp_filter_iobuff[sizeof(trf_mgmt_filter_t)*(MAX_NUM_TRF_MGMT_DWM_RULES)+ 1254 sizeof("trf_mgmt_filters_add") + OFFSETOF(trf_mgmt_filter_list_t, filter)]; 1255 int dscp_filterlen; 1256 trf_mgmt_filter_t *trf_mgmt_dwm_filter; 1257 trf_mgmt_filter_list_t *trf_mgmt_dwm_filter_list = NULL; 1258 netconf_trmgmt_t nettrm_dwm; 1259 1260 snprintf(nvram_ifname, sizeof(nvram_ifname), "%sifname", prefix); 1261 wlifname = nvram_get(nvram_ifname); 1262 if (!wlifname) { 1263 return; 1264 } 1265 1266 trf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buffer; 1267 trfmgmt = &trf_mgmt_filter_list->filter[0]; 1268 1269 /* Initialize the common parameters */ 1270 memset(buffer, 0, sizeof(buffer)); 1271 memset(&trf_mgmt_config, 0, sizeof(trf_mgmt_config_t)); 1272 1273 /* no-rx packets, local subnet, don't override priority and no-traffic shape */ 1274 trf_mgmt_config.flags = (TRF_MGMT_FLAG_NO_RX | 1275 TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC | 1276 TRF_MGMT_FLAG_DISABLE_SHAPING); 1277 (void) inet_aton("192.168.1.1", &ipaddr); /* Dummy value */ 1278 (void) inet_aton("255.255.255.0", &ipmask); /* Dummy value */ 1279 trf_mgmt_config.host_ip_addr = ipaddr.s_addr; /* Dummy value */ 1280 trf_mgmt_config.host_subnet_mask = ipmask.s_addr; /* Dummy value */ 1281 trf_mgmt_config.downlink_bandwidth = 1; /* Dummy value */ 1282 trf_mgmt_config.uplink_bandwidth = 1; /* Dummy value */ 1283 1284 /* Read up to NUM_TFF_MGMT_FILTERS entries from NVRAM */ 1285 for (i = 0; i < MAX_NUM_TRF_MGMT_RULES; i++) { 1286 if (get_trf_mgmt_port(prefix, i, &nettrm) == FALSE) { 1287 continue; 1288 } 1289 if (nettrm.match.flags == NETCONF_DISABLED) { 1290 continue; 1291 } 1292 trfmgmt->dst_port = ntohs(nettrm.match.dst.ports[0]); 1293 trfmgmt->src_port = ntohs(nettrm.match.src.ports[0]); 1294 trfmgmt->prot = nettrm.match.ipproto; 1295 if (nettrm.favored) { 1296 trfmgmt->flags |= TRF_FILTER_FAVORED; 1297 } 1298 trfmgmt->priority = nettrm.prio; 1299 memcpy(&trfmgmt->dst_ether_addr, &nettrm.match.mac, sizeof(struct ether_addr)); 1300 if (nettrm.match.ipproto == IPPROTO_IP) { 1301 /* Enable MAC filter */ 1302 trf_mgmt_config.flags |= TRF_MGMT_FLAG_FILTER_ON_MACADDR; 1303 trfmgmt->flags |= TRF_FILTER_MAC_ADDR; 1304 } 1305 trf_mgmt_filter_list->num_filters += 1; 1306 trfmgmt++; 1307 } 1308 if (trf_mgmt_filter_list->num_filters) 1309 tm_filters_configured = TRUE; 1310 1311 if (dwm_supported) { 1312 trf_mgmt_dwm_filter_list = (trf_mgmt_filter_list_t *)dscp_filter_buffer; 1313 trf_mgmt_dwm_filter = &trf_mgmt_dwm_filter_list->filter[0]; 1314 memset(dscp_filter_buffer, 0, sizeof(dscp_filter_buffer)); 1315 1316 /* Read up to NUM_TFF_MGMT_FILTERS entries from NVRAM */ 1317 for (i = 0; i < MAX_NUM_TRF_MGMT_DWM_RULES; i++) { 1318 if (get_trf_mgmt_dwm(prefix, i, &nettrm_dwm) == FALSE) { 1319 continue; 1320 } 1321 if (nettrm_dwm.match.flags == NETCONF_DISABLED) { 1322 continue; 1323 } 1324 1325 trf_mgmt_dwm_filter->dscp = nettrm_dwm.match.dscp; 1326 if (nettrm_dwm.favored) 1327 trf_mgmt_dwm_filter->flags |= TRF_FILTER_FAVORED; 1328 trf_mgmt_dwm_filter->flags |= TRF_FILTER_DWM; 1329 trf_mgmt_dwm_filter->priority = nettrm_dwm.prio; 1330 trf_mgmt_dwm_filter++; 1331 trf_mgmt_dwm_filter_list->num_filters += 1; 1332 } 1333 if (trf_mgmt_dwm_filter_list->num_filters) 1334 dwm_filters_configured = TRUE; 1335 } 1336 1337 /* Disable traffic management module to initial known state */ 1338 trf_mgmt_config.trf_mgmt_enabled = 0; 1339 WL_IOVAR_SET(wlifname, "trf_mgmt_config", &trf_mgmt_config, sizeof(trf_mgmt_config_t)); 1340 1341 /* Add traffic management filter entries */ 1342 if (tm_filters_configured || dwm_filters_configured) { 1343 /* Enable traffic management module before adding filter mappings */ 1344 trf_mgmt_config.trf_mgmt_enabled = 1; 1345 WL_IOVAR_SET(wlifname, "trf_mgmt_config", &trf_mgmt_config, 1346 sizeof(trf_mgmt_config_t)); 1347 1348 if (tm_filters_configured) { 1349 /* Configure TM module filters mappings */ 1350 filterlen = trf_mgmt_filter_list->num_filters * 1351 sizeof(trf_mgmt_filter_t) + 1352 OFFSETOF(trf_mgmt_filter_list_t, filter); 1353 wl_iovar_setbuf(wlifname, "trf_mgmt_filters_add", trf_mgmt_filter_list, 1354 filterlen, iobuff, sizeof(iobuff)); 1355 } 1356 1357 if (dwm_filters_configured) { 1358 dscp_filterlen = trf_mgmt_dwm_filter_list->num_filters * 1359 sizeof(trf_mgmt_filter_t) + 1360 OFFSETOF(trf_mgmt_filter_list_t, filter); 1361 wl_iovar_setbuf(wlifname, "trf_mgmt_filters_add", trf_mgmt_dwm_filter_list, 1362 dscp_filterlen, dscp_filter_iobuff, sizeof(dscp_filter_iobuff)); 1363 } 1364 } 1365} 1366 1367#ifdef TRAFFIC_MGMT_RSSI_POLICY 1368static void 1369trf_mgmt_rssi_policy(char *prefix) 1370{ 1371 char *wlifname; 1372 char nvram_ifname[32]; 1373 char rssi_policy[64]; 1374 uint32 rssi_policy_value, ret; 1375 1376 /* Get wl interface name */ 1377 snprintf(nvram_ifname, sizeof(nvram_ifname), "%sifname", prefix); 1378 if ((wlifname = nvram_get(nvram_ifname)) == NULL) { 1379 return; 1380 } 1381 1382 /* Get RSSI policy from NVRAM variable wlx_trf_mgmt_rssi_policy */ 1383 snprintf(rssi_policy, sizeof(rssi_policy), "%strf_mgmt_rssi_policy", prefix); 1384 if (!nvram_invmatch(rssi_policy, "")) 1385 return; 1386 rssi_policy_value = atoi(nvram_get(rssi_policy)); 1387 1388 /* Enable/Disable RSSI policy depending on value of rssi_policy_value */ 1389 WL_IOVAR_SETINT(wlifname, "trf_mgmt_rssi_policy", rssi_policy_value); 1390} 1391#endif /* TRAFFIC_MGMT_RSSI_POLICY */ 1392 1393static int 1394wlconf_del_brcm_syscap_ie(char *name, int bsscfg_idx, char *oui) 1395{ 1396 int iebuf_len = 0; 1397 vndr_ie_setbuf_t *ie_setbuf = NULL; 1398 int iecount, i; 1399 1400 char getbuf[2048] = {0}; 1401 vndr_ie_buf_t *iebuf; 1402 vndr_ie_info_t *ieinfo; 1403 char *bufaddr; 1404 int buflen = 0; 1405 int found = 0; 1406 uint32 pktflag; 1407 uint32 frametype; 1408 int ret = 0; 1409 1410 frametype = VNDR_IE_BEACON_FLAG; 1411 1412 WL_BSSIOVAR_GET(name, "vndr_ie", bsscfg_idx, getbuf, 2048); 1413 iebuf = (vndr_ie_buf_t *)getbuf; 1414 1415 bufaddr = (char*)iebuf->vndr_ie_list; 1416 1417 for (i = 0; i < iebuf->iecount; i++) { 1418 ieinfo = (vndr_ie_info_t *)bufaddr; 1419 bcopy((char*)&ieinfo->pktflag, (char*)&pktflag, (int)sizeof(uint32)); 1420 if (pktflag == frametype) { 1421 if (!memcmp(ieinfo->vndr_ie_data.oui, oui, DOT11_OUI_LEN)) { 1422 found = 1; 1423 bufaddr = (char*) &ieinfo->vndr_ie_data; 1424 buflen = (int)ieinfo->vndr_ie_data.len + VNDR_IE_HDR_LEN; 1425 break; 1426 } 1427 } 1428 bufaddr = (char *)(ieinfo->vndr_ie_data.oui + ieinfo->vndr_ie_data.len); 1429 } 1430 1431 if (!found) 1432 goto err; 1433 1434 iebuf_len = buflen + sizeof(vndr_ie_setbuf_t) - sizeof(vndr_ie_t); 1435 ie_setbuf = (vndr_ie_setbuf_t *)malloc(iebuf_len); 1436 if (!ie_setbuf) { 1437 WLCONF_DBG("memory alloc failure\n"); 1438 ret = -1; 1439 goto err; 1440 } 1441 1442 memset(ie_setbuf, 0, iebuf_len); 1443 1444 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ 1445 strcpy(ie_setbuf->cmd, "del"); 1446 1447 /* Buffer contains only 1 IE */ 1448 iecount = 1; 1449 memcpy(&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int)); 1450 1451 memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, &frametype, sizeof(uint32)); 1452 1453 memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data, bufaddr, buflen); 1454 1455 WL_BSSIOVAR_SET(name, "vndr_ie", bsscfg_idx, ie_setbuf, iebuf_len); 1456 1457err: 1458 if (ie_setbuf) 1459 free(ie_setbuf); 1460 1461 return ret; 1462} 1463 1464static int 1465wlconf_set_brcm_syscap_ie(char *name, int bsscfg_idx, char *oui, uchar *data, int datalen) 1466{ 1467 vndr_ie_setbuf_t *ie_setbuf = NULL; 1468 unsigned int pktflag; 1469 int buflen, iecount; 1470 int ret = 0; 1471 1472 pktflag = VNDR_IE_BEACON_FLAG; 1473 1474 buflen = sizeof(vndr_ie_setbuf_t) + datalen - 1; 1475 ie_setbuf = (vndr_ie_setbuf_t *)malloc(buflen); 1476 if (!ie_setbuf) { 1477 WLCONF_DBG("memory alloc failure\n"); 1478 ret = -1; 1479 goto err; 1480 } 1481 1482 memset(ie_setbuf, 0, buflen); 1483 1484 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ 1485 strcpy(ie_setbuf->cmd, "add"); 1486 1487 /* Buffer contains only 1 IE */ 1488 iecount = 1; 1489 memcpy(&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int)); 1490 1491 /* The packet flag bit field indicates the packets that will contain this IE */ 1492 memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, sizeof(uint32)); 1493 1494 /* Now, add the IE to the buffer, +1: one byte OUI_TYPE */ 1495 ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = DOT11_OUI_LEN + datalen; 1496 1497 memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0], oui, DOT11_OUI_LEN); 1498 if (datalen > 0) 1499 memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0], data, 1500 datalen); 1501 1502 ret = wlconf_del_brcm_syscap_ie(name, bsscfg_idx, oui); 1503 if (ret) 1504 goto err; 1505 1506 WL_BSSIOVAR_SET(name, "vndr_ie", (int)bsscfg_idx, ie_setbuf, buflen); 1507 1508err: 1509 if (ie_setbuf) 1510 free(ie_setbuf); 1511 1512 return (ret); 1513} 1514 1515/* 1516 * wlconf_process_sta_config_entry() - process a single sta_config settings entry. 1517 * 1518 * This function processes a single sta_config settings entry by parsing the entry and 1519 * calling the appropriate IOVAR(s) to apply the settings in the driver. 1520 * 1521 * Inputs: 1522 * params - address of a nul terminated ascii string buffer containing a single sta_config 1523 * settings entry in the form "xx:xx:xx:xx:xx:xx,prio[,steerflag]". 1524 * 1525 * At least the mac address of the station to which the settings are to be applied needs 1526 * to be present, with one or more setting values, in a specific order. New settings must 1527 * be added at the end. Alternatively, we could allow "prio=<value>,steerflag=<value>" and 1528 * so on, but that would take some more parsing and use more nvram space. 1529 * 1530 * Outputs: 1531 * Driver settings may be updated. 1532 * 1533 * Returns: 1534 * This function returns a BCME_xxx status indicating success (BCME_OK) or failure. 1535 * 1536 * Side effects: The input buffer is trashed by the strsep() function. 1537 * 1538 */ 1539static int 1540wlconf_process_sta_config_entry(char *ifname, char *param_list) 1541{ 1542 enum { /* Parameter index in comma-separated list of settings. */ 1543 PARAM_MACADDRESS = 0, 1544 PARAM_PRIO = 1, 1545 PARAM_STEERFLAG = 2, 1546 PARAM_COUNT 1547 } param_idx = PARAM_MACADDRESS; 1548 char *param; 1549 struct ether_addr ea; 1550 char *end; 1551 uint32 value; 1552 1553 while ((param = strsep(¶m_list, ","))) { 1554 switch (param_idx) { 1555 1556 case PARAM_MACADDRESS: /* MAC Address - parse into ea */ 1557 if (!param || !ether_atoe(param, &ea.octet[0])) { 1558 return BCME_BADADDR; 1559 } 1560 break; 1561 1562 case PARAM_PRIO: /* prio value - parse and apply through "staprio" iovar */ 1563 if (*param) { /* If no value is provided, do not configure the prio */ 1564 wl_staprio_cfg_t staprio_arg; 1565 int ret; 1566 1567 value = strtol(param, &end, 0); 1568 if (*end != '\0') { 1569 return BCME_BADARG; 1570 } 1571 memset(&staprio_arg, 0, sizeof(staprio_arg)); 1572 memcpy(&staprio_arg.ea, &ea, sizeof(ea)); 1573 staprio_arg.prio = value; /* prio is byte sized, no htod() needed */ 1574 WL_IOVAR_SET(ifname, "staprio", &staprio_arg, sizeof(staprio_arg)); 1575 } 1576 break; 1577 1578 case PARAM_STEERFLAG: 1579 if (*param) { 1580 value = strtol(param, &end, 0); 1581 if (*end != '\0') { 1582 return BCME_BADARG; 1583 } 1584 } 1585 break; 1586 1587 default: 1588 /* Future use parameter already set in nvram config - ignore. */ 1589 break; 1590 } 1591 ++param_idx; 1592 } 1593 1594 if (param_idx <= PARAM_PRIO) { /* No mac address and/or no parameters at all, forget it. */ 1595 return BCME_BADARG; 1596 } 1597 1598 return BCME_OK; 1599} 1600 1601#define VIFNAME_LEN 16 1602 1603#define AMPDU_DENSITY_8USEC 6 1604 1605/* configure the specified wireless interface */ 1606int 1607wlconf(char *name) 1608{ 1609 int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0; 1610 int bcmerr; 1611 int error_bg, error_a; 1612 struct bsscfg_list *bclist = NULL; 1613 struct bsscfg_info *bsscfg = NULL; 1614 char tmp[100], tmp2[100], prefix[PREFIX_LEN]; 1615 char var[80], *next, *str, *addr = NULL; 1616 /* Pay attention to buffer length requirements when using this */ 1617 char buf[WLC_IOCTL_SMLEN*2] __attribute__ ((aligned(4))); 1618 char *country; 1619 char *country_rev; 1620 wlc_rev_info_t rev; 1621 channel_info_t ci; 1622 struct maclist *maclist; 1623 struct ether_addr *ea; 1624 wlc_ssid_t ssid; 1625 wl_rateset_t rs; 1626 unsigned int i; 1627 char eaddr[32]; 1628 int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0, wmf = 0; 1629 int rxchain_pwrsave = 0, radio_pwrsave = 0; 1630 wl_country_t country_spec = {{0}, 0, {0}}; 1631 char *ba; 1632 char *preauth; 1633 int set_preauth; 1634 int wlunit = -1; 1635 int wlsubunit = -1; 1636 int wl_ap_build = 0; /* wl compiled with AP capabilities */ 1637 char cap[WLC_IOCTL_SMLEN]; 1638 char caps[WLC_IOCTL_MEDLEN]; 1639 int btc_mode; 1640 uint32 leddc; 1641 uint nbw = WL_CHANSPEC_BW_20; 1642 int nmode = OFF; /* 802.11n support */ 1643 char vif_addr[WLC_IOCTL_SMLEN]; 1644 int max_no_vifs = 0; 1645 int wme_global; 1646 int max_assoc = -1; 1647 bool ure_enab = FALSE; 1648 bool radar_enab = FALSE; 1649 bool obss_coex = FALSE, psta, psr; 1650 chanspec_t chanspec = 0; 1651 int wet_tunnel_cap = 0, wet_tunnel_enable = 0; 1652 brcm_prop_ie_t brcm_syscap_ie; 1653 1654 /* wlconf doesn't work for virtual i/f, so if we are given a 1655 * virtual i/f return 0 if that interface is in it's parent's "vifs" 1656 * list otherwise return -1 1657 */ 1658 if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0) { 1659 if (wlsubunit >= 0) { 1660 /* we have been given a virtual i/f, 1661 * is it in it's parent i/f's virtual i/f list? 1662 */ 1663 sprintf(tmp, "wl%d_vifs", wlunit); 1664 1665 if (strstr(nvram_safe_get(tmp), name) == NULL) 1666 return -1; /* config error */ 1667 else 1668 return 0; /* okay */ 1669 } 1670 } else { 1671 return -1; 1672 } 1673 1674 /* clean up tmp */ 1675 memset(tmp, 0, sizeof(tmp)); 1676 1677 /* because of ifdefs in wl driver, when we don't have AP capabilities we 1678 * can't use the same iovars to configure the wl. 1679 * so we use "wl_ap_build" to help us know how to configure the driver 1680 */ 1681 if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps))) 1682 return -1; 1683 1684 foreach(cap, caps, next) { 1685 if (!strcmp(cap, "ap")) { 1686 wl_ap_build = 1; 1687 } else if (!strcmp(cap, "mbss16")) 1688 max_no_vifs = 16; 1689 else if (!strcmp(cap, "mbss8")) 1690 max_no_vifs = 8; 1691 else if (!strcmp(cap, "mbss4")) 1692 max_no_vifs = 4; 1693 else if (!strcmp(cap, "wmf")) 1694 wmf = 1; 1695 else if (!strcmp(cap, "rxchain_pwrsave")) 1696 rxchain_pwrsave = 1; 1697 else if (!strcmp(cap, "radio_pwrsave")) 1698 radio_pwrsave = 1; 1699 else if (!strcmp(cap, "wet_tunnel")) 1700 wet_tunnel_cap = 1; 1701 } 1702 1703 /* Check interface (fail silently for non-wl interfaces) */ 1704 if ((ret = wl_probe(name))) 1705 return ret; 1706 1707 /* Get MAC address */ 1708 (void) wl_hwaddr(name, (uchar *)buf); 1709 memcpy(vif_addr, buf, ETHER_ADDR_LEN); 1710 1711 /* Get instance */ 1712 WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit)); 1713 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 1714 1715 /* Restore defaults if per-interface parameters do not exist */ 1716// restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp)); 1717 restore_defaults = !strlen(nvram_safe_get(strcat_r(prefix, "ifname", tmp))); 1718// nvram_validate_all(prefix, restore_defaults); 1719 nvram_set(strcat_r(prefix, "ifname", tmp), name); 1720 nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr)); 1721 snprintf(buf, sizeof(buf), "%d", unit); 1722 nvram_set(strcat_r(prefix, "unit", tmp), buf); 1723 1724 if (restore_defaults) { 1725 wlconf_set_current_txparam_into_nvram(name, prefix); 1726 } 1727#ifdef BCMDBG 1728 /* Apply message level */ 1729 if (nvram_invmatch("wl_msglevel", "")) { 1730 val = (int)strtoul(nvram_get("wl_msglevel"), NULL, 0); 1731 1732 if (nvram_invmatch("wl_msglevel2", "")) { 1733 struct wl_msglevel2 msglevel64; 1734 msglevel64.low = val; 1735 val = (int)strtoul(nvram_get("wl_msglevel2"), NULL, 0); 1736 msglevel64.high = val; 1737 WL_IOVAR_SET(name, "msglevel", &msglevel64, sizeof(struct wl_msglevel2)); 1738 } 1739 else 1740 WL_IOCTL(name, WLC_SET_MSGLEVEL, &val, sizeof(val)); 1741 } 1742#endif 1743 1744 /* Bring the interface down */ 1745 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); 1746 1747 /* Disable all BSS Configs */ 1748 for (i = 0; i < WL_MAXBSSCFG; i++) { 1749 struct {int bsscfg_idx; int enable;} setbuf; 1750 setbuf.bsscfg_idx = i; 1751 setbuf.enable = 0; 1752 1753 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf)); 1754 if (ret) { 1755 wl_iovar_getint(name, "bcmerror", &bcmerr); 1756 /* fail quietly on a range error since the driver may 1757 * support fewer bsscfgs than we are prepared to configure 1758 */ 1759 if (bcmerr == BCME_RANGE) 1760 break; 1761 } 1762 if (ret) { 1763 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0" 1764 " (down) failed, ret = %d, bcmerr = %d\n", 1765 __LINE__, name, i, ret, bcmerr); 1766 } 1767 } 1768 1769 /* Get the list of BSS Configs */ 1770 bclist = wlconf_get_bsscfgs(name, prefix); 1771 if (bclist == NULL) { 1772 ret = -1; 1773 goto exit; 1774 } 1775 1776#ifdef BCMDBG 1777 strcat_r(prefix, "vifs", tmp); 1778 printf("BSS Config summary: primary -> \"%s\", %s -> \"%s\"\n", name, tmp, 1779 nvram_safe_get(tmp)); 1780 for (i = 0; i < bclist->count; i++) { 1781 printf("BSS Config \"%s\": index %d\n", 1782 bclist->bsscfgs[i].ifname, bclist->bsscfgs[i].idx); 1783 } 1784#endif 1785 1786 /* create a wlX.Y_ifname nvram setting */ 1787 for (i = 1; i < bclist->count; i++) { 1788 bsscfg = &bclist->bsscfgs[i]; 1789#if defined(linux) || defined(__ECOS) || defined(__NetBSD__) 1790 strcpy(var, bsscfg->ifname); 1791#endif 1792 nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var); 1793 } 1794 1795 str = nvram_safe_get(strcat_r(prefix, "mode", tmp)); 1796 1797 /* If ure_disable is not present or is 1, ure is not enabled; 1798 * that is, if it is present and 0, ure is enabled. 1799 */ 1800 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */ 1801 ure_enab = TRUE; 1802 } 1803 if (wl_ap_build) { 1804 /* Enable MBSS mode if appropriate. */ 1805 if (!ure_enab && strcmp(str, "psr")) { 1806#ifndef __CONFIG_USBAP__ 1807 WL_IOVAR_SETINT(name, "mbss", (bclist->count >= 1)); 1808#else 1809 WL_IOVAR_SETINT(name, "mbss", (bclist->count >= 2)); 1810#endif 1811 } else 1812 WL_IOVAR_SETINT(name, "mbss", 0); 1813 1814 /* 1815 * Set SSID for each BSS Config 1816 */ 1817 for (i = 0; i < bclist->count; i++) { 1818 bsscfg = &bclist->bsscfgs[i]; 1819 strcat_r(bsscfg->prefix, "ssid", tmp); 1820 ssid.SSID_len = strlen(nvram_safe_get(tmp)); 1821 if (ssid.SSID_len > sizeof(ssid.SSID)) 1822 ssid.SSID_len = sizeof(ssid.SSID); 1823 strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len); 1824 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) " 1825 "with SSID \"%s\"\n", name, bsscfg->idx, 1826 bsscfg->ifname, nvram_safe_get(tmp)); 1827 WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, 1828 sizeof(ssid)); 1829 } 1830 } 1831 1832 /* Create addresses for VIFs */ 1833 if (!ure_enab && strcmp(str, "psr")) { 1834 /* set local bit for our MBSS vif base */ 1835 ETHER_SET_LOCALADDR(vif_addr); 1836 1837 /* construct and set other wlX.Y_hwaddr */ 1838 for (i = 1; i < max_no_vifs; i++) { 1839 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i); 1840 addr = nvram_safe_get(tmp); 1841 if (!strcmp(addr, "")) { 1842 vif_addr[5] = (vif_addr[5] & ~(max_no_vifs-1)) 1843 | ((max_no_vifs-1) & (vif_addr[5]+1)); 1844 1845 nvram_set(tmp, ether_etoa((uchar *)vif_addr, eaddr)); 1846 } 1847 } 1848 1849 for (i = 0; i < bclist->count; i++) { 1850 bsscfg = &bclist->bsscfgs[i]; 1851 /* Ignore primary */ 1852 if (bsscfg->idx == 0) 1853 continue; 1854 1855 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, bsscfg->idx); 1856 ether_atoe(nvram_safe_get(tmp), (unsigned char *)eaddr); 1857 WL_BSSIOVAR_SET(name, "cur_etheraddr", bsscfg->idx, eaddr, ETHER_ADDR_LEN); 1858 } 1859 } else { /* One of URE or Proxy STA Repeater is enabled */ 1860 /* URE/PSR is on, so set wlX.1 hwaddr is same as that of primary interface */ 1861 snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit); 1862 WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr, 1863 ETHER_ADDR_LEN); 1864 nvram_set(tmp, ether_etoa((uchar *)vif_addr, eaddr)); 1865 } 1866 1867 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */ 1868 str = nvram_safe_get(strcat_r(prefix, "mode", tmp)); 1869 ap = (!strcmp(str, "") || !strcmp(str, "ap")); 1870 apsta = (!strcmp(str, "apsta") || 1871 ((!strcmp(str, "sta") || !strcmp(str, "psr") || !strcmp(str, "wet")) && 1872 bclist->count > 1)); 1873 sta = (!strcmp(str, "sta") && bclist->count == 1); 1874 wds = !strcmp(str, "wds"); 1875 wet = !strcmp(str, "wet"); 1876 mac_spoof = !strcmp(str, "mac_spoof"); 1877 psta = !strcmp(str, "psta"); 1878 psr = !strcmp(str, "psr"); 1879 1880 /* set apsta var first, because APSTA mode takes precedence */ 1881 WL_IOVAR_SETINT(name, "apsta", apsta); 1882 1883 /* Set AP mode */ 1884 val = (ap || apsta || wds) ? 1 : 0; 1885 WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val)); 1886 1887 /* Turn WET mode ON or OFF based on selected mode */ 1888 WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet)); 1889 1890 if (mac_spoof) { 1891 sta = 1; 1892 WL_IOVAR_SETINT(name, "mac_spoof", 1); 1893 } 1894 1895 /* For STA configurations, configure association retry time. 1896 * Use specified time (capped), or mode-specific defaults. 1897 */ 1898 if (sta || wet || apsta || psta || psr) { 1899 char *sta_retry_time_name = "sta_retry_time"; 1900 char *assoc_retry_max_name = "assoc_retry_max"; 1901 struct { 1902 int val; 1903 int band; 1904 } roam; 1905 1906 str = nvram_safe_get(strcat_r(prefix, sta_retry_time_name, tmp)); 1907 WL_IOVAR_SETINT(name, sta_retry_time_name, atoi(str)); 1908 1909 /* Set the wlX_assoc_retry_max, but only if one was specified. */ 1910 if ((str = nvram_get(strcat_r(prefix, assoc_retry_max_name, tmp)))) { 1911 WL_IOVAR_SETINT(name, assoc_retry_max_name, atoi(str)); 1912 } 1913 1914 roam.val = WLC_ROAM_NEVER_ROAM_TRIGGER; 1915 roam.band = WLC_BAND_ALL; 1916 WL_IOCTL(name, WLC_SET_ROAM_TRIGGER, &roam, sizeof(roam)); 1917 } 1918 1919 /* Retain remaining WET effects only if not APSTA */ 1920 wet &= !apsta; 1921 1922 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */ 1923 val = 1; 1924 if (wet || sta || psta || psr) 1925 val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp))); 1926 WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val)); 1927 1928 /* Set DWDS only for AP or STA modes */ 1929 for (i = 0; i < bclist->count; i++) { 1930 val = 0; 1931 bsscfg = &bclist->bsscfgs[i]; 1932 1933 if (ap || sta || psta || psr || (apsta && !wet)) { 1934 strcat_r(bsscfg->prefix, "dwds", tmp); 1935 val = atoi(nvram_safe_get(tmp)); 1936 } 1937 WL_BSSIOVAR_SETINT(name, "dwds", bsscfg->idx, val); 1938 } 1939 1940 /* Set The AP MAX Associations Limit */ 1941 if (ap || apsta) { 1942 max_assoc = val = atoi(nvram_safe_get(strcat_r(prefix, "maxassoc", tmp))); 1943 if (val > 0) { 1944 WL_IOVAR_SETINT(name, "maxassoc", val); 1945 } else { /* Get value from driver if not in nvram */ 1946 WL_IOVAR_GETINT(name, "maxassoc", &max_assoc); 1947 } 1948 } 1949 if (!wet && !sta) 1950 WL_IOVAR_SETINT(name, "mpc", OFF); 1951 1952 /* Set the Proxy STA or Repeater mode */ 1953 if (psta) { 1954 WL_IOVAR_SETINT(name, "psta", PSTA_MODE_PROXY); 1955 /* Set inactivity timer */ 1956 str = nvram_get(strcat_r(prefix, "psta_inact", tmp)); 1957 if (str) { 1958 val = atoi(str); 1959 WL_IOVAR_SETINT(name, "psta_inact", val); 1960 } 1961 } else if (psr) { 1962 WL_IOVAR_SETINT(name, "psta", PSTA_MODE_REPEATER); 1963 val = atoi(nvram_safe_get(strcat_r(prefix, "psr_mrpt", tmp))); 1964 WL_IOVAR_SETINT(name, "psta_mrpt", val); 1965 } else { 1966 WL_IOVAR_SETINT(name, "psta", PSTA_MODE_DISABLED); 1967 } 1968 1969 /* Turn WET tunnel mode ON or OFF */ 1970 if ((ap || apsta) && (wet_tunnel_cap)) { 1971 if (atoi(nvram_safe_get(strcat_r(prefix, "wet_tunnel", tmp))) == 1) { 1972 WL_IOVAR_SETINT(name, "wet_tunnel", 1); 1973 wet_tunnel_enable = 1; 1974 } else { 1975 WL_IOVAR_SETINT(name, "wet_tunnel", 0); 1976 } 1977 } 1978 1979 for (i = 0; i < bclist->count; i++) { 1980 char *subprefix; 1981 bsscfg = &bclist->bsscfgs[i]; 1982 1983 /* XXXMSSID: The note about setting preauth now does not seem right. 1984 * NAS brings the BSS up if it runs, so setting the preauth value 1985 * will make it in the bcn/prb. If that is right, we can move this 1986 * chunk out of wlconf. 1987 */ 1988 /* 1989 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down 1990 * if we do it in the NAS we need to bring down the interface and up to make 1991 * it affect in the beacons 1992 */ 1993 if (ap || (apsta && bsscfg->idx != 0)) { 1994 set_preauth = 1; 1995 preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp)); 1996 if (strlen (preauth) != 0) { 1997 set_preauth = atoi(preauth); 1998 } 1999 wlconf_set_preauth(name, bsscfg->idx, set_preauth); 2000 } 2001 2002 /* Clear BRCM System level Capability IE */ 2003 memset(&brcm_syscap_ie, 0, sizeof(brcm_prop_ie_t)); 2004 brcm_syscap_ie.type = BRCM_SYSCAP_IE_TYPE; 2005 2006 /* Add WET TUNNEL to IE */ 2007 if (wet_tunnel_enable) 2008 brcm_syscap_ie.cap |= BRCM_SYSCAP_WET_TUNNEL; 2009 2010 subprefix = apsta ? prefix : bsscfg->prefix; 2011 2012 if (ap || (apsta && bsscfg->idx != 0)) { 2013 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "bss_maxassoc", tmp))); 2014 if (val > 0) { 2015 WL_BSSIOVAR_SETINT(name, "bss_maxassoc", bsscfg->idx, val); 2016 } else if (max_assoc > 0) { /* Set maxassoc same as global if not set */ 2017 snprintf(var, sizeof(var), "%d", max_assoc); 2018 nvram_set(tmp, var); 2019 } 2020 } 2021 2022 /* Set network type */ 2023 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "closed", tmp))); 2024 WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val); 2025 2026 /* Set the ap isolate mode */ 2027 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "ap_isolate", tmp))); 2028 WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val); 2029 2030 /* Set the WMF enable mode */ 2031 if (wmf) { 2032 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "wmf_bss_enable", tmp))); 2033 WL_BSSIOVAR_SETINT(name, "wmf_bss_enable", bsscfg->idx, val); 2034 2035 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, 2036 "wmf_psta_disable", tmp))); 2037 WL_BSSIOVAR_SETINT(name, "wmf_psta_disable", bsscfg->idx, val); 2038 } 2039 2040 /* Set the Multicast Reverse Translation enable mode */ 2041 if (wet || psta || psr) { 2042 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, 2043 "mcast_regen_bss_enable", tmp))); 2044 WL_BSSIOVAR_SETINT(name, "mcast_regen_bss_enable", bsscfg->idx, val); 2045 } 2046 2047 if (rxchain_pwrsave) { 2048 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "rxchain_pwrsave_enable", 2049 tmp))); 2050 WL_BSSIOVAR_SETINT(name, "rxchain_pwrsave_enable", bsscfg->idx, val); 2051 2052 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, 2053 "rxchain_pwrsave_quiet_time", tmp))); 2054 WL_BSSIOVAR_SETINT(name, "rxchain_pwrsave_quiet_time", bsscfg->idx, val); 2055 2056 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "rxchain_pwrsave_pps", 2057 tmp))); 2058 WL_BSSIOVAR_SETINT(name, "rxchain_pwrsave_pps", bsscfg->idx, val); 2059 2060 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, 2061 "rxchain_pwrsave_stas_assoc_check", tmp))); 2062 WL_BSSIOVAR_SETINT(name, "rxchain_pwrsave_stas_assoc_check", bsscfg->idx, 2063 val); 2064 } 2065 2066 if (radio_pwrsave) { 2067 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "radio_pwrsave_enable", 2068 tmp))); 2069 WL_BSSIOVAR_SETINT(name, "radio_pwrsave_enable", bsscfg->idx, val); 2070 2071 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, 2072 "radio_pwrsave_quiet_time", tmp))); 2073 WL_BSSIOVAR_SETINT(name, "radio_pwrsave_quiet_time", bsscfg->idx, val); 2074 2075 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "radio_pwrsave_pps", 2076 tmp))); 2077 WL_BSSIOVAR_SETINT(name, "radio_pwrsave_pps", bsscfg->idx, val); 2078 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "radio_pwrsave_level", 2079 tmp))); 2080 WL_BSSIOVAR_SETINT(name, "radio_pwrsave_level", bsscfg->idx, val); 2081 2082 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, 2083 "radio_pwrsave_stas_assoc_check", tmp))); 2084 WL_BSSIOVAR_SETINT(name, "radio_pwrsave_stas_assoc_check", bsscfg->idx, 2085 val); 2086 } 2087 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "aspm", tmp))); 2088 WL_BSSIOVAR_SETINT(name, "aspm", bsscfg->idx, val); 2089 2090 /* Configure SYSCAP IE to driver */ 2091 if (brcm_syscap_ie.cap) { 2092 wlconf_set_brcm_syscap_ie(name, bsscfg->idx, 2093 BRCM_PROP_OUI, (uchar *)&(brcm_syscap_ie.type), 2094 sizeof(brcm_syscap_ie.type) + 2095 sizeof(brcm_syscap_ie.cap)); 2096 } 2097 } 2098 2099 /* Set up the country code */ 2100 (void) strcat_r(prefix, "country_code", tmp); 2101 country = nvram_get(tmp); 2102 (void) strcat_r(prefix, "country_rev", tmp2); 2103 country_rev = nvram_get(tmp2); 2104 if ((country && country[0] != '\0') && (country_rev && country_rev[0] != '\0')) { 2105 /* Initialize the wl country parameter */ 2106 strncpy(country_spec.country_abbrev, country, WLC_CNTRY_BUF_SZ-1); 2107 country_spec.country_abbrev[WLC_CNTRY_BUF_SZ-1] = '\0'; 2108 strncpy(country_spec.ccode, country, WLC_CNTRY_BUF_SZ-1); 2109 country_spec.ccode[WLC_CNTRY_BUF_SZ-1] = '\0'; 2110 country_spec.rev = atoi(country_rev); 2111 2112 WL_IOVAR_SET(name, "country", &country_spec, sizeof(country_spec)); 2113 } else { 2114 /* Get the default country code if undefined */ 2115 wl_iovar_get(name, "country", &country_spec, sizeof(country_spec)); 2116 2117 /* Add the new NVRAM variable */ 2118 nvram_set("wl_country_code", country_spec.ccode); 2119 (void) strcat_r(prefix, "country_code", tmp); 2120 nvram_set(tmp, country_spec.ccode); 2121 snprintf(buf, sizeof(buf), "%d", country_spec.rev); 2122 nvram_set("wl_country_rev", buf); 2123 (void) strcat_r(prefix, "country_rev", tmp); 2124 nvram_set(tmp, buf); 2125 } 2126 2127 /* Change LED Duty Cycle */ 2128 leddc = (uint32)strtoul(nvram_safe_get(strcat_r(prefix, "leddc", tmp)), NULL, 16); 2129 if (leddc) 2130 WL_IOVAR_SETINT(name, "leddc", leddc); 2131 2132 /* Enable or disable the radio */ 2133 val = nvram_match(strcat_r(prefix, "radio", tmp), "0"); 2134 val += WL_RADIO_SW_DISABLE << 16; 2135 WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val)); 2136 2137 /* Get supported phy types */ 2138 WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var)); 2139 nvram_set(strcat_r(prefix, "phytypes", tmp), var); 2140 2141 /* Get radio IDs */ 2142 *(next = buf) = '\0'; 2143 for (i = 0; i < strlen(var); i++) { 2144 /* Switch to band */ 2145 val = WLCONF_STR2PHYTYPE(var[i]); 2146 if (WLCONF_PHYTYPE_11N(val)) { 2147 WL_GETINT(name, WLC_GET_BAND, &val); 2148 } else 2149 val = WLCONF_PHYTYPE2BAND(val); 2150 WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val)); 2151 /* Get radio ID on this band */ 2152 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 2153 next += sprintf(next, "%sBCM%X", i ? " " : "", 2154 (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT); 2155 } 2156 nvram_set(strcat_r(prefix, "radioids", tmp), buf); 2157 2158 /* Set band */ 2159 str = nvram_get(strcat_r(prefix, "phytype", tmp)); 2160 val = str ? WLCONF_STR2PHYTYPE(str[0]) : PHY_TYPE_G; 2161 /* For NPHY use band value from NVRAM */ 2162 if (WLCONF_PHYTYPE_11N(val)) { 2163 str = nvram_get(strcat_r(prefix, "nband", tmp)); 2164 if (str) 2165 val = atoi(str); 2166 else { 2167 WL_GETINT(name, WLC_GET_BAND, &val); 2168 } 2169 } else 2170 val = WLCONF_PHYTYPE2BAND(val); 2171 2172 WL_SETINT(name, WLC_SET_BAND, val); 2173 2174 /* Check errors (card may have changed) */ 2175 if (ret) { 2176 /* default band to the first band in band list */ 2177 val = WLCONF_STR2PHYTYPE(var[0]); 2178 val = WLCONF_PHYTYPE2BAND(val); 2179 WL_SETINT(name, WLC_SET_BAND, val); 2180 } 2181 2182 /* Store the resolved bandtype */ 2183 bandtype = val; 2184 2185 /* Check errors again (will cover 5Ghz-only cards) */ 2186 if (ret) { 2187 int list[3]; 2188 2189 /* default band to the first band in band list */ 2190 wl_ioctl(name, WLC_GET_BANDLIST, list, sizeof(list)); 2191 WL_SETINT(name, WLC_SET_BAND, list[1]); 2192 2193 /* Read it back, and set bandtype accordingly */ 2194 WL_GETINT(name, WLC_GET_BAND, &bandtype); 2195 } 2196 2197 /* Get current core revision */ 2198 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev)); 2199 snprintf(buf, sizeof(buf), "%d", rev.corerev); 2200 nvram_set(strcat_r(prefix, "corerev", tmp), buf); 2201 2202 if ((rev.chipnum == BCM4716_CHIP_ID) || (rev.chipnum == BCM47162_CHIP_ID) || 2203 (rev.chipnum == BCM4748_CHIP_ID) || (rev.chipnum == BCM4331_CHIP_ID) || 2204 (rev.chipnum == BCM43431_CHIP_ID) || (rev.chipnum == BCM5357_CHIP_ID) || 2205 (rev.chipnum == BCM53572_CHIP_ID) || (rev.chipnum == BCM43236_CHIP_ID)) { 2206 int pam_mode = WLC_N_PREAMBLE_GF_BRCM; /* default GF-BRCM */ 2207 2208 strcat_r(prefix, "mimo_preamble", tmp); 2209 if (nvram_match(tmp, "mm")) 2210 pam_mode = WLC_N_PREAMBLE_MIXEDMODE; 2211 else if (nvram_match(tmp, "gf")) 2212 pam_mode = WLC_N_PREAMBLE_GF; 2213 else if (nvram_match(tmp, "auto")) 2214 pam_mode = -1; 2215 WL_IOVAR_SETINT(name, "mimo_preamble", pam_mode); 2216 } 2217 2218 /* Making default ampdu_density to 8usec in order to improve throughput 2219 * of very small packet sizes (64, 88, 128,..). 2220 */ 2221 if (rev.chipnum == BCM43217_CHIP_ID) 2222 WL_IOVAR_SETINT(name, "ampdu_rx_density", AMPDU_DENSITY_8USEC); 2223 2224 if ((rev.chipnum == BCM5357_CHIP_ID) || (rev.chipnum == BCM53572_CHIP_ID)) { 2225 val = atoi(nvram_safe_get("coma_sleep")); 2226 if (val > 0) { 2227 struct {int sleep; int delay;} setbuf; 2228 nvram_unset("coma_sleep"); 2229 nvram_commit(); 2230 setbuf.sleep = val; 2231 setbuf.delay = 1; 2232 WL_IOVAR_SET(name, "coma", &setbuf, sizeof(setbuf)); 2233 } 2234 } 2235 2236 /* Get current phy type */ 2237 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); 2238 snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype)); 2239 nvram_set(strcat_r(prefix, "phytype", tmp), buf); 2240 2241 /* Setup regulatory mode */ 2242 strcat_r(prefix, "reg_mode", tmp); 2243 if (nvram_match(tmp, "off")) { 2244 val = 0; 2245 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); 2246 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); 2247 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); 2248 } else if (nvram_match(tmp, "h") || nvram_match(tmp, "strict_h")) { 2249 val = 0; 2250 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); 2251 val = 1; 2252 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); 2253 radar_enab = TRUE; 2254 if (nvram_match(tmp, "h")) 2255 val = 1; 2256 else 2257 val = 2; 2258 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); 2259 2260 /* Set the CAC parameters, if they exist in nvram. */ 2261 if ((str = nvram_get(strcat_r(prefix, "dfs_preism", tmp)))) { 2262 val = atoi(str); 2263 wl_iovar_setint(name, "dfs_preism", val); 2264 } 2265 if ((str = nvram_get(strcat_r(prefix, "dfs_postism", tmp)))) { 2266 val = atoi(str); 2267 wl_iovar_setint(name, "dfs_postism", val); 2268 } 2269 val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp))); 2270 WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val)); 2271 2272 } else if (nvram_match(tmp, "d")) { 2273 val = 0; 2274 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val)); 2275 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val)); 2276 val = 1; 2277 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val)); 2278 } 2279 2280 /* set bandwidth capability for nphy and calculate nbw */ 2281 if (WLCONF_PHYTYPE_11N(phytype)) { 2282 struct { 2283 int bandtype; 2284 uint8 bw_cap; 2285 } param; 2286 2287 /* Get the user nmode setting now */ 2288 nmode = AUTO; /* enable by default for NPHY */ 2289 /* Set n mode */ 2290 strcat_r(prefix, "nmode", tmp); 2291 if (nvram_match(tmp, "0")) 2292 nmode = OFF; 2293 2294 WL_IOVAR_SETINT(name, "nmode", (uint32)nmode); 2295 2296 if (nmode == OFF) 2297 val = WLC_BW_CAP_20MHZ; 2298 else 2299 val = wlconf_bw_cap(prefix, bandtype); 2300 2301 /* record the bw here */ 2302 if (val == WLC_BW_CAP_80MHZ) 2303 nbw = WL_CHANSPEC_BW_80; 2304 else if (val == WLC_BW_CAP_40MHZ) 2305 nbw = WL_CHANSPEC_BW_40; 2306 2307 param.bandtype = bandtype; 2308 param.bw_cap = (uint8) val; 2309 2310 WL_IOVAR_SET(name, "bw_cap", ¶m, sizeof(param)); 2311 } else { 2312 /* Save n mode to OFF */ 2313 nvram_set(strcat_r(prefix, "nmode", tmp), "0"); 2314 } 2315 2316 /* Use chanspec to set the channel */ 2317 if ((str = nvram_get(strcat_r(prefix, "chanspec", tmp))) != NULL) { 2318 chanspec = wf_chspec_aton(str); 2319 2320 if (chanspec) { 2321 WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec); 2322 } 2323 } 2324 2325 /* Legacy method of setting channels (for compatibility) */ 2326 /* Set channel before setting gmode or rateset */ 2327 /* Manual Channel Selection - when channel # is not 0 */ 2328 val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))); 2329 if ((chanspec == 0) && val && !WLCONF_PHYTYPE_11N(phytype)) { 2330 WL_SETINT(name, WLC_SET_CHANNEL, val); 2331 if (ret) { 2332 /* Use current channel (card may have changed) */ 2333 WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci)); 2334 snprintf(buf, sizeof(buf), "%d", ci.target_channel); 2335 nvram_set(strcat_r(prefix, "channel", tmp), buf); 2336 } 2337 } else if ((chanspec == 0) && val && WLCONF_PHYTYPE_11N(phytype)) { 2338 uint channel; 2339 uint nctrlsb = 0; 2340 uint cspecbw = (bandtype == WLC_BAND_2G) ? 2341 WL_CHANSPEC_BAND_2G:WL_CHANSPEC_BAND_5G; 2342 2343 channel = val; 2344 2345 if (nbw == WL_CHANSPEC_BW_80) { 2346 /* Get Ctrl SB for 80MHz channel */ 2347 str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp)); 2348 2349 /* Adjust the channel to be center channel */ 2350 channel = channel + CH_40MHZ_APART - CH_10MHZ_APART; 2351 2352 if (!strcmp(str, "ll")) { 2353 nctrlsb = WL_CHANSPEC_CTL_SB_LL; 2354 } else if (!strcmp(str, "lu")) { 2355 nctrlsb = WL_CHANSPEC_CTL_SB_LU; 2356 channel -= CH_20MHZ_APART; 2357 } else if (!strcmp(str, "ul")) { 2358 nctrlsb = WL_CHANSPEC_CTL_SB_UL; 2359 channel -= 2 * CH_20MHZ_APART; 2360 } else if (!strcmp(str, "uu")) { 2361 nctrlsb = WL_CHANSPEC_CTL_SB_UU; 2362 channel -= 3 * CH_20MHZ_APART; 2363 } 2364 2365 } else if (nbw == WL_CHANSPEC_BW_40) { 2366 /* Get Ctrl SB for 40MHz channel */ 2367 str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp)); 2368 2369 /* Adjust the channel to be center channel */ 2370 if (!strcmp(str, "lower")) { 2371 nctrlsb = WL_CHANSPEC_CTL_SB_LOWER; 2372 channel = channel + 2; 2373 } else if (!strcmp(str, "upper")) { 2374 nctrlsb = WL_CHANSPEC_CTL_SB_UPPER; 2375 channel = channel - 2; 2376 } 2377 } 2378 2379 /* band | BW | CTRL SB | Channel */ 2380 chanspec |= (cspecbw | nbw | nctrlsb | channel); 2381 WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec); 2382 } 2383 2384 /* Set up number of Tx and Rx streams */ 2385 if (WLCONF_PHYTYPE_11N(phytype)) { 2386 int count; 2387 int streams; 2388 2389 /* Get the number of tx chains supported by the hardware */ 2390 wl_iovar_getint(name, "hw_txchain", &count); 2391 /* update NVRAM with capabilities */ 2392 snprintf(var, sizeof(var), "%d", count); 2393 nvram_set(strcat_r(prefix, "hw_txchain", tmp), var); 2394 2395 /* Verify that there is an NVRAM param for txstreams, if not create it and 2396 * set it to hw_txchain 2397 */ 2398 streams = atoi(nvram_safe_get(strcat_r(prefix, "txchain", tmp))); 2399 if (streams == 0) { 2400 /* invalid - NVRAM needs to be fixed/initialized */ 2401 nvram_set(strcat_r(prefix, "txchain", tmp), var); 2402 streams = count; 2403 } 2404 /* Apply user configured txstreams, use 1 if user disabled nmode */ 2405 WL_IOVAR_SETINT(name, "txchain", streams); 2406 2407 wl_iovar_getint(name, "hw_rxchain", &count); 2408 /* update NVRAM with capabilities */ 2409 snprintf(var, sizeof(var), "%d", count); 2410 nvram_set(strcat_r(prefix, "hw_rxchain", tmp), var); 2411 2412 /* Verify that there is an NVRAM param for rxstreams, if not create it and 2413 * set it to hw_txchain 2414 */ 2415 streams = atoi(nvram_safe_get(strcat_r(prefix, "rxchain", tmp))); 2416 if (streams == 0) { 2417 /* invalid - NVRAM needs to be fixed/initialized */ 2418 nvram_set(strcat_r(prefix, "rxchain", tmp), var); 2419 streams = count; 2420 } 2421 2422 /* Apply user configured rxstreams, use 1 if user disabled nmode */ 2423 WL_IOVAR_SETINT(name, "rxchain", streams); 2424 } 2425 2426 /* Reset to hardware rateset (band may have changed) */ 2427 WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t)); 2428 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t)); 2429 2430 /* Set gmode */ 2431 if (bandtype == WLC_BAND_2G) { 2432 int override = WLC_PROTECTION_OFF; 2433 int control = WLC_PROTECTION_CTL_OFF; 2434 2435 /* Set gmode */ 2436 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp))); 2437 WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode)); 2438 2439 /* Set gmode protection override and control algorithm */ 2440 strcat_r(prefix, "gmode_protection", tmp); 2441 if (nvram_match(tmp, "auto")) { 2442 override = WLC_PROTECTION_AUTO; 2443 control = WLC_PROTECTION_CTL_OVERLAP; 2444 } 2445 WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override)); 2446 WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control)); 2447 } 2448 2449 /* Set nmode_protection */ 2450 if (WLCONF_PHYTYPE_11N(phytype)) { 2451 int override = WLC_PROTECTION_OFF; 2452 int control = WLC_PROTECTION_CTL_OFF; 2453 2454 /* Set n protection override and control algorithm */ 2455 str = nvram_get(strcat_r(prefix, "nmode_protection", tmp)); 2456 if (!str || !strcmp(str, "auto")) { 2457 override = WLC_PROTECTION_AUTO; 2458 control = WLC_PROTECTION_CTL_OVERLAP; 2459 } 2460 2461 WL_IOVAR_SETINT(name, "nmode_protection_override", 2462 (uint32)override); 2463 WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control)); 2464 } 2465 2466 /* Set vlan_prio_mode */ 2467 { 2468 uint32 mode = OFF; /* default */ 2469 2470 strcat_r(prefix, "vlan_prio_mode", tmp); 2471 2472 if (nvram_match(tmp, "on")) 2473 mode = ON; 2474 2475 WL_IOVAR_SETINT(name, "vlan_mode", mode); 2476 } 2477 2478 /* Get bluetooth coexistance(BTC) mode */ 2479 btc_mode = atoi(nvram_safe_get(strcat_r(prefix, "btc_mode", tmp))); 2480 2481 /* Set the AMPDU and AMSDU options based on the N-mode */ 2482 wme_global = wlconf_ampdu_amsdu_set(name, prefix, nmode, btc_mode, ap); 2483 2484 /* Now that wme_global is known, check per-BSS disable settings */ 2485 for (i = 0; i < bclist->count; i++) { 2486 char *subprefix; 2487 bsscfg = &bclist->bsscfgs[i]; 2488 2489 subprefix = apsta ? prefix : bsscfg->prefix; 2490 2491 /* For each BSS, check WME; make sure wme is set properly for this interface */ 2492 strcat_r(subprefix, "wme", tmp); 2493 nvram_set(tmp, wme_global ? "on" : "off"); 2494 2495 str = nvram_safe_get(strcat_r(bsscfg->prefix, "wme_bss_disable", tmp)); 2496 val = (str[0] == '1') ? 1 : 0; 2497 WL_BSSIOVAR_SETINT(name, "wme_bss_disable", bsscfg->idx, val); 2498 } 2499 2500 /* 2501 * Set operational capabilities required for stations 2502 * to associate to the BSS. Per-BSS setting. 2503 */ 2504 for (i = 0; i < bclist->count; i++) { 2505 bsscfg = &bclist->bsscfgs[i]; 2506 str = nvram_safe_get(strcat_r(bsscfg->prefix, "bss_opmode_cap_reqd", tmp)); 2507 val = atoi(str); 2508 WL_BSSIOVAR_SETINT(name, "mode_reqd", bsscfg->idx, val); 2509 } 2510 2511 2512 /* Get current rateset (gmode may have changed) */ 2513 WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof(wl_rateset_t)); 2514 2515 strcat_r(prefix, "rateset", tmp); 2516 if (nvram_match(tmp, "all")) { 2517 /* Make all rates basic */ 2518 for (i = 0; i < rs.count; i++) 2519 rs.rates[i] |= 0x80; 2520 } else if (nvram_match(tmp, "12")) { 2521 /* Make 1 and 2 basic */ 2522 for (i = 0; i < rs.count; i++) { 2523 if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4) 2524 rs.rates[i] |= 0x80; 2525 else 2526 rs.rates[i] &= ~0x80; 2527 } 2528 } 2529 2530 if (phytype != PHY_TYPE_SSN && phytype != PHY_TYPE_LCN) { 2531 /* Set BTC mode */ 2532 if (!wl_iovar_setint(name, "btc_mode", btc_mode)) { 2533 if (btc_mode == WL_BTC_PREMPT) { 2534 wl_rateset_t rs_tmp = rs; 2535 /* remove 1Mbps and 2 Mbps from rateset */ 2536 for (i = 0, rs.count = 0; i < rs_tmp.count; i++) { 2537 if ((rs_tmp.rates[i] & 0x7f) == 2 || 2538 (rs_tmp.rates[i] & 0x7f) == 4) 2539 continue; 2540 rs.rates[rs.count++] = rs_tmp.rates[i]; 2541 } 2542 } 2543 } 2544 } 2545 2546 /* Set rateset */ 2547 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t)); 2548 2549 /* Allow short preamble settings for the following: 2550 * 11b - short/long 2551 * 11g - short /long in GMODE_LEGACY_B and GMODE_AUTO gmodes 2552 * GMODE_PERFORMANCE and GMODE_LRS will use short and long 2553 * preambles respectively, by default 2554 * 11n - short/long applicable in 2.4G band only 2555 */ 2556 if (phytype == PHY_TYPE_B || 2557 (WLCONF_PHYTYPE_11N(phytype) && (bandtype == WLC_BAND_2G)) || 2558 ((phytype == PHY_TYPE_G || phytype == PHY_TYPE_LP) && 2559 (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) { 2560 strcat_r(prefix, "plcphdr", tmp); 2561 if (nvram_match(tmp, "long")) 2562 val = WLC_PLCP_AUTO; 2563 else 2564 val = WLC_PLCP_SHORT; 2565 WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val)); 2566 } 2567 2568 /* Set rate in 500 Kbps units */ 2569 val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000; 2570 2571 /* Convert Auto mcsidx to Auto rate */ 2572 if (WLCONF_PHYTYPE_11N(phytype)) { 2573 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp))); 2574 2575 /* -1 mcsidx used to designate AUTO rate */ 2576 if (mcsidx == -1) 2577 val = 0; 2578 } 2579 2580 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */ 2581 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4)) 2582 /* Must b/g band. Set to 5.5Mbps */ 2583 val = 11; 2584 2585 /* it is band-blind. try both band */ 2586 error_bg = wl_iovar_setint(name, "bg_rate", val); 2587 error_a = wl_iovar_setint(name, "a_rate", val); 2588 2589 if (error_bg && error_a) { 2590 /* both failed. Try default rate (card may have changed) */ 2591 val = 0; 2592 2593 error_bg = wl_iovar_setint(name, "bg_rate", val); 2594 error_a = wl_iovar_setint(name, "a_rate", val); 2595 2596 snprintf(buf, sizeof(buf), "%d", val); 2597 nvram_set(strcat_r(prefix, "rate", tmp), buf); 2598 } 2599 2600 /* check if nrate needs to be applied */ 2601 if (nmode != OFF) { 2602 uint32 nrate = 0; 2603 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp))); 2604 bool ismcs = (mcsidx >= 0); 2605 2606 /* mcsidx of 32 is valid only for 40 Mhz */ 2607 if (mcsidx == 32 && nbw == WL_CHANSPEC_BW_20) { 2608 mcsidx = -1; 2609 ismcs = FALSE; 2610 nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1"); 2611 } 2612 2613 /* Use nrate iovar only for MCS rate. */ 2614 if (ismcs) { 2615 nrate |= WL_RSPEC_ENCODE_HT; 2616 nrate |= mcsidx & WL_RSPEC_RATE_MASK; 2617 2618 WL_IOVAR_SETINT(name, "nrate", nrate); 2619 } 2620 } 2621 2622 /* Set multicast rate in 500 Kbps units */ 2623 val = atoi(nvram_safe_get(strcat_r(prefix, "mrate", tmp))) / 500000; 2624 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */ 2625 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4)) 2626 /* Must b/g band. Set to 5.5Mbps */ 2627 val = 11; 2628 2629 /* it is band-blind. try both band */ 2630 error_bg = wl_iovar_setint(name, "bg_mrate", val); 2631 error_a = wl_iovar_setint(name, "a_mrate", val); 2632 2633 if (error_bg && error_a) { 2634 /* Try default rate (card may have changed) */ 2635 val = 0; 2636 2637 wl_iovar_setint(name, "bg_mrate", val); 2638 wl_iovar_setint(name, "a_mrate", val); 2639 2640 snprintf(buf, sizeof(buf), "%d", val); 2641 nvram_set(strcat_r(prefix, "mrate", tmp), buf); 2642 } 2643 2644 /* Set fragmentation threshold */ 2645 val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp))); 2646 wl_iovar_setint(name, "fragthresh", val); 2647 2648 /* Set RTS threshold */ 2649 val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp))); 2650 wl_iovar_setint(name, "rtsthresh", val); 2651 2652 /* Set DTIM period */ 2653 val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp))); 2654 WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val)); 2655 2656 /* Set beacon period */ 2657 val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp))); 2658 WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val)); 2659 2660 /* Set beacon rotation */ 2661 str = nvram_get(strcat_r(prefix, "bcn_rotate", tmp)); 2662 if (!str) { 2663 /* No nvram variable found, use the default */ 2664 str = nvram_default_get(strcat_r(prefix, "bcn_rotate", tmp)); 2665 } 2666 val = atoi(str); 2667 wl_iovar_setint(name, "bcn_rotate", val); 2668 2669 /* Set framebursting mode */ 2670 if (btc_mode == WL_BTC_PREMPT) 2671 val = FALSE; 2672 else 2673 val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on"); 2674 WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val)); 2675 2676 /* Set dynamic frameburst max station limit */ 2677 str = nvram_get(strcat_r(prefix, "frameburst_dyn_max_stations", tmp)); 2678 if (!str) { /* Fall back to previous name, frameburst_dyn */ 2679 str = nvram_safe_get("frameburst_dyn"); 2680 } 2681 wl_iovar_setint(name, "frameburst_dyn_max_stations", atoi(str)); 2682 2683 /* Set STBC tx and rx mode */ 2684 if (phytype == PHY_TYPE_N || 2685 phytype == PHY_TYPE_HT || 2686 phytype == PHY_TYPE_AC) { 2687 char *nvram_str = nvram_safe_get(strcat_r(prefix, "stbc_tx", tmp)); 2688 2689 if (!strcmp(nvram_str, "auto")) { 2690 WL_IOVAR_SETINT(name, "stbc_tx", AUTO); 2691 } else if (!strcmp(nvram_str, "on")) { 2692 WL_IOVAR_SETINT(name, "stbc_tx", ON); 2693 } else if (!strcmp(nvram_str, "off")) { 2694 WL_IOVAR_SETINT(name, "stbc_tx", OFF); 2695 } 2696 val = atoi(nvram_safe_get(strcat_r(prefix, "stbc_rx", tmp))); 2697 WL_IOVAR_SETINT(name, "stbc_rx", val); 2698 } 2699 2700 /* Set RIFS mode based on framebursting */ 2701 if (WLCONF_PHYTYPE_11N(phytype)) { 2702 char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp)); 2703 if (!strcmp(nvram_str, "on")) 2704 wl_iovar_setint(name, "rifs", ON); 2705 else if (!strcmp(nvram_str, "off")) 2706 wl_iovar_setint(name, "rifs", OFF); 2707 2708 /* RIFS mode advertisement */ 2709 nvram_str = nvram_safe_get(strcat_r(prefix, "rifs_advert", tmp)); 2710 if (!strcmp(nvram_str, "auto")) 2711 wl_iovar_setint(name, "rifs_advert", AUTO); 2712 else if (!strcmp(nvram_str, "off")) 2713 wl_iovar_setint(name, "rifs_advert", OFF); 2714 } 2715 2716 /* Override BA mode only if set to on/off */ 2717 ba = nvram_safe_get(strcat_r(prefix, "ba", tmp)); 2718 if (!strcmp(ba, "on")) 2719 wl_iovar_setint(name, "ba", ON); 2720 else if (!strcmp(ba, "off")) 2721 wl_iovar_setint(name, "ba", OFF); 2722 2723 if (WLCONF_PHYTYPE_11N(phytype)) { 2724 val = AVG_DMA_XFER_RATE; 2725 wl_iovar_set(name, "avg_dma_xfer_rate", &val, sizeof(val)); 2726 } 2727 2728 /* 2729 * If no nvram variable exists to force non-aggregated mpdu regulation on/off, 2730 * limit to 2G interfaces. 2731 */ 2732 str = nvram_get(strcat_r(prefix, "nar", tmp)); 2733 if (str) { 2734 val = atoi(str); 2735 } else { 2736 val = (bandtype == WLC_BAND_2G) ? 1 : 0; 2737 } 2738 WLCONF_DBG("%sabling non-aggregated regulation on band %d\n", (val) ? "En":"Dis", bandtype); 2739 WL_IOVAR_SETINT(name, "nar", val); 2740 if (val) { 2741 /* nar is enabled on this interface, add tuneable parameters */ 2742 str = nvram_get(strcat_r(prefix, "nar_handle_ampdu", tmp)); 2743 if (str) { 2744 WL_IOVAR_SETINT(name, "nar_handle_ampdu", atoi(str)); 2745 } 2746 str = nvram_get(strcat_r(prefix, "nar_transit_limit", tmp)); 2747 if (str) { 2748 WL_IOVAR_SETINT(name, "nar_transit_limit", atoi(str)); 2749 } 2750 } 2751 2752 /* Set up TxBF */ 2753 wlconf_set_txbf(name, prefix); 2754 2755 /* set airtime fairness */ 2756 val = 0; 2757 str = nvram_get(strcat_r(prefix, "atf", tmp)); 2758 if (str) { 2759 val = atoi(str); 2760 } 2761 WL_IOVAR_SETINT(name, "atf", val); 2762 2763 str = nvram_get(strcat_r(prefix, "ampdu_atf_us", tmp)); 2764 if (str) { 2765 val = atoi(str); 2766 if (val) { 2767 WL_IOVAR_SETINT(name, "ampdu_atf_us", val); 2768 WL_IOVAR_SETINT(name, "nar_atf_us", val); 2769 } 2770 } 2771 2772 /* set TAF */ 2773 val = 0; 2774 str = nvram_get(strcat_r(prefix, "taf_enable", tmp)); 2775 if (str && (bandtype == WLC_BAND_5G)) { 2776 val = atoi(str); 2777 } 2778 WL_IOVAR_SETINT(name, "taf", val); 2779 2780 val = 0; 2781 str = nvram_get(strcat_r(prefix, "taf_rule", tmp)); 2782 if (str) { 2783 val = strtoul(str, NULL, 0); 2784 WL_IOVAR_SETINT(name, "taf_rule", val); 2785 } 2786 2787 /* Bring the interface back up */ 2788 WL_IOCTL(name, WLC_UP, NULL, 0); 2789 2790 /* set ebos, interface must be up */ 2791 val = 0; 2792 str = nvram_get(strcat_r(prefix, "ebos_enable", tmp)); 2793 if (str) { 2794 val = atoi(str); 2795 } 2796 WL_IOVAR_SETINT(name, "ebos_enable", val); 2797 2798 val = 0; 2799 str = nvram_get(strcat_r(prefix, "ebos_flags", tmp)); 2800 if (str) { 2801 val = strtoul(str, NULL, 0); 2802 WL_IOVAR_SETINT(name, "ebos_flags", val); 2803 } 2804 2805 val = 0; 2806 str = nvram_get(strcat_r(prefix, "ebos_prr_threshold", tmp)); 2807 if (str) { 2808 val = strtoul(str, NULL, 0); 2809 WL_IOVAR_SETINT(name, "ebos_prr_threshold", val); 2810 } 2811 2812 val = 0; 2813 str = nvram_get(strcat_r(prefix, "ebos_prr_flags", tmp)); 2814 if (str) { 2815 val = strtoul(str, NULL, 0); 2816 WL_IOVAR_SETINT(name, "ebos_prr_flags", val); 2817 } 2818 2819 val = 0; 2820 str = nvram_get(strcat_r(prefix, "ebos_prr_transit", tmp)); 2821 if (str) { 2822 val = strtol(str, NULL, 0); 2823 WL_IOVAR_SETINT(name, "ebos_prr_transit", val); 2824 } 2825 val = 0; 2826 2827 str = nvram_get(strcat_r(prefix, "ebos_transit", tmp)); 2828 if (str) { 2829 val = strtol(str, NULL, 0); 2830 WL_IOVAR_SETINT(name, "ebos_transit", val); 2831 } 2832 2833 /* set phy_percal_delay */ 2834 val = atoi(nvram_safe_get(strcat_r(prefix, "percal_delay", tmp))); 2835 if (val) { 2836 wl_iovar_set(name, "phy_percal_delay", &val, sizeof(val)); 2837 } 2838 2839 /* Set phy periodic cal if nvram present. Otherwise, use driver defaults. */ 2840 str = nvram_get(strcat_r(prefix, "cal_period", tmp)); 2841 if (str) { 2842 /* user specified phy cal period. */ 2843 val = atoi(str); 2844 WL_IOVAR_SET(name, "cal_period", &val, sizeof(val)); 2845 } 2846 2847 /* Set antenna */ 2848 val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp))); 2849 WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val)); 2850 2851 /* Set antenna selection */ 2852 wlconf_set_antsel(name, prefix); 2853 2854 /* Set radar parameters if it is enabled */ 2855 if (radar_enab) { 2856 wlconf_set_radarthrs(name, prefix); 2857 } 2858 2859 /* set pspretend */ 2860 val = 0; 2861 if (ap) { 2862 /* Set pspretend for multi-ssid bss */ 2863 for (i = 0; i < bclist->count; i++) { 2864 bsscfg = &bclist->bsscfgs[i]; 2865 str = nvram_safe_get(strcat_r(bsscfg->prefix, 2866 "pspretend_retry_limit", tmp)); 2867 if (str) { 2868 val = atoi(str); 2869 WL_BSSIOVAR_SETINT(name, "pspretend_retry_limit", bsscfg->idx, val); 2870 } 2871 } 2872 2873 /* now set it for primary bss */ 2874 val = 0; 2875 str = nvram_get(strcat_r(prefix, "pspretend_retry_limit", tmp)); 2876 if (str) { 2877 val = atoi(str); 2878 } 2879 } 2880 WL_IOVAR_SETINT(name, "pspretend_retry_limit", val); 2881 2882 val = 0; 2883 if (ap) { 2884 str = nvram_get(strcat_r(prefix, "pspretend_threshold", tmp)); 2885 if (str) { 2886 val = atoi(str); 2887 } 2888 } 2889 WL_IOVAR_SETINT(name, "pspretend_threshold", val); 2890 2891 /* Set channel interference threshold value if it is enabled */ 2892 2893 str = nvram_get(strcat_r(prefix, "glitchthres", tmp)); 2894 2895 if (str) { 2896 int glitch_thres = atoi(str); 2897 if (glitch_thres > 0) 2898 WL_IOVAR_SETINT(name, "chanim_glitchthres", glitch_thres); 2899 } 2900 2901 str = nvram_get(strcat_r(prefix, "ccathres", tmp)); 2902 2903 if (str) { 2904 int cca_thres = atoi(str); 2905 if (cca_thres > 0) 2906 WL_IOVAR_SETINT(name, "chanim_ccathres", cca_thres); 2907 } 2908 2909 str = nvram_get(strcat_r(prefix, "chanimmode", tmp)); 2910 2911 if (str) { 2912 int chanim_mode = atoi(str); 2913 if (chanim_mode >= 0) 2914 WL_IOVAR_SETINT(name, "chanim_mode", chanim_mode); 2915 } 2916 2917 /* bcm_dcs (dynamic channel selection) settings */ 2918 str = nvram_safe_get(strcat_r(prefix, "bcmdcs", tmp)); 2919 if (!strcmp(str, "on")) 2920 wl_iovar_setint(name, "bcm_dcs", ON); 2921 else if (!strcmp(str, "off")) 2922 wl_iovar_setint(name, "bcm_dcs", OFF); 2923 2924 /* Overlapping BSS Coexistence aka 20/40 Coex. aka OBSS Coex. 2925 * For an AP - Only use if 2G band AND user wants a 40Mhz chanspec. 2926 * For a STA - Always 2927 */ 2928 if (WLCONF_PHYTYPE_11N(phytype)) { 2929 if (sta || 2930 ((ap || apsta) && (nbw == WL_CHANSPEC_BW_40) && (bandtype == WLC_BAND_2G))) { 2931 str = nvram_safe_get(strcat_r(prefix, "obss_coex", tmp)); 2932 if (!str) { 2933 /* No nvram variable found, use the default */ 2934 str = nvram_default_get(strcat_r(prefix, "obss_coex", tmp)); 2935 } 2936 obss_coex = atoi(str); 2937 } else { 2938 /* Need to disable obss coex in case of 20MHz and/or 2939 * in case of 5G. 2940 */ 2941 obss_coex = 0; 2942 } 2943#ifdef WLTEST 2944 /* force coex off for msgtest build */ 2945 obss_coex = 0; 2946#endif 2947 WL_IOVAR_SETINT(name, "obss_coex", obss_coex); 2948 } 2949 2950 /* Set up TxBF timer */ 2951 wlconf_set_txbf_timer(name, prefix); 2952 2953 /* Auto Channel Selection: 2954 * 1. When channel # is 0 in AP mode, this determines our channel and 20Mhz vs. 40Mhz 2955 * 2. If we're running OBSS Coex and the user specified a channel, Autochannel runs to 2956 * do an initial scan to help us make decisions about whether we can create a 40Mhz AP 2957 */ 2958 /* The following condition(s) must be met in order for Auto Channel Selection to work. 2959 * - the I/F must be up for the channel scan 2960 * - the AP must not be supporting a BSS (all BSS Configs must be disabled) 2961 */ 2962 if (ap || apsta) { 2963 int channel = chanspec ? wf_chspec_ctlchan(chanspec) : 0; 2964#ifdef EXT_ACS 2965 char tmp[100]; 2966 char *ptr; 2967 char * str_val; 2968 2969 str_val = nvram_safe_get("acs_mode"); 2970 if (!strcmp(str_val, "legacy")) 2971 goto legacy_mode; 2972 2973 snprintf(tmp, sizeof(tmp), "acs_ifnames"); 2974 ptr = nvram_get(tmp); 2975 if (ptr) 2976 snprintf(buf, sizeof(buf), "%s %s", ptr, name); 2977 else 2978 strncpy(buf, name, sizeof(buf)); 2979 nvram_set(tmp, buf); 2980 WL_IOVAR_SETINT(name, "chanim_mode", CHANIM_EXT); 2981 goto legacy_end; 2982 2983legacy_mode: 2984#endif /* EXT_ACS */ 2985 if (obss_coex || channel == 0) { 2986 if (WLCONF_PHYTYPE_11N(phytype)) { 2987 chanspec_t chanspec; 2988 int pref_chspec; 2989 2990 if (channel != 0) { 2991 /* assumes that initial chanspec has been set earlier */ 2992 /* Maybe we expand scope of chanspec from above so 2993 * that we don't have to do the iovar_get here? 2994 */ 2995 2996 /* We're not doing auto-channel, give the driver 2997 * the preferred chanspec. 2998 */ 2999 WL_IOVAR_GETINT(name, "chanspec", &pref_chspec); 3000 WL_IOVAR_SETINT(name, "pref_chanspec", pref_chspec); 3001 } else { 3002 WL_IOVAR_SETINT(name, "pref_chanspec", 0); 3003 } 3004 3005 chanspec = wlconf_auto_chanspec(name); 3006 if (chanspec != 0) 3007 WL_IOVAR_SETINT(name, "chanspec", chanspec); 3008 } else { 3009 /* select a channel */ 3010 val = wlconf_auto_channel(name); 3011 /* switch to the selected channel */ 3012 if (val != 0) 3013 WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val)); 3014 } 3015 /* set the auto channel scan timer in the driver when in auto mode */ 3016 if (channel == 0) { 3017 val = 15; /* 15 minutes for now */ 3018 } else { 3019 val = 0; 3020 } 3021 } else { 3022 /* reset the channel scan timer in the driver when not in auto mode */ 3023 val = 0; 3024 } 3025 3026 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val)); 3027 WL_IOVAR_SETINT(name, "chanim_mode", CHANIM_ACT); 3028#ifdef EXT_ACS 3029legacy_end: 3030 ; 3031#endif /* EXT_ACS */ 3032 /* Apply sta_config configuration settings for this interface */ 3033 foreach(var, nvram_safe_get("sta_config"), next) { 3034 wlconf_process_sta_config_entry(name, var); 3035 } 3036 3037 } /* AP or APSTA */ 3038 3039 /* Security settings for each BSS Configuration */ 3040 for (i = 0; i < bclist->count; i++) { 3041 bsscfg = &bclist->bsscfgs[i]; 3042 wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, 3043 mac_spoof, wet || sta || apsta || psta || psr); 3044 } 3045 3046 /* 3047 * Finally enable BSS Configs or Join BSS 3048 * 3049 * AP: Enable BSS Config to bring AP up only when nas will not run 3050 * STA: Join the BSS regardless. 3051 */ 3052 for (i = 0; i < bclist->count; i++) { 3053 struct {int bsscfg_idx; int enable;} setbuf; 3054 char vifname[VIFNAME_LEN]; 3055 char *name_ptr = name; 3056 3057 setbuf.bsscfg_idx = bclist->bsscfgs[i].idx; 3058 setbuf.enable = 0; 3059 3060 bsscfg = &bclist->bsscfgs[i]; 3061 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) { 3062 setbuf.enable = 1; 3063 } 3064 3065 /* Set the MAC list */ 3066 maclist = (struct maclist *)buf; 3067 maclist->count = 0; 3068 if (!nvram_match(strcat_r(bsscfg->prefix, "macmode", tmp), "disabled")) { 3069 ea = maclist->ea; 3070 foreach(var, nvram_safe_get(strcat_r(bsscfg->prefix, "maclist", tmp)), 3071 next) { 3072 if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)]))) 3073 break; 3074 if (ether_atoe(var, ea->octet)) { 3075 maclist->count++; 3076 ea++; 3077 } 3078 } 3079 } 3080 3081 if (setbuf.bsscfg_idx == 0) { 3082 name_ptr = name; 3083 } else { /* Non-primary BSS; changes name syntax */ 3084 char tmp[VIFNAME_LEN]; 3085 int len; 3086 3087 /* Remove trailing _ if present */ 3088 memset(tmp, 0, sizeof(tmp)); 3089 strncpy(tmp, bsscfg->prefix, VIFNAME_LEN - 1); 3090 if (((len = strlen(tmp)) > 0) && (tmp[len - 1] == '_')) { 3091 tmp[len - 1] = 0; 3092 } 3093 nvifname_to_osifname(tmp, vifname, VIFNAME_LEN); 3094 name_ptr = vifname; 3095 } 3096 3097 WL_IOCTL(name_ptr, WLC_SET_MACLIST, buf, sizeof(buf)); 3098 3099 /* Set macmode for each VIF */ 3100 (void) strcat_r(bsscfg->prefix, "macmode", tmp); 3101 3102 if (nvram_match(tmp, "deny")) 3103 val = WLC_MACMODE_DENY; 3104 else if (nvram_match(tmp, "allow")) 3105 val = WLC_MACMODE_ALLOW; 3106 else 3107 val = WLC_MACMODE_DISABLED; 3108 3109 WL_IOCTL(name_ptr, WLC_SET_MACMODE, &val, sizeof(val)); 3110 } 3111 3112 ret = 0; 3113exit: 3114 if (bclist != NULL) 3115 free(bclist); 3116 3117 return ret; 3118} 3119 3120int 3121wlconf_down(char *name) 3122{ 3123 int val, ret = 0; 3124 int i; 3125 int wlsubunit; 3126 int bcmerr; 3127 struct {int bsscfg_idx; int enable;} setbuf; 3128 int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */ 3129 char cap[WLC_IOCTL_SMLEN]; 3130 char caps[WLC_IOCTL_MEDLEN]; 3131 char *next; 3132 wlc_ssid_t ssid; 3133 3134 /* wlconf doesn't work for virtual i/f */ 3135 if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) { 3136 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name); 3137 return 0; 3138 } 3139 3140 /* Check interface (fail silently for non-wl interfaces) */ 3141 if ((ret = wl_probe(name))) 3142 return ret; 3143 3144 /* because of ifdefs in wl driver, when we don't have AP capabilities we 3145 * can't use the same iovars to configure the wl. 3146 * so we use "wl_ap_build" to help us know how to configure the driver 3147 */ 3148 if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps))) 3149 return -1; 3150 3151 foreach(cap, caps, next) { 3152 if (!strcmp(cap, "ap")) { 3153 wl_ap_build = 1; 3154 } 3155 } 3156 3157 if (wl_ap_build) { 3158 /* Bring down the interface */ 3159 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); 3160 3161 /* Disable all BSS Configs */ 3162 for (i = 0; i < WL_MAXBSSCFG; i++) { 3163 setbuf.bsscfg_idx = i; 3164 setbuf.enable = 0; 3165 3166 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf)); 3167 if (ret) { 3168 wl_iovar_getint(name, "bcmerror", &bcmerr); 3169 /* fail quietly on a range error since the driver may 3170 * support fewer bsscfgs than we are prepared to configure 3171 */ 3172 if (bcmerr == BCME_RANGE) 3173 break; 3174 } 3175 } 3176 } else { 3177 WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val)); 3178 if (val) { 3179 /* Nuke SSID */ 3180 ssid.SSID_len = 0; 3181 ssid.SSID[0] = '\0'; 3182 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); 3183 3184 /* Bring down the interface */ 3185 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val)); 3186 } 3187 } 3188 3189 /* Nuke the WDS list */ 3190 wlconf_wds_clear(name); 3191 3192 return 0; 3193} 3194 3195int 3196wlconf_start(char *name) 3197{ 3198 int i, ii, unit, val, ret = 0; 3199 int wlunit = -1; 3200 int wlsubunit = -1; 3201 int ap, apsta, wds, sta = 0, wet = 0; 3202 int wl_ap_build = 0; /* wl compiled with AP capabilities */ 3203 char buf[WLC_IOCTL_SMLEN]; 3204 struct maclist *maclist; 3205 struct ether_addr *ea; 3206 struct bsscfg_list *bclist = NULL; 3207 struct bsscfg_info *bsscfg = NULL; 3208 wlc_ssid_t ssid; 3209 char cap[WLC_IOCTL_SMLEN], caps[WLC_IOCTL_MEDLEN]; 3210 char var[80], tmp[100], prefix[PREFIX_LEN], *str, *next; 3211 int trf_mgmt_cap = 0, trf_mgmt_dwm_cap = 0; 3212 bool dwm_supported = FALSE; 3213 3214 /* Check interface (fail silently for non-wl interfaces) */ 3215 if ((ret = wl_probe(name))) 3216 return ret; 3217 3218 /* wlconf doesn't work for virtual i/f, so if we are given a 3219 * virtual i/f return 0 if that interface is in it's parent's "vifs" 3220 * list otherwise return -1 3221 */ 3222 memset(tmp, 0, sizeof(tmp)); 3223 if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0) { 3224 if (wlsubunit >= 0) { 3225 /* we have been given a virtual i/f, 3226 * is it in it's parent i/f's virtual i/f list? 3227 */ 3228 sprintf(tmp, "wl%d_vifs", wlunit); 3229 3230 if (strstr(nvram_safe_get(tmp), name) == NULL) 3231 return -1; /* config error */ 3232 else 3233 return 0; /* okay */ 3234 } 3235 } 3236 else { 3237 return -1; 3238 } 3239 3240 /* because of ifdefs in wl driver, when we don't have AP capabilities we 3241 * can't use the same iovars to configure the wl. 3242 * so we use "wl_ap_build" to help us know how to configure the driver 3243 */ 3244 if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps))) 3245 return -1; 3246 3247 foreach(cap, caps, next) { 3248 if (!strcmp(cap, "ap")) 3249 wl_ap_build = 1; 3250 3251 if (!strcmp(cap, "traffic-mgmt")) 3252 trf_mgmt_cap = 1; 3253 3254 if (!strcmp(cap, "traffic-mgmt-dwm")) 3255 trf_mgmt_dwm_cap = 1; 3256 } 3257 3258 /* Get instance */ 3259 WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit)); 3260 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 3261 3262 3263 /* Get the list of BSS Configs */ 3264 if (!(bclist = wlconf_get_bsscfgs(name, prefix))) 3265 return -1; 3266 3267 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */ 3268 str = nvram_safe_get(strcat_r(prefix, "mode", tmp)); 3269 ap = (!strcmp(str, "") || !strcmp(str, "ap")); 3270 apsta = (!strcmp(str, "apsta") || 3271 ((!strcmp(str, "sta") || !strcmp(str, "psr") || !strcmp(str, "wet")) && 3272 bclist->count > 1)); 3273 sta = (!strcmp(str, "sta") && bclist->count == 1); 3274 wds = !strcmp(str, "wds"); 3275 wet = !strcmp(str, "wet"); 3276 if (!strcmp(str, "mac_spoof") || !strcmp(str, "psta") || !strcmp(str, "psr")) 3277 sta = 1; 3278 3279 /* Retain remaining WET effects only if not APSTA */ 3280 wet &= !apsta; 3281 3282 /* AP only config, code copied as-is from wlconf function */ 3283 if (ap || apsta || wds) { 3284 /* Set lazy WDS mode */ 3285 val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp))); 3286 WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val)); 3287 3288 /* Set the WDS list */ 3289 maclist = (struct maclist *) buf; 3290 maclist->count = 0; 3291 ea = maclist->ea; 3292 foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) { 3293 if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)]))) 3294 break; 3295 ether_atoe(var, ea->octet); 3296 maclist->count++; 3297 ea++; 3298 } 3299 WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf)); 3300 3301 /* Set WDS link detection timeout */ 3302 val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp))); 3303 wl_iovar_setint(name, "wdstimeout", val); 3304 } 3305 3306 /* 3307 * Finally enable BSS Configs or Join BSS 3308 * code copied as-is from wlconf function 3309 */ 3310 for (i = 0; i < bclist->count; i++) { 3311 struct {int bsscfg_idx; int enable;} setbuf; 3312 3313 setbuf.bsscfg_idx = bclist->bsscfgs[i].idx; 3314 setbuf.enable = 0; 3315 3316 bsscfg = &bclist->bsscfgs[i]; 3317 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) { 3318 setbuf.enable = 1; 3319 } 3320 3321 /* bring up BSS */ 3322 if (ap || apsta || sta || wet) { 3323 for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) { 3324 if (wl_ap_build) { 3325 WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf)); 3326 } 3327 else { 3328 strcat_r(prefix, "ssid", tmp); 3329 ssid.SSID_len = strlen(nvram_safe_get(tmp)); 3330 if (ssid.SSID_len > sizeof(ssid.SSID)) 3331 ssid.SSID_len = sizeof(ssid.SSID); 3332 strncpy((char *)ssid.SSID, nvram_safe_get(tmp), 3333 ssid.SSID_len); 3334 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid)); 3335 } 3336 if (apsta && (ret != 0)) 3337 sleep_ms(1000); 3338 else 3339 break; 3340 } 3341 } 3342 3343 } 3344 if ((ap || apsta || sta) && (trf_mgmt_cap)) { 3345 if (trf_mgmt_dwm_cap && ap) 3346 dwm_supported = TRUE; 3347 trf_mgmt_settings(prefix, dwm_supported); 3348 } 3349 3350#ifdef TRAFFIC_MGMT_RSSI_POLICY 3351 if ((ap || apsta) && (trf_mgmt_cap)) { 3352 trf_mgmt_rssi_policy(prefix); 3353 } 3354#endif /* TRAFFIC_MGMT_RSSI_POLICY */ 3355 3356#ifdef __CONFIG_EMF__ 3357 if (nvram_match(strcat_r(bsscfg->prefix, "wmf_bss_enable", tmp), "1")) { 3358 val = atoi(nvram_safe_get(strcat_r(prefix, "wmf_ucigmp_query", tmp))); 3359 wl_iovar_setint(name, "wmf_ucast_igmp_query", val); 3360 val = atoi(nvram_safe_get(strcat_r(prefix, "wmf_mdata_sendup", tmp))); 3361 wl_iovar_setint(name, "wmf_mcast_data_sendup", val); 3362 val = atoi(nvram_safe_get(strcat_r(prefix, "wmf_ucast_upnp", tmp))); 3363 wl_iovar_setint(name, "wmf_ucast_upnp", val); 3364 val = atoi(nvram_safe_get(strcat_r(prefix, "wmf_igmpq_filter", tmp))); 3365 wl_iovar_setint(name, "wmf_igmpq_filter", val); 3366 } 3367#endif /* __CONFIG_EMF__ */ 3368 3369 if (bclist != NULL) 3370 free(bclist); 3371 3372 return ret; 3373} 3374 3375#if defined(linux) 3376static int 3377wlconf_security(char *name) 3378{ 3379 int unit, bsscfg_idx; 3380 char prefix[PREFIX_LEN]; 3381 char tmp[100], *str; 3382 3383 /* Get the interface subunit */ 3384 if (get_ifname_unit(name, &unit, &bsscfg_idx) != 0) { 3385 WLCONF_DBG("wlconfig(%s): unable to parse unit.subunit in interface " 3386 "name \"%s\"\n", name, name); 3387 return -1; 3388 } 3389 3390 /* Configure security parameters for the newly created interface */ 3391 snprintf(prefix, sizeof(prefix), "wl%d_", unit); 3392 str = nvram_safe_get(strcat_r(prefix, "mode", tmp)); 3393 wlconf_security_options(name, prefix, bsscfg_idx, FALSE, 3394 !strcmp(str, "psta") || !strcmp(str, "psr")); 3395 3396 return 0; 3397} 3398 3399int 3400main(int argc, char *argv[]) 3401{ 3402 /* Check parameters and branch based on action */ 3403 if (argc == 3 && !strcmp(argv[2], "up")) 3404 return wlconf(argv[1]); 3405 else if (argc == 3 && !strcmp(argv[2], "down")) 3406 return wlconf_down(argv[1]); 3407 else if (argc == 3 && !strcmp(argv[2], "start")) 3408 return wlconf_start(argv[1]); 3409 else if (argc == 3 && !strcmp(argv[2], "security")) 3410 return wlconf_security(argv[1]); 3411 else { 3412 fprintf(stderr, "Usage: wlconf <ifname> up|down\n"); 3413 return -1; 3414 } 3415} 3416#endif /* defined(linux) */ 3417