2 * Wireless Network Adapter Configuration Utility
4 * Copyright 2008, Broadcom Corporation
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.
22 #include <bcmparams.h>
32 #define PHY_TYPE_NULL 0xf
34 /* how many times to attempt to bring up a virtual i/f when
35 * we are in APSTA mode and IOVAR set of "bss" "up" returns busy
37 #define MAX_BSS_UP_RETRIES 5
39 /* notify the average dma xfer rate (in kbps) to the driver */
40 #define AVG_DMA_XFER_RATE 120000
42 /* parts of an idcode: */
43 #define IDCODE_MFG_MASK 0x00000fff
44 #define IDCODE_MFG_SHIFT 0
45 #define IDCODE_ID_MASK 0x0ffff000
46 #define IDCODE_ID_SHIFT 12
47 #define IDCODE_REV_MASK 0xf0000000
48 #define IDCODE_REV_SHIFT 28
53 #define WLCONF_DBG(fmt, arg...)
54 #define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len))
55 #define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val))
56 #define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval))
57 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \
59 #define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val))
60 #define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val))
61 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
62 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))
63 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
64 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))
65 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
66 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))
67 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \
71 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
73 #define CHECK_PSK(mode) ((mode) & WPA_AUTH_PSK)
77 struct bsscfg_list
*wlconf_get_bsscfgs(char* ifname
, char* prefix
);
78 int wlconf(char *name
);
79 int wlconf_down(char *name
);
82 wlconf_getint(char* ifname
, int cmd
, int *pval
)
84 return wl_ioctl(ifname
, cmd
, pval
, sizeof(int));
88 wlconf_setint(char* ifname
, int cmd
, int val
)
90 return wl_ioctl(ifname
, cmd
, &val
, sizeof(int));
94 wlconf_wds_clear(char *name
)
96 struct maclist maclist
;
100 WL_IOCTL(name
, WLC_SET_WDSLIST
, &maclist
, sizeof(maclist
));
107 wlconf_set_wep_key(char *name
, char *prefix
, int bsscfg_idx
, int i
)
110 char wl_key
[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
111 char *keystr
, hex
[] = "XX";
112 unsigned char *data
= key
.data
;
115 memset(&key
, 0, sizeof(key
));
117 sprintf(wl_key
, "%skey%d", prefix
, i
);
118 keystr
= nvram_safe_get(wl_key
);
120 switch (strlen(keystr
)) {
122 case WEP128_KEY_SIZE
:
123 key
.len
= strlen(keystr
);
124 strcpy((char *)key
.data
, keystr
);
126 case WEP1_KEY_HEX_SIZE
:
127 case WEP128_KEY_HEX_SIZE
:
128 key
.len
= strlen(keystr
) / 2;
130 strncpy(hex
, keystr
, 2);
131 *data
++ = (unsigned char) strtoul(hex
, NULL
, 16);
140 /* Set current WEP key */
141 if (key
.len
&& i
== atoi(nvram_safe_get(strcat_r(prefix
, "key", wl_key
))))
142 key
.flags
= WL_PRIMARY_KEY
;
144 WL_BSSIOVAR_SET(name
, "wsec_key", bsscfg_idx
, &key
, sizeof(key
));
149 extern struct nvram_tuple router_defaults
[];
151 /* validate/restore all per-interface related variables */
153 wlconf_validate_all(char *prefix
, bool restore
)
155 struct nvram_tuple
*t
;
158 for (t
= router_defaults
; t
->name
; t
++) {
159 if (!strncmp(t
->name
, "wl_", 3)) {
160 strcat_r(prefix
, &t
->name
[3], tmp
);
161 if (!restore
&& nvram_get(tmp
))
163 v
= nvram_get(t
->name
);
164 nvram_set(tmp
, v
? v
: t
->value
);
169 /* restore specific per-interface variable */
171 wlconf_restore_var(char *prefix
, char *name
)
173 struct nvram_tuple
*t
;
175 for (t
= router_defaults
; t
->name
; t
++) {
176 if (!strncmp(t
->name
, "wl_", 3) && !strcmp(&t
->name
[3], name
)) {
177 nvram_set(strcat_r(prefix
, name
, tmp
), t
->value
);
183 wlconf_akm_options(char *prefix
)
191 wl_akm
= nvram_safe_get(strcat_r(prefix
, "akm", comb
));
192 foreach(akm
, wl_akm
, next
) {
193 if (!strcmp(akm
, "wpa"))
194 akm_ret_val
|= WPA_AUTH_UNSPECIFIED
;
195 if (!strcmp(akm
, "psk"))
196 akm_ret_val
|= WPA_AUTH_PSK
;
198 if (!strcmp(akm
, "wpa2"))
199 akm_ret_val
|= WPA2_AUTH_UNSPECIFIED
;
200 if (!strcmp(akm
, "psk2"))
201 akm_ret_val
|= WPA2_AUTH_PSK
;
202 if (!strcmp(akm
, "brcm_psk"))
203 akm_ret_val
|= BRCM_AUTH_PSK
;
211 wlconf_set_wsec(char *ifname
, char *prefix
, int bsscfg_idx
)
218 /* Set wsec bitvec */
219 akm_val
= wlconf_akm_options(prefix
);
221 if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "tkip"))
223 else if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "aes"))
225 else if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "tkip+aes"))
226 val
= TKIP_ENABLED
| AES_ENABLED
;
228 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled"))
230 WL_BSSIOVAR_SETINT(ifname
, "wsec", bsscfg_idx
, val
);
231 /* Set wsec restrict if WSEC_ENABLED */
232 WL_BSSIOVAR_SETINT(ifname
, "wsec_restrict", bsscfg_idx
, val
? 1 : 0);
239 wlconf_set_preauth(char *name
, int bsscfg_idx
, int preauth
)
244 WL_BSSIOVAR_GET(name
, "wpa_cap", bsscfg_idx
, &cap
, sizeof(uint
));
245 if (ret
!= 0) return -1;
248 cap
|= WPA_CAP_WPA2_PREAUTH
;
250 cap
&= ~WPA_CAP_WPA2_PREAUTH
;
252 WL_BSSIOVAR_SETINT(name
, "wpa_cap", bsscfg_idx
, cap
);
259 wlconf_set_radarthrs(char *name
, char *prefix
)
261 wl_radar_thr_t radar_thr
;
263 char nv_buf
[NVRAM_MAX_VALUE_LEN
], *rargs
, *v
, *endptr
;
264 char buf
[WLC_IOCTL_SMLEN
];
265 char *version
= NULL
, *thr0_20_lo
= NULL
, *thr1_20_lo
= NULL
, *thr0_40_lo
= NULL
;
266 char *thr1_40_lo
= NULL
, *thr0_20_hi
= NULL
, *thr1_20_hi
= NULL
, *thr0_40_hi
= NULL
;
267 char *thr1_40_hi
= NULL
;
268 char **locals
[] = { &version
, &thr0_20_lo
, &thr1_20_lo
, &thr0_40_lo
, &thr1_40_lo
,
269 &thr0_20_hi
, &thr1_20_hi
, &thr0_40_hi
, &thr1_40_hi
};
271 rargs
= nvram_safe_get(strcat_r(prefix
, "radarthrs", nv_buf
));
276 if ((len
> NVRAM_MAX_VALUE_LEN
) || (len
== 0))
279 memset(nv_buf
, 0, sizeof(nv_buf
));
280 strncpy(nv_buf
, rargs
, len
);
282 for (i
= 0; i
< (sizeof(locals
) / sizeof(locals
[0])); i
++) {
284 while (*v
&& *v
!= ' ') {
291 if (v
>= (nv_buf
+ len
)) /* Check for complete list, if not caught later */
295 /* Start building request */
296 memset(buf
, 0, sizeof(buf
));
297 strcpy(buf
, "radarthrs");
298 /* Retrieve radar thrs parameters */
301 radar_thr
.version
= atoi(version
);
302 if (radar_thr
.version
> WL_RADAR_THR_VERSION
)
305 /* Retrieve ver 0 params */
308 radar_thr
.thresh0_20_lo
= (uint16
)strtol(thr0_20_lo
, &endptr
, 0);
314 radar_thr
.thresh1_20_lo
= (uint16
)strtol(thr1_20_lo
, &endptr
, 0);
320 radar_thr
.thresh0_40_lo
= (uint16
)strtol(thr0_40_lo
, &endptr
, 0);
326 radar_thr
.thresh1_40_lo
= (uint16
)strtol(thr1_40_lo
, &endptr
, 0);
330 if (radar_thr
.version
== 0) {
332 * Attempt a best effort update of ver 0 to ver 1 by updating
333 * the appropriate values with the specified defaults. The defaults
334 * are from the reference design.
336 radar_thr
.version
= WL_RADAR_THR_VERSION
; /* avoid driver rejecting it */
337 radar_thr
.thresh0_20_hi
= 0x6ac;
338 radar_thr
.thresh1_20_hi
= 0x6cc;
339 radar_thr
.thresh0_40_hi
= 0x6bc;
340 radar_thr
.thresh1_40_hi
= 0x6e0;
342 /* Retrieve ver 1 params */
345 radar_thr
.thresh0_20_hi
= (uint16
)strtol(thr0_20_hi
, &endptr
, 0);
351 radar_thr
.thresh1_20_hi
= (uint16
)strtol(thr1_20_hi
, &endptr
, 0);
357 radar_thr
.thresh0_40_hi
= (uint16
)strtol(thr0_40_hi
, &endptr
, 0);
363 radar_thr
.thresh1_40_hi
= (uint16
)strtol(thr1_40_hi
, &endptr
, 0);
368 /* Copy radar parameters into buffer and plug them to the driver */
369 memcpy((char*)(buf
+ strlen(buf
) + 1), (char*)&radar_thr
, sizeof(wl_radar_thr_t
));
370 WL_IOCTL(name
, WLC_SET_VAR
, buf
, sizeof(buf
));
375 WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n");
382 wlconf_set_wme(char *name
, char *prefix
)
386 int phytype
, gmode
, no_ack
, apsd
, dp
[2];
387 edcf_acparam_t
*acparams
;
388 /* Pay attention to buffer length requirements when using this */
389 char buf
[WLC_IOCTL_SMLEN
];
390 char *v
, *nv_value
, nv
[100];
391 char nv_name
[] = "%swme_%s_%s";
392 char *ac
[] = {"be", "bk", "vi", "vo"};
393 char *cwmin
, *cwmax
, *aifsn
, *txop_b
, *txop_ag
, *admin_forced
, *oldest_first
;
394 char **locals
[] = { &cwmin
, &cwmax
, &aifsn
, &txop_b
, &txop_ag
, &admin_forced
,
396 struct {char *req
; char *str
;} mode
[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"},
397 {"wme_tx_params", "txp"}};
399 /* query the phy type */
400 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
402 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", nv
)));
404 /* WME sta setting first */
405 for (i
= 0; i
< 2; i
++) {
406 /* build request block */
407 memset(buf
, 0, sizeof(buf
));
408 strcpy(buf
, mode
[i
].req
);
409 /* put push wmeac params after "wme-ac" in buf */
410 acparams
= (edcf_acparam_t
*)(buf
+ strlen(buf
) + 1);
412 for (j
= 0; j
< AC_COUNT
; j
++) {
413 /* get packed nvram parameter */
414 snprintf(nv
, sizeof(nv
), nv_name
, prefix
, mode
[i
].str
, ac
[j
]);
415 nv_value
= nvram_safe_get(nv
);
416 strcpy(nv
, nv_value
);
419 for (k
= 0; k
< (sizeof(locals
) / sizeof(locals
[0])); k
++) {
421 while (*v
&& *v
!= ' ')
430 acparams
->ECW
&= ~EDCF_ECWMIN_MASK
;
432 for (val
++, k
= 0; val
; val
>>= 1, k
++);
433 acparams
->ECW
|= (k
? k
- 1 : 0) & EDCF_ECWMIN_MASK
;
435 acparams
->ECW
&= ~EDCF_ECWMAX_MASK
;
437 for (val
++, k
= 0; val
; val
>>= 1, k
++);
438 acparams
->ECW
|= ((k
? k
- 1 : 0) << EDCF_ECWMAX_SHIFT
) & EDCF_ECWMAX_MASK
;
440 acparams
->ACI
&= ~EDCF_AIFSN_MASK
;
441 acparams
->ACI
|= atoi(aifsn
) & EDCF_AIFSN_MASK
;
443 acparams
->ACI
&= ~EDCF_ACI_MASK
;
444 acparams
->ACI
|= j
<< EDCF_ACI_SHIFT
;
446 if (phytype
== PHY_TYPE_B
|| gmode
== 0)
450 acparams
->TXOP
= val
/ 32;
452 acparams
->ACI
&= ~EDCF_ACM_MASK
;
453 val
= strcmp(admin_forced
, "on") ? 0 : 1;
454 acparams
->ACI
|= val
<< 4;
456 /* configure driver */
457 WL_IOCTL(name
, WLC_SET_VAR
, buf
, sizeof(buf
));
462 v
= nvram_safe_get(strcat_r(prefix
, "wme_no_ack", nv
));
463 no_ack
= strcmp(v
, "on") ? 0 : 1;
464 WL_IOVAR_SETINT(name
, "wme_noack", no_ack
);
467 v
= nvram_safe_get(strcat_r(prefix
, "wme_apsd", nv
));
468 apsd
= strcmp(v
, "on") ? 0 : 1;
469 WL_IOVAR_SETINT(name
, "wme_apsd", apsd
);
471 /* set per-AC discard policy */
472 strcpy(buf
, "wme_dp");
473 WL_IOVAR_SETINT(name
, "wme_dp", dp
[1]);
475 /* WME Tx parameters setting */
477 wme_tx_params_t txparams
[AC_COUNT
];
478 char *srl
, *sfbl
, *lrl
, *lfbl
, *maxrate
;
479 char **locals
[] = { &srl
, &sfbl
, &lrl
, &lfbl
, &maxrate
};
481 /* build request block */
482 memset(txparams
, 0, sizeof(txparams
));
484 for (j
= 0; j
< AC_COUNT
; j
++) {
485 /* get packed nvram parameter */
486 snprintf(nv
, sizeof(nv
), nv_name
, prefix
, mode
[2].str
, ac
[j
]);
487 nv_value
= nvram_safe_get(nv
);
488 strcpy(nv
, nv_value
);
491 for (k
= 0; k
< (sizeof(locals
) / sizeof(locals
[0])); k
++) {
493 while (*v
&& *v
!= ' ')
501 /* update short retry limit */
502 txparams
[j
].short_retry
= atoi(srl
);
504 /* update short fallback limit */
505 txparams
[j
].short_fallback
= atoi(sfbl
);
507 /* update long retry limit */
508 txparams
[j
].long_retry
= atoi(lrl
);
510 /* update long fallback limit */
511 txparams
[j
].long_fallback
= atoi(lfbl
);
513 /* update max rate */
514 txparams
[j
].max_rate
= atoi(maxrate
);
517 /* set the WME tx parameters */
518 WL_IOVAR_SET(name
, mode
[2].req
, txparams
, sizeof(txparams
));
527 sleep_ms(const unsigned int ms
)
531 #elif defined(__ECOS)
533 sleep_ms(const unsigned int ms
)
535 cyg_tick_count_t ostick
;
538 cyg_thread_delay(ostick
);
541 #error "sleep_ms() not defined for this OS!!!"
542 #endif /* defined(linux) */
545 * The following condition(s) must be met when Auto Channel Selection
547 * - the I/F is up (change radio channel requires it is up?)
548 * - the AP must not be associated (setting SSID to empty should
549 * make sure it for us)
552 wlconf_auto_channel(char *name
)
555 wl_uint32_list_t request
;
560 /* query the phy type */
561 WL_GETINT(name
, WLC_GET_PHYTYPE
, &phytype
);
563 request
.count
= 0; /* let the ioctl decide */
564 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
566 sleep_ms(phytype
== PHY_TYPE_A
? 1000 : 750);
567 for (i
= 0; i
< 100; i
++) {
568 WL_GETINT(name
, WLC_GET_CHANNEL_SEL
, &chosen
);
574 WLCONF_DBG("interface %s: channel selected %d\n", name
, chosen
);
579 wlconf_auto_chanspec(char *name
)
581 chanspec_t chosen
= 0;
583 wl_uint32_list_t request
;
587 request
.count
= 0; /* let the ioctl decide */
588 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
591 for (i
= 0; i
< 100; i
++) {
592 WL_IOVAR_GETINT(name
, "apcschspec", &temp
);
599 chosen
= (chanspec_t
) temp
;
600 WLCONF_DBG("interface %s: chanspec selected %04x\n", name
, chosen
);
604 /* PHY type/BAND conversion */
605 #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
606 /* PHY type conversion */
607 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
608 (phy) == PHY_TYPE_B ? "b" : \
609 (phy) == PHY_TYPE_LP ? "l" : \
610 (phy) == PHY_TYPE_G ? "g" : "n")
611 #define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
612 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \
613 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \
614 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N)
616 #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */
619 int idx
; /* bsscfg index */
620 char ifname
[PREFIX_LEN
]; /* OS name of interface (debug only) */
621 char prefix
[PREFIX_LEN
]; /* prefix for nvram params (eg. "wl0.1_") */
626 struct bsscfg_info bsscfgs
[WL_MAXBSSCFG
];
630 wlconf_get_bsscfgs(char* ifname
, char* prefix
)
636 struct bsscfg_list
*bclist
;
637 struct bsscfg_info
*bsscfg
;
639 bclist
= (struct bsscfg_list
*)malloc(sizeof(struct bsscfg_list
));
642 memset(bclist
, 0, sizeof(struct bsscfg_list
));
644 /* Set up Primary BSS Config information */
645 bsscfg
= &bclist
->bsscfgs
[0];
647 strncpy(bsscfg
->ifname
, ifname
, PREFIX_LEN
-1);
648 strcpy(bsscfg
->prefix
, prefix
);
651 /* additional virtual BSS Configs from wlX_vifs */
652 foreach(var
, nvram_safe_get(strcat_r(prefix
, "vifs", tmp
)), next
) {
653 if (bclist
->count
== WL_MAXBSSCFG
) {
654 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
656 "while configuring interface \"%s\"\n",
657 ifname
, WL_MAXBSSCFG
, strcat_r(prefix
, "vifs", tmp
), var
);
660 bsscfg
= &bclist
->bsscfgs
[bclist
->count
];
661 if (get_ifname_unit(var
, NULL
, &bsscfg
->idx
) != 0) {
662 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
667 strncpy(bsscfg
->ifname
, var
, PREFIX_LEN
-1);
668 snprintf(bsscfg
->prefix
, PREFIX_LEN
, "%s_", bsscfg
->ifname
);
676 wlconf_security_options(char *name
, char *prefix
, int bsscfg_idx
, bool id_supp
)
685 * Need to check errors (card may have changed) and change to
686 * defaults since the new chip may not support the requested
687 * encryptions after the card has been changed.
689 if (wlconf_set_wsec(name
, prefix
, bsscfg_idx
)) {
690 /* change nvram only, code below will pass them on */
691 wlconf_restore_var(prefix
, "auth_mode");
692 wlconf_restore_var(prefix
, "auth");
693 /* reset wep to default */
694 wlconf_restore_var(prefix
, "crypto");
695 wlconf_restore_var(prefix
, "wep");
696 wlconf_set_wsec(name
, prefix
, bsscfg_idx
);
699 val
= wlconf_akm_options(prefix
);
700 /* enable in-driver wpa supplicant? */
701 if (id_supp
&& !nvram_get_int(strcat_r(prefix
, "disable_wpa_supp", tmp
)) && (CHECK_PSK(val
))) {
705 if (((key
= nvram_get(strcat_r(prefix
, "wpa_psk", tmp
))) != NULL
) &&
706 (strlen(key
) < WSEC_MAX_PSK_LEN
)) {
707 psk
.key_len
= (ushort
) strlen(key
);
708 psk
.flags
= WSEC_PASSPHRASE
;
709 strcpy((char *)psk
.key
, key
);
710 WL_IOCTL(name
, WLC_SET_WSEC_PMK
, &psk
, sizeof(psk
));
712 wl_iovar_setint(name
, "sup_wpa", 1);
714 WL_BSSIOVAR_SETINT(name
, "wpa_auth", bsscfg_idx
, val
);
716 /* EAP Restrict if we have an AKM or radius authentication */
717 val
= ((val
!= 0) || (nvram_match(strcat_r(prefix
, "auth_mode", tmp
), "radius")));
718 WL_BSSIOVAR_SETINT(name
, "eap_restrict", bsscfg_idx
, val
);
721 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled")) {
722 for (i
= 1; i
<= DOT11_MAX_DEFAULT_KEYS
; i
++)
723 wlconf_set_wep_key(name
, prefix
, bsscfg_idx
, i
);
726 /* Set 802.11 authentication mode - open/shared */
727 val
= atoi(nvram_safe_get(strcat_r(prefix
, "auth", tmp
)));
728 WL_BSSIOVAR_SETINT(name
, "auth", bsscfg_idx
, val
);
732 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled
733 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
734 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off,
735 * afterburner is enabled/disabled based on the nvram settings.
737 * WME/WMM is also set in this procedure as it depends on N and afterburner.
738 * N ==> WMM is on by default
739 * N (or ampdu) ==> afterburner is off
740 * WMM ==> afterburner is off
742 * Returns whether afterburner is on in the system.
745 wlconf_aburn_ampdu_amsdu_set(char *name
, char prefix
[PREFIX_LEN
], int nmode
, int btc_mode
)
747 bool ampdu_valid_option
= FALSE
;
748 bool amsdu_valid_option
= FALSE
;
749 bool aburn_valid_option
= FALSE
;
750 int val
, aburn_option_val
= OFF
, ampdu_option_val
= OFF
, amsdu_option_val
= OFF
;
751 int wme_option_val
= ON
; /* On by default */
752 char tmp
[100], var
[80], *next
, *wme_val
;
753 char buf
[WLC_IOCTL_SMLEN
];
756 /* First, clear WMM and afterburner settings to avoid conflicts */
757 WL_IOVAR_SETINT(name
, "wme", OFF
);
758 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
760 /* Get WME setting from NVRAM if present */
761 wme_val
= nvram_get(strcat_r(prefix
, "wme", tmp
));
762 if (wme_val
&& !strcmp(wme_val
, "off")) {
763 wme_option_val
= OFF
;
766 /* Set options based on capability */
767 wl_iovar_get(name
, "cap", (void *)tmp
, 100);
768 foreach(var
, tmp
, next
) {
769 char *nvram_str
= nvram_get(strcat_r(prefix
, var
, buf
));
774 if (!strcmp(nvram_str
, "on"))
776 else if (!strcmp(nvram_str
, "off"))
778 else if (!strcmp(nvram_str
, "auto"))
783 if (btc_mode
!= WL_BTC_PREMPT
&& strncmp(var
, "afterburner", sizeof(var
)) == 0) {
784 aburn_valid_option
= TRUE
;
785 aburn_option_val
= val
;
788 if (strncmp(var
, "ampdu", sizeof(var
)) == 0) {
789 ampdu_valid_option
= TRUE
;
790 ampdu_option_val
= val
;
793 if (strncmp(var
, "amsdu", sizeof(var
)) == 0) {
794 amsdu_valid_option
= TRUE
;
795 amsdu_option_val
= val
;
799 if (nmode
!= OFF
) { /* N-mode is ON/AUTO */
802 if (ampdu_valid_option
) {
803 if (ampdu_option_val
!= OFF
) {
804 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
805 WL_IOVAR_SETINT(name
, "ampdu", ampdu_option_val
);
807 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
811 if (amsdu_valid_option
) {
812 if (amsdu_option_val
!= OFF
) { /* AMPDU (above) has priority over AMSDU */
813 if (ampdu_option_val
== OFF
) {
814 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
815 WL_IOVAR_SETINT(name
, "amsdu", amsdu_option_val
);
818 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
820 /* allow ab in N mode. Do this last: may defeat ampdu et al */
821 if (aburn_valid_option
) {
822 WL_IOVAR_SETINT(name
, "afterburner_override", aburn_option_val
);
824 /* Also turn off N reqd setting if ab is not OFF */
825 if (aburn_option_val
!= 0)
826 WL_IOVAR_SETINT(name
, "nreqd", 0);
830 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
831 * if WME is off, set the afterburner based on the configured nvram setting.
833 wl_iovar_setint(name
, "amsdu", OFF
);
834 wl_iovar_setint(name
, "ampdu", OFF
);
835 if (wme_option_val
!= OFF
) { /* Can't have afterburner with WMM */
836 if (aburn_valid_option
) {
837 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
839 } else if (aburn_valid_option
) { /* Okay, use NVRam setting for afterburner */
840 WL_IOVAR_SETINT(name
, "afterburner_override", aburn_option_val
);
844 if (wme_option_val
&& aburn_option_val
== 0) {
845 WL_IOVAR_SETINT(name
, "wme", wme_option_val
);
846 wlconf_set_wme(name
, prefix
);
849 return wme_option_val
;
852 #define VIFNAME_LEN 16
854 /* configure the specified wireless interface */
858 int restore_defaults
, val
, unit
, phytype
, bandtype
, gmode
= 0, ret
= 0;
860 int error_bg
, error_a
;
861 struct bsscfg_list
*bclist
= NULL
;
862 struct bsscfg_info
*bsscfg
;
863 char tmp
[100], prefix
[PREFIX_LEN
];
864 char var
[80], *next
, phy
[] = "a", *str
, *addr
= NULL
;
865 /* Pay attention to buffer length requirements when using this */
866 char buf
[WLC_IOCTL_SMLEN
];
870 struct maclist
*maclist
;
871 struct ether_addr
*ea
;
876 int ap
, apsta
, wds
, sta
= 0, wet
= 0, mac_spoof
= 0;
877 char country_code
[4];
878 int nas_will_run
= 0;
887 int wl_ap_build
= 0; /* wl compiled with AP capabilities */
888 char cap
[WLC_IOCTL_SMLEN
];
889 char caps
[WLC_IOCTL_SMLEN
];
892 uint nbw
= WL_CHANSPEC_BW_20
;
893 int nmode
= OFF
; /* 802.11n support */
894 char vif_addr
[WLC_IOCTL_SMLEN
];
898 bool ure_enab
= FALSE
;
899 bool radar_enab
= FALSE
;
901 /* wlconf doesn't work for virtual i/f, so if we are given a
902 * virtual i/f return 0 if that interface is in it's parent's "vifs"
903 * list otherwise return -1
905 if (get_ifname_unit(name
, &wlunit
, &wlsubunit
) == 0)
909 /* we have been given a virtual i/f,
910 * is it in it's parent i/f's virtual i/f list?
912 sprintf(tmp
, "wl%d_vifs", wlunit
);
914 if (strstr(nvram_safe_get(tmp
), name
) == NULL
)
915 return -1; /* config error */
926 memset(tmp
, 0, sizeof(tmp
));
928 /* because of ifdefs in wl driver, when we don't have AP capabilities we
929 * can't use the same iovars to configure the wl.
930 * so we use "wl_ap_build" to help us know how to configure the driver
932 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
935 foreach(cap
, caps
, next
) {
936 if (!strcmp(cap
, "ap")) {
939 else if (!strcmp(cap
, "mbss16"))
941 else if (!strcmp(cap
, "mbss4"))
945 /* Check interface (fail silently for non-wl interfaces) */
946 if ((ret
= wl_probe(name
)))
949 /* Get MAC address */
950 (void) wl_hwaddr(name
, (uchar
*)buf
);
951 memcpy(vif_addr
, buf
, ETHER_ADDR_LEN
);
954 WL_IOCTL(name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
));
955 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
957 /* Restore defaults if per-interface parameters do not exist */
958 restore_defaults
= !nvram_get(strcat_r(prefix
, "ifname", tmp
));
959 wlconf_validate_all(prefix
, restore_defaults
);
960 nvram_set(strcat_r(prefix
, "ifname", tmp
), name
);
961 nvram_set(strcat_r(prefix
, "hwaddr", tmp
), ether_etoa((uchar
*)buf
, eaddr
));
962 snprintf(buf
, sizeof(buf
), "%d", unit
);
963 nvram_set(strcat_r(prefix
, "unit", tmp
), buf
);
966 /* Bring the interface down */
967 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
969 /* Disable all BSS Configs */
970 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
971 struct {int bsscfg_idx
; int enable
;} setbuf
;
972 setbuf
.bsscfg_idx
= i
;
975 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
977 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
978 /* fail quietly on a range error since the driver may
979 * support fewer bsscfgs than we are prepared to configure
981 if (bcmerr
== BCME_RANGE
)
985 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
986 " (down) failed, ret = %d, bcmerr = %d\n",
987 __LINE__
, name
, i
, ret
, bcmerr
);
990 /* Get the list of BSS Configs */
991 bclist
= wlconf_get_bsscfgs(name
, prefix
);
992 if (bclist
== NULL
) {
998 /* create a wlX.Y_ifname nvram setting */
999 for (i
= 1; i
< bclist
->count
; i
++) {
1000 bsscfg
= &bclist
->bsscfgs
[i
];
1001 #if defined(linux) || defined(__ECOS)
1002 strcpy(var
, bsscfg
->ifname
);
1004 nvram_set(strcat_r(bsscfg
->prefix
, "ifname", tmp
), var
);
1007 /* If ure_disable is not present or is 1, ure is not enabled;
1008 * that is, if it is present and 0, ure is enabled.
1010 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
1014 /* Enable MBSS mode if appropriate */
1016 WL_IOVAR_SETINT(name
, "mbss", (bclist
->count
> 1));
1020 * Set SSID for each BSS Config
1022 for (i
= 0; i
< bclist
->count
; i
++) {
1023 bsscfg
= &bclist
->bsscfgs
[i
];
1024 strcat_r(bsscfg
->prefix
, "ssid", tmp
);
1025 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
1026 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
1027 ssid
.SSID_len
= sizeof(ssid
.SSID
);
1028 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
), ssid
.SSID_len
);
1029 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1030 "with SSID \"%s\"\n", name
, bsscfg
->idx
,
1031 bsscfg
->ifname
, nvram_safe_get(tmp
));
1032 WL_BSSIOVAR_SET(name
, "ssid", bsscfg
->idx
, &ssid
,
1037 /* Create addresses for VIFs */
1039 /* set local bit for our MBSS vif base */
1040 ETHER_SET_LOCALADDR(vif_addr
);
1042 /* construct and set other wlX.Y_hwaddr */
1043 for (i
= 1; i
< max_no_vifs
; i
++) {
1044 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr", unit
, i
);
1045 addr
= nvram_safe_get(tmp
);
1046 if (!strcmp(addr
, "")) {
1047 vif_addr
[5] = (vif_addr
[5] & ~(max_no_vifs
-1))
1048 | ((max_no_vifs
-1) & (vif_addr
[5]+1));
1050 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
,
1054 /* The addresses are available in NVRAM, so set them */
1055 for (i
= 1; i
< max_no_vifs
; i
++) {
1056 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_bss_enabled",
1058 if (!strcmp(nvram_safe_get(tmp
), "1")) {
1059 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr",
1061 ether_atoe(nvram_safe_get(tmp
), (unsigned char *)eaddr
);
1062 WL_BSSIOVAR_SET(name
, "cur_etheraddr", i
,
1063 eaddr
, ETHER_ADDR_LEN
);
1066 } else { /* URE is enabled */
1067 /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
1068 snprintf(tmp
, sizeof(tmp
), "wl%d.1_hwaddr", unit
);
1069 WL_BSSIOVAR_SET(name
, "cur_etheraddr", 1, vif_addr
,
1071 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
, eaddr
));
1074 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1075 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
1076 ap
= (!strcmp(str
, "") || !strcmp(str
, "ap"));
1077 apsta
= (!strcmp(str
, "apsta") ||
1078 ((!strcmp(str
, "sta") || !strcmp(str
, "wet")) &&
1079 bclist
->count
> 1));
1080 sta
= (!strcmp(str
, "sta") && bclist
->count
== 1);
1081 wds
= !strcmp(str
, "wds");
1082 wet
= !strcmp(str
, "wet");
1083 mac_spoof
= !strcmp(str
, "mac_spoof");
1085 /* set apsta var first, because APSTA mode takes precedence */
1086 WL_IOVAR_SETINT(name
, "apsta", apsta
);
1089 val
= (ap
|| apsta
|| wds
) ? 1 : 0;
1090 WL_IOCTL(name
, WLC_SET_AP
, &val
, sizeof(val
));
1094 WL_IOCTL(name
, WLC_SET_WET
, &wet
, sizeof(wet
));
1098 WL_IOVAR_SETINT(name
, "mac_spoof", 1);
1101 /* For STA configurations, configure association retry time.
1102 * Use specified time (capped), or mode-specific defaults.
1104 if (sta
|| wet
|| apsta
) {
1105 char *retry_time
= nvram_safe_get(strcat_r(prefix
, "sta_retry_time", tmp
));
1106 val
= atoi(retry_time
);
1107 WL_IOVAR_SETINT(name
, "sta_retry_time", val
);
1110 /* Retain remaining WET effects only if not APSTA */
1113 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1116 val
= atoi(nvram_safe_get(strcat_r(prefix
, "infra", tmp
)));
1117 WL_IOCTL(name
, WLC_SET_INFRA
, &val
, sizeof(val
));
1119 /* Set The AP MAX Associations Limit */
1121 max_assoc
= val
= atoi(nvram_safe_get(strcat_r(prefix
, "maxassoc", tmp
)));
1123 WL_IOVAR_SETINT(name
, "maxassoc", val
);
1124 } else { /* Get value from driver if not in nvram */
1125 WL_IOVAR_GETINT(name
, "maxassoc", &max_assoc
);
1129 for (i
= 0; i
< bclist
->count
; i
++) {
1131 bsscfg
= &bclist
->bsscfgs
[i
];
1134 /* XXXMSSID: The note about setting preauth now does not seem right.
1135 * NAS brings the BSS up if it runs, so setting the preauth value
1136 * will make it in the bcn/prb. If that is right, we can move this
1137 * chunk out of wlconf.
1140 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1141 * if we do it in the NAS we need to bring down the interface and up to make
1142 * it affect in the beacons
1144 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1146 preauth
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "preauth", tmp
));
1147 if (strlen (preauth
) != 0) {
1148 set_preauth
= atoi(preauth
);
1150 wlconf_set_preauth(name
, bsscfg
->idx
, set_preauth
);
1152 #endif /* BCMWPA2 */
1154 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1156 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1157 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "bss_maxassoc", tmp
)));
1159 WL_BSSIOVAR_SETINT(name
, "bss_maxassoc", bsscfg
->idx
, val
);
1160 } else if (max_assoc
> 0) { /* Set maxassoc same as global if not set */
1161 snprintf(var
, sizeof(var
), "%d", max_assoc
);
1162 nvram_set(tmp
, var
);
1166 /* Set network type */
1167 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "closed", tmp
)));
1168 WL_BSSIOVAR_SETINT(name
, "closednet", bsscfg
->idx
, val
);
1170 /* Set the ap isolate mode */
1171 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "ap_isolate", tmp
)));
1172 WL_BSSIOVAR_SETINT(name
, "ap_isolate", bsscfg
->idx
, val
);
1175 /* Set up the country code */
1176 (void) strcat_r(prefix
, "country_code", tmp
);
1177 country
= nvram_get(tmp
);
1178 if (country
&& country
[0] != '\0') {
1179 strncpy(country_code
, country
, sizeof(country_code
));
1180 WL_IOCTL(name
, WLC_SET_COUNTRY
, country_code
, strlen(country_code
)+1);
1182 /* Get the default country code if undefined */
1183 WL_IOCTL(name
, WLC_GET_COUNTRY
, country_code
, sizeof(country_code
));
1185 /* Add the new NVRAM variable */
1186 nvram_set("wl_country_code", country_code
);
1187 (void) strcat_r(prefix
, "country_code", tmp
);
1188 nvram_set(tmp
, country_code
);
1191 /* Change LED Duty Cycle */
1192 leddc
= (uint32
)strtoul(nvram_safe_get(strcat_r(prefix
, "leddc", tmp
)), NULL
, 16);
1194 WL_IOVAR_SETINT(name
, "leddc", leddc
);
1196 /* Enable or disable the radio */
1197 val
= nvram_match(strcat_r(prefix
, "radio", tmp
), "0");
1198 val
+= WL_RADIO_SW_DISABLE
<< 16;
1199 WL_IOCTL(name
, WLC_SET_RADIO
, &val
, sizeof(val
));
1201 /* Get supported phy types */
1202 WL_IOCTL(name
, WLC_GET_PHYLIST
, var
, sizeof(var
));
1203 nvram_set(strcat_r(prefix
, "phytypes", tmp
), var
);
1206 *(next
= buf
) = '\0';
1207 for (i
= 0; i
< strlen(var
); i
++) {
1208 /* Switch to band */
1210 val
= WLCONF_STR2PHYTYPE(phy
);
1211 if (val
== PHY_TYPE_N
) {
1212 WL_GETINT(name
, WLC_GET_BAND
, &val
);
1214 val
= WLCONF_PHYTYPE2BAND(val
);
1215 WL_IOCTL(name
, WLC_SET_BAND
, &val
, sizeof(val
));
1216 /* Get radio ID on this band */
1217 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1218 next
+= sprintf(next
, "%sBCM%X", i
? " " : "",
1219 (rev
.radiorev
& IDCODE_ID_MASK
) >> IDCODE_ID_SHIFT
);
1221 nvram_set(strcat_r(prefix
, "radioids", tmp
), buf
);
1224 str
= nvram_get(strcat_r(prefix
, "phytype", tmp
));
1225 val
= WLCONF_STR2PHYTYPE(str
);
1226 /* For NPHY use band value from NVRAM */
1227 if (val
== PHY_TYPE_N
) {
1228 str
= nvram_get(strcat_r(prefix
, "nband", tmp
));
1232 WL_GETINT(name
, WLC_GET_BAND
, &val
);
1235 val
= WLCONF_PHYTYPE2BAND(val
);
1237 WL_SETINT(name
, WLC_SET_BAND
, val
);
1239 /* Check errors (card may have changed) */
1241 /* default band to the first band in band list */
1243 val
= WLCONF_STR2PHYTYPE(phy
);
1244 val
= WLCONF_PHYTYPE2BAND(val
);
1245 WL_SETINT(name
, WLC_SET_BAND
, val
);
1248 /* Store the resolved bandtype */
1251 /* Get current core revision */
1252 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1253 snprintf(buf
, sizeof(buf
), "%d", rev
.corerev
);
1254 nvram_set(strcat_r(prefix
, "corerev", tmp
), buf
);
1256 /* Get current phy type */
1257 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
1258 snprintf(buf
, sizeof(buf
), "%s", WLCONF_PHYTYPE2STR(phytype
));
1259 nvram_set(strcat_r(prefix
, "phytype", tmp
), buf
);
1261 /* Setup regulatory mode */
1262 strcat_r(prefix
, "reg_mode", tmp
);
1263 if (nvram_match(tmp
, "off")) {
1265 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1266 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1267 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1268 } else if (nvram_match(tmp
, "h")) {
1270 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1272 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1274 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1276 /* Set the CAC parameters */
1277 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dfs_preism", tmp
)));
1278 wl_iovar_setint(name
, "dfs_preism", val
);
1279 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dfs_postism", tmp
)));
1280 wl_iovar_setint(name
, "dfs_postism", val
);
1281 val
= atoi(nvram_safe_get(strcat_r(prefix
, "tpc_db", tmp
)));
1282 WL_IOCTL(name
, WLC_SEND_PWR_CONSTRAINT
, &val
, sizeof(val
));
1284 } else if (nvram_match(tmp
, "d")) {
1286 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1287 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1289 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1292 /* Reset to hardware rateset (band may have changed) */
1293 WL_IOCTL(name
, WLC_GET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1294 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1296 /* set bandwidth capability for nphy and calculate nbw */
1297 if (phytype
== PHY_TYPE_N
) {
1298 /* Get the user nmode setting now */
1299 nmode
= AUTO
; /* enable by default for NPHY */
1301 strcat_r(prefix
, "nmode", tmp
);
1302 if (nvram_match(tmp
, "0"))
1305 val
= (nmode
!= OFF
) ? atoi(nvram_safe_get(strcat_r(prefix
, "nbw_cap", tmp
))) :
1308 WL_IOVAR_SETINT(name
, "nmode", (uint32
)nmode
);
1309 WL_IOVAR_SETINT(name
, "mimo_bw_cap", val
);
1311 if (((bandtype
== WLC_BAND_2G
) && (val
== WLC_N_BW_40ALL
)) ||
1312 ((bandtype
== WLC_BAND_5G
) &&
1313 (val
== WLC_N_BW_40ALL
|| val
== WLC_N_BW_20IN2G_40IN5G
)))
1314 nbw
= WL_CHANSPEC_BW_40
;
1316 nbw
= WL_CHANSPEC_BW_20
;
1319 /* Set channel before setting gmode or rateset */
1320 /* Manual Channel Selection - when channel # is not 0 */
1321 val
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
)));
1322 if (val
&& phytype
!= PHY_TYPE_N
) {
1323 WL_SETINT(name
, WLC_SET_CHANNEL
, val
);
1325 /* Use current channel (card may have changed) */
1326 WL_IOCTL(name
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
1327 snprintf(buf
, sizeof(buf
), "%d", ci
.target_channel
);
1328 nvram_set(strcat_r(prefix
, "channel", tmp
), buf
);
1330 } else if (val
&& phytype
== PHY_TYPE_N
) {
1331 chanspec_t chanspec
= 0;
1333 uint nctrlsb
= WL_CHANSPEC_CTL_SB_NONE
;
1337 /* Get Ctrl SB for 40MHz channel */
1338 if (nbw
== WL_CHANSPEC_BW_40
) {
1339 str
= nvram_safe_get(strcat_r(prefix
, "nctrlsb", tmp
));
1341 /* Adjust the channel to be center channel */
1342 if (!strcmp(str
, "lower")) {
1343 nctrlsb
= WL_CHANSPEC_CTL_SB_LOWER
;
1344 channel
= channel
+ 2;
1345 } else if (!strcmp(str
, "upper")) {
1346 nctrlsb
= WL_CHANSPEC_CTL_SB_UPPER
;
1347 channel
= channel
- 2;
1351 /* band | BW | CTRL SB | Channel */
1352 chanspec
|= ((bandtype
<< WL_CHANSPEC_BAND_SHIFT
) |
1353 (nbw
| nctrlsb
| channel
));
1355 WL_IOVAR_SETINT(name
, "chanspec", (uint32
)chanspec
);
1358 /* Set up number of Tx and Rx streams */
1359 if (phytype
== PHY_TYPE_N
) {
1363 wl_iovar_getint(name
, "txchain_cnt", &count
);
1364 /* update NVRAM with capabilities */
1365 snprintf(var
, sizeof(var
), "%d", count
);
1366 nvram_set(strcat_r(prefix
, "txchain_cnt", tmp
), var
);
1368 /* Verify that there is an NVRAM param for txstreams, if not create it and
1369 * set it to txchain_cnt
1371 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "txstreams", tmp
)));
1373 /* invalid - NVRAM needs to be fixed/initialized */
1374 nvram_set(strcat_r(prefix
, "txstreams", tmp
), var
);
1377 /* Apply user configured txstreams, use 1 if user disabled nmode */
1380 WL_IOVAR_SETINT(name
, "txstreams", streams
);
1382 wl_iovar_getint(name
, "rxchain_cnt", &count
);
1383 /* update NVRAM with capabilities */
1384 snprintf(var
, sizeof(var
), "%d", count
);
1385 nvram_set(strcat_r(prefix
, "rxchain_cnt", tmp
), var
);
1387 /* Verify that there is an NVRAM param for rxstreams, if not create it and
1388 * set it to txchain_cnt
1390 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "rxstreams", tmp
)));
1392 /* invalid - NVRAM needs to be fixed/initialized */
1393 nvram_set(strcat_r(prefix
, "rxstreams", tmp
), var
);
1397 /* Apply user configured rxstreams, use 1 if user disabled nmode */
1400 WL_IOVAR_SETINT(name
, "rxstreams", streams
);
1404 if (bandtype
== WLC_BAND_2G
) {
1405 int override
= WLC_PROTECTION_OFF
;
1406 int control
= WLC_PROTECTION_CTL_OFF
;
1409 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", tmp
)));
1410 WL_IOCTL(name
, WLC_SET_GMODE
, &gmode
, sizeof(gmode
));
1412 /* Set gmode protection override and control algorithm */
1413 strcat_r(prefix
, "gmode_protection", tmp
);
1414 if (nvram_match(tmp
, "auto")) {
1415 override
= WLC_PROTECTION_AUTO
;
1416 control
= WLC_PROTECTION_CTL_OVERLAP
;
1418 WL_IOCTL(name
, WLC_SET_GMODE_PROTECTION_OVERRIDE
, &override
, sizeof(override
));
1419 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
1422 /* Set nmode_protection */
1423 if (phytype
== PHY_TYPE_N
) {
1424 int override
= WLC_PROTECTION_OFF
;
1425 int control
= WLC_PROTECTION_CTL_OFF
;
1427 /* Set n protection override and control algorithm */
1428 strcat_r(prefix
, "nmode_protection", tmp
);
1430 if (nvram_match(tmp
, "auto")) {
1431 override
= WLC_PROTECTION_AUTO
;
1432 control
= WLC_PROTECTION_CTL_OVERLAP
;
1435 WL_IOVAR_SETINT(name
, "nmode_protection_override",
1437 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
1440 /* Set 802.11n required */
1442 uint32 nreqd
= OFF
; /* default */
1444 strcat_r(prefix
, "nreqd", tmp
);
1446 if (nvram_match(tmp
, "1"))
1449 WL_IOVAR_SETINT(name
, "nreqd", nreqd
);
1452 /* Set vlan_prio_mode */
1454 uint32 mode
= OFF
; /* default */
1456 strcat_r(prefix
, "vlan_prio_mode", tmp
);
1458 if (nvram_match(tmp
, "on"))
1461 WL_IOVAR_SETINT(name
, "vlan_mode", mode
);
1464 /* Get bluetooth coexistance(BTC) mode */
1465 btc_mode
= atoi(nvram_safe_get(strcat_r(prefix
, "btc_mode", tmp
)));
1467 /* Set the afterburner, AMPDU and AMSDU options based on the N-mode */
1468 wme_global
= wlconf_aburn_ampdu_amsdu_set(name
, prefix
, nmode
, btc_mode
);
1470 /* Now that wme_global is known, check per-BSS disable settings */
1471 for (i
= 0; i
< bclist
->count
; i
++) {
1473 bsscfg
= &bclist
->bsscfgs
[i
];
1475 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1477 /* For each BSS, check WME; make sure wme is set properly for this interface */
1478 strcat_r(subprefix
, "wme", tmp
);
1479 nvram_set(tmp
, wme_global
? "on" : "off");
1481 str
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "wme_bss_disable", tmp
));
1482 val
= (str
[0] == '1') ? 1 : 0;
1483 WL_BSSIOVAR_SETINT(name
, "wme_bss_disable", bsscfg
->idx
, val
);
1487 if (!wl_iovar_setint(name
, "btc_mode", btc_mode
)) {
1488 if (btc_mode
== WL_BTC_PREMPT
) {
1489 wl_rateset_t rs_tmp
= rs
;
1490 /* remove 1Mbps and 2 Mbps from rateset */
1491 for (i
= 0, rs
.count
= 0; i
< rs_tmp
.count
; i
++) {
1492 if ((rs_tmp
.rates
[i
] & 0x7f) == 2 || (rs_tmp
.rates
[i
] & 0x7f) == 4)
1494 rs
.rates
[rs
.count
++] = rs_tmp
.rates
[i
];
1499 /* Allow short preamble override for b cards */
1500 if (phytype
== PHY_TYPE_B
||
1501 (phytype
== PHY_TYPE_G
&& (gmode
== GMODE_LEGACY_B
|| gmode
== GMODE_AUTO
))) {
1502 strcat_r(prefix
, "plcphdr", tmp
);
1503 if (nvram_match(tmp
, "long"))
1504 val
= WLC_PLCP_AUTO
;
1506 val
= WLC_PLCP_SHORT
;
1507 WL_IOCTL(name
, WLC_SET_PLCPHDR
, &val
, sizeof(val
));
1510 /* Set rate in 500 Kbps units */
1511 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rate", tmp
))) / 500000;
1513 /* Convert Auto mcsidx to Auto rate */
1514 if (phytype
== PHY_TYPE_N
) {
1515 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
1517 /* -1 mcsidx used to designate AUTO rate */
1522 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1523 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
1524 /* Must b/g band. Set to 5.5Mbps */
1527 /* it is band-blind. try both band */
1528 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
1529 error_a
= wl_iovar_setint(name
, "a_rate", val
);
1531 if (error_bg
&& error_a
) {
1532 /* both failed. Try default rate (card may have changed) */
1535 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
1536 error_a
= wl_iovar_setint(name
, "a_rate", val
);
1538 snprintf(buf
, sizeof(buf
), "%d", val
);
1539 nvram_set(strcat_r(prefix
, "rate", tmp
), buf
);
1542 /* check if nrate needs to be applied */
1545 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
1546 bool ismcs
= (mcsidx
>= 0);
1548 /* mcsidx of 32 is valid only for 40 Mhz */
1549 if (mcsidx
== 32 && nbw
== WL_CHANSPEC_BW_20
) {
1552 nvram_set(strcat_r(prefix
, "nmcsidx", tmp
), "-1");
1555 /* Use nrate iovar only for MCS rate. */
1557 nrate
|= NRATE_MCS_INUSE
;
1558 nrate
|= mcsidx
& NRATE_RATE_MASK
;
1560 WL_IOVAR_SETINT(name
, "nrate", nrate
);
1564 /* Set multicast rate in 500 Kbps units */
1565 val
= atoi(nvram_safe_get(strcat_r(prefix
, "mrate", tmp
))) / 500000;
1566 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1567 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
1568 /* Must b/g band. Set to 5.5Mbps */
1571 /* it is band-blind. try both band */
1572 error_bg
= wl_iovar_setint(name
, "bg_mrate", val
);
1573 error_a
= wl_iovar_setint(name
, "a_mrate", val
);
1575 if (error_bg
&& error_a
) {
1576 /* Try default rate (card may have changed) */
1579 wl_iovar_setint(name
, "bg_mrate", val
);
1580 wl_iovar_setint(name
, "a_mrate", val
);
1582 snprintf(buf
, sizeof(buf
), "%d", val
);
1583 nvram_set(strcat_r(prefix
, "mrate", tmp
), buf
);
1586 /* Set fragmentation threshold */
1587 val
= atoi(nvram_safe_get(strcat_r(prefix
, "frag", tmp
)));
1588 wl_iovar_setint(name
, "fragthresh", val
);
1590 /* Set RTS threshold */
1591 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rts", tmp
)));
1592 wl_iovar_setint(name
, "rtsthresh", val
);
1594 /* Set DTIM period */
1595 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dtim", tmp
)));
1596 WL_IOCTL(name
, WLC_SET_DTIMPRD
, &val
, sizeof(val
));
1598 /* Set beacon period */
1599 val
= atoi(nvram_safe_get(strcat_r(prefix
, "bcn", tmp
)));
1600 WL_IOCTL(name
, WLC_SET_BCNPRD
, &val
, sizeof(val
));
1602 /* Set framebursting mode */
1603 if (btc_mode
== WL_BTC_PREMPT
)
1606 val
= nvram_match(strcat_r(prefix
, "frameburst", tmp
), "on");
1607 WL_IOCTL(name
, WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
1609 /* Set RIFS mode based on framebursting */
1610 if (phytype
== PHY_TYPE_N
) {
1611 char *nvram_str
= nvram_safe_get(strcat_r(prefix
, "rifs", tmp
));
1612 if (!strcmp(nvram_str
, "on"))
1613 wl_iovar_setint(name
, "rifs", ON
);
1614 else if (!strcmp(nvram_str
, "off"))
1615 wl_iovar_setint(name
, "rifs", OFF
);
1618 /* Override BA mode only if set to on/off */
1619 ba
= nvram_safe_get(strcat_r(prefix
, "ba", tmp
));
1620 if (!strcmp(ba
, "on"))
1621 wl_iovar_setint(name
, "ba", ON
);
1622 else if (!strcmp(ba
, "off"))
1623 wl_iovar_setint(name
, "ba", OFF
);
1625 if (phytype
== PHY_TYPE_N
) {
1626 val
= AVG_DMA_XFER_RATE
;
1627 wl_iovar_set(name
, "avg_dma_xfer_rate", &val
, sizeof(val
));
1630 /* Bring the interface back up */
1631 WL_IOCTL(name
, WLC_UP
, NULL
, 0);
1634 val
= atoi(nvram_safe_get(strcat_r(prefix
, "antdiv", tmp
)));
1635 WL_IOCTL(name
, WLC_SET_ANTDIV
, &val
, sizeof(val
));
1638 /* Get current rateset (gmode may have changed) */
1639 WL_IOCTL(name
, WLC_GET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1641 strcat_r(prefix
, "rateset", tmp
);
1642 if (nvram_match(tmp
, "all")) {
1643 /* Make all rates basic */
1644 for (i
= 0; i
< rs
.count
; i
++)
1645 rs
.rates
[i
] |= 0x80;
1646 } else if (nvram_match(tmp
, "12") && bandtype
== WLC_BAND_2G
) {
1647 /* Make 1 and 2 basic */
1648 for (i
= 0; i
< rs
.count
; i
++) {
1649 if ((rs
.rates
[i
] & 0x7f) == 2 || (rs
.rates
[i
] & 0x7f) == 4)
1650 rs
.rates
[i
] |= 0x80;
1652 rs
.rates
[i
] &= ~0x80;
1657 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1659 /* Set radar parameters if it is enabled */
1661 wlconf_set_radarthrs(name
, prefix
);
1664 /* The following condition(s) must be met in order for Auto Channel Selection to work.
1665 * - the I/F must be up for the channel scan
1666 * - the AP must not be supporting a BSS (all BSS Configs must be disabled)
1669 int channel
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
)));
1672 if (phytype
== PHY_TYPE_N
) {
1673 chanspec_t chanspec
;
1674 chanspec
= wlconf_auto_chanspec(name
);
1676 WL_IOVAR_SETINT(name
, "chanspec", chanspec
);
1678 /* select a channel */
1679 val
= wlconf_auto_channel(name
);
1680 /* switch to the selected channel */
1682 WL_IOCTL(name
, WLC_SET_CHANNEL
, &val
, sizeof(val
));
1684 /* set the auto channel scan timer in the driver when in auto mode */
1686 val
= 15; /* 15 minutes for now */
1692 /* reset the channel scan timer in the driver when not in auto mode */
1696 WL_IOCTL(name
, WLC_SET_CS_SCAN_TIMER
, &val
, sizeof(val
));
1699 /* Security settings for each BSS Configuration */
1700 for (i
= 0; i
< bclist
->count
; i
++) {
1701 bsscfg
= &bclist
->bsscfgs
[i
];
1702 wlconf_security_options(name
, bsscfg
->prefix
, bsscfg
->idx
, wet
| sta
);
1705 /* AP only config */
1706 if (ap
|| apsta
|| wds
) {
1707 /* Set lazy WDS mode */
1708 val
= atoi(nvram_safe_get(strcat_r(prefix
, "lazywds", tmp
)));
1709 WL_IOCTL(name
, WLC_SET_LAZYWDS
, &val
, sizeof(val
));
1711 /* Set the WDS list */
1712 maclist
= (struct maclist
*) buf
;
1715 foreach(var
, nvram_safe_get(strcat_r(prefix
, "wds", tmp
)), next
) {
1716 if (((char *)(ea
->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
1718 ether_atoe(var
, ea
->octet
);
1722 WL_IOCTL(name
, WLC_SET_WDSLIST
, buf
, sizeof(buf
));
1724 /* Set WDS link detection timeout */
1725 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wds_timeout", tmp
)));
1726 wl_iovar_setint(name
, "wdstimeout", val
);
1730 * Finally enable BSS Configs or Join BSS
1732 * AP: Enable BSS Config to bring AP up only when nas will not run
1733 * STA: Join the BSS regardless.
1735 for (i
= 0; i
< bclist
->count
; i
++) {
1736 struct {int bsscfg_idx
; int enable
;} setbuf
;
1737 char vifname
[VIFNAME_LEN
];
1738 char *name_ptr
= name
;
1740 setbuf
.bsscfg_idx
= bclist
->bsscfgs
[i
].idx
;
1743 bsscfg
= &bclist
->bsscfgs
[i
];
1744 if (nvram_match(strcat_r(bsscfg
->prefix
, "bss_enabled", tmp
), "1")) {
1748 /* Set the MAC list */
1749 maclist
= (struct maclist
*)buf
;
1751 if (!nvram_match(strcat_r(bsscfg
->prefix
, "macmode", tmp
), "disabled")) {
1753 foreach(var
, nvram_safe_get(strcat_r(bsscfg
->prefix
, "maclist", tmp
)),
1755 if (((char *)((&ea
[1])->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
1757 if (ether_atoe(var
, ea
->octet
)) {
1764 if (setbuf
.bsscfg_idx
== 0) {
1766 } else { /* Non-primary BSS; changes name syntax */
1767 char tmp
[VIFNAME_LEN
];
1770 /* Remove trailing _ if present */
1771 memset(tmp
, 0, sizeof(tmp
));
1772 strncpy(tmp
, bsscfg
->prefix
, VIFNAME_LEN
- 1);
1773 if (((len
= strlen(tmp
)) > 0) && (tmp
[len
- 1] == '_')) {
1776 nvifname_to_osifname(tmp
, vifname
, VIFNAME_LEN
);
1780 WL_IOCTL(name_ptr
, WLC_SET_MACLIST
, buf
, sizeof(buf
));
1782 /* Set macmode for each VIF */
1783 (void) strcat_r(bsscfg
->prefix
, "macmode", tmp
);
1785 if (nvram_match(tmp
, "deny"))
1786 val
= WLC_MACMODE_DENY
;
1787 else if (nvram_match(tmp
, "allow"))
1788 val
= WLC_MACMODE_ALLOW
;
1790 val
= WLC_MACMODE_DISABLED
;
1792 WL_IOCTL(name_ptr
, WLC_SET_MACMODE
, &val
, sizeof(val
));
1794 /* NAS runs if we have an AKM or radius authentication */
1795 nas_will_run
= wlconf_akm_options(bclist
->bsscfgs
[i
].prefix
) ||
1796 nvram_match(strcat_r(bclist
->bsscfgs
[i
].prefix
, "auth_mode", tmp
),
1799 if (((ap
|| apsta
) && !nas_will_run
) || sta
|| wet
) {
1800 for (ii
= 0; ii
< MAX_BSS_UP_RETRIES
; ii
++) {
1802 WL_IOVAR_SET(name
, "bss", &setbuf
, sizeof(setbuf
));
1805 strcat_r(prefix
, "ssid", tmp
);
1806 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
1807 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
1808 ssid
.SSID_len
= sizeof(ssid
.SSID
);
1809 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
),
1811 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
1813 if (apsta
&& (ret
!= 0))
1830 wlconf_down(char *name
)
1836 struct {int bsscfg_idx
; int enable
;} setbuf
;
1837 int wl_ap_build
= 0; /* 1 = wl compiled with AP capabilities */
1838 char cap
[WLC_IOCTL_SMLEN
];
1839 char caps
[WLC_IOCTL_SMLEN
];
1843 /* wlconf doesn't work for virtual i/f */
1844 if (get_ifname_unit(name
, NULL
, &wlsubunit
) == 0 && wlsubunit
>= 0) {
1845 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name
);
1849 /* Check interface (fail silently for non-wl interfaces) */
1850 if ((ret
= wl_probe(name
)))
1853 /* because of ifdefs in wl driver, when we don't have AP capabilities we
1854 * can't use the same iovars to configure the wl.
1855 * so we use "wl_ap_build" to help us know how to configure the driver
1857 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
1860 foreach(cap
, caps
, next
) {
1861 if (!strcmp(cap
, "ap")) {
1867 /* Bring down the interface */
1868 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
1870 /* Disable all BSS Configs */
1871 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
1872 setbuf
.bsscfg_idx
= i
;
1875 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
1877 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
1878 /* fail quietly on a range error since the driver may
1879 * support fewer bsscfgs than we are prepared to configure
1881 if (bcmerr
== BCME_RANGE
)
1887 WL_IOCTL(name
, WLC_GET_UP
, &val
, sizeof(val
));
1891 ssid
.SSID
[0] = '\0';
1892 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
1894 /* Bring down the interface */
1895 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
1899 /* Nuke the WDS list */
1900 wlconf_wds_clear(name
);
1907 main(int argc
, char *argv
[])
1909 /* Check parameters and branch based on action */
1910 if (argc
== 3 && !strcmp(argv
[2], "up"))
1911 return wlconf(argv
[1]);
1912 else if (argc
== 3 && !strcmp(argv
[2], "down"))
1913 return wlconf_down(argv
[1]);
1915 fprintf(stderr
, "Usage: wlconf <ifname> up|down\n");