2 * Wireless Network Adapter Configuration Utility
4 * Copyright 2007, 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
)
532 #error "sleep_ms() not defined for this OS!!!"
533 #endif /* defined(linux) */
536 * The following condition(s) must be met when Auto Channel Selection
538 * - the I/F is up (change radio channel requires it is up?)
539 * - the AP must not be associated (setting SSID to empty should
540 * make sure it for us)
543 wlconf_auto_channel(char *name
)
546 wl_uint32_list_t request
;
551 /* query the phy type */
552 WL_GETINT(name
, WLC_GET_PHYTYPE
, &phytype
);
554 request
.count
= 0; /* let the ioctl decide */
555 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
557 sleep_ms(phytype
== PHY_TYPE_A
? 1000 : 750);
558 for (i
= 0; i
< 100; i
++) {
559 WL_GETINT(name
, WLC_GET_CHANNEL_SEL
, &chosen
);
565 WLCONF_DBG("interface %s: channel selected %d\n", name
, chosen
);
570 wlconf_auto_chanspec(char *name
)
572 chanspec_t chosen
= 0;
573 wl_uint32_list_t request
;
578 /* query the band type */
579 WL_GETINT(name
, WLC_GET_BAND
, &bandtype
);
581 request
.count
= 0; /* let the ioctl decide */
582 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
585 for (i
= 0; i
< 100; i
++) {
586 WL_IOVAR_GETINT(name
, "apcschspec", (void *)&chosen
);
592 WLCONF_DBG("interface %s: chanspec selected %04x\n", name
, chosen
);
596 /* PHY type/BAND conversion */
597 #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
598 /* PHY type conversion */
599 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
600 (phy) == PHY_TYPE_B ? "b" : \
601 (phy) == PHY_TYPE_LP ? "l" : \
602 (phy) == PHY_TYPE_G ? "g" : "n")
603 #define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
604 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \
605 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \
606 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N)
608 #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */
611 int idx
; /* bsscfg index */
612 char ifname
[PREFIX_LEN
]; /* OS name of interface (debug only) */
613 char prefix
[PREFIX_LEN
]; /* prefix for nvram params (eg. "wl0.1_") */
618 struct bsscfg_info bsscfgs
[WL_MAXBSSCFG
];
622 wlconf_get_bsscfgs(char* ifname
, char* prefix
)
628 struct bsscfg_list
*bclist
;
629 struct bsscfg_info
*bsscfg
;
631 bclist
= (struct bsscfg_list
*)malloc(sizeof(struct bsscfg_list
));
634 memset(bclist
, 0, sizeof(struct bsscfg_list
));
636 /* Set up Primary BSS Config information */
637 bsscfg
= &bclist
->bsscfgs
[0];
639 strncpy(bsscfg
->ifname
, ifname
, PREFIX_LEN
-1);
640 strcpy(bsscfg
->prefix
, prefix
);
643 /* additional virtual BSS Configs from wlX_vifs */
644 foreach(var
, nvram_safe_get(strcat_r(prefix
, "vifs", tmp
)), next
) {
645 if (bclist
->count
== WL_MAXBSSCFG
) {
646 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
648 "while configuring interface \"%s\"\n",
649 ifname
, WL_MAXBSSCFG
, strcat_r(prefix
, "vifs", tmp
), var
);
652 bsscfg
= &bclist
->bsscfgs
[bclist
->count
];
653 if (get_ifname_unit(var
, NULL
, &bsscfg
->idx
) != 0) {
654 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
659 strncpy(bsscfg
->ifname
, var
, PREFIX_LEN
-1);
660 snprintf(bsscfg
->prefix
, PREFIX_LEN
, "%s_", bsscfg
->ifname
);
668 wlconf_security_options(char *name
, char *prefix
, int bsscfg_idx
, bool id_supp
)
677 * Need to check errors (card may have changed) and change to
678 * defaults since the new chip may not support the requested
679 * encryptions after the card has been changed.
681 if (wlconf_set_wsec(name
, prefix
, bsscfg_idx
)) {
682 /* change nvram only, code below will pass them on */
683 wlconf_restore_var(prefix
, "auth_mode");
684 wlconf_restore_var(prefix
, "auth");
685 /* reset wep to default */
686 wlconf_restore_var(prefix
, "crypto");
687 wlconf_restore_var(prefix
, "wep");
688 wlconf_set_wsec(name
, prefix
, bsscfg_idx
);
691 val
= wlconf_akm_options(prefix
);
692 /* enable in-driver wpa supplicant? */
693 if (id_supp
&& (CHECK_PSK(val
))) {
697 if (((key
= nvram_get(strcat_r(prefix
, "wpa_psk", tmp
))) != NULL
) &&
698 (strlen(key
) < WSEC_MAX_PSK_LEN
)) {
699 psk
.key_len
= (ushort
) strlen(key
);
700 psk
.flags
= WSEC_PASSPHRASE
;
701 strcpy((char *)psk
.key
, key
);
702 WL_IOCTL(name
, WLC_SET_WSEC_PMK
, &psk
, sizeof(psk
));
704 wl_iovar_setint(name
, "sup_wpa", 1);
706 WL_BSSIOVAR_SETINT(name
, "wpa_auth", bsscfg_idx
, val
);
708 /* EAP Restrict if we have an AKM or radius authentication */
709 val
= ((val
!= 0) || (nvram_match(strcat_r(prefix
, "auth_mode", tmp
), "radius")));
710 WL_BSSIOVAR_SETINT(name
, "eap_restrict", bsscfg_idx
, val
);
713 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled")) {
714 for (i
= 1; i
<= DOT11_MAX_DEFAULT_KEYS
; i
++)
715 wlconf_set_wep_key(name
, prefix
, bsscfg_idx
, i
);
718 /* Set 802.11 authentication mode - open/shared */
719 val
= atoi(nvram_safe_get(strcat_r(prefix
, "auth", tmp
)));
720 WL_BSSIOVAR_SETINT(name
, "auth", bsscfg_idx
, val
);
724 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled
725 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
726 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off,
727 * afterburner is enabled/disabled based on the nvram settings.
729 * WME/WMM is also set in this procedure as it depends on N and afterburner.
730 * N ==> WMM is on by default
731 * N (or ampdu) ==> afterburner is off
732 * WMM ==> afterburner is off
734 * Returns whether afterburner is on in the system.
737 wlconf_aburn_ampdu_amsdu_set(char *name
, char prefix
[PREFIX_LEN
], int nmode
, int btc_mode
)
739 bool ampdu_valid_option
= FALSE
;
740 bool amsdu_valid_option
= FALSE
;
741 bool aburn_valid_option
= FALSE
;
742 int val
, aburn_option_val
= OFF
, ampdu_option_val
= OFF
, amsdu_option_val
= OFF
;
743 int wme_option_val
= ON
; /* On by default */
744 char tmp
[100], var
[80], *next
, *wme_val
;
745 char buf
[WLC_IOCTL_SMLEN
];
748 /* First, clear WMM and afterburner settings to avoid conflicts */
749 WL_IOVAR_SETINT(name
, "wme", OFF
);
750 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
752 /* Get WME setting from NVRAM if present */
753 wme_val
= nvram_get(strcat_r(prefix
, "wme", tmp
));
754 if (wme_val
&& !strcmp(wme_val
, "off")) {
755 wme_option_val
= OFF
;
758 /* Set options based on capability */
759 wl_iovar_get(name
, "cap", (void *)tmp
, 100);
760 foreach(var
, tmp
, next
) {
761 char *nvram_str
= nvram_get(strcat_r(prefix
, var
, buf
));
766 if (!strcmp(nvram_str
, "on"))
768 else if (!strcmp(nvram_str
, "off"))
770 else if (!strcmp(nvram_str
, "auto"))
775 if (btc_mode
!= WL_BTC_PREMPT
&& strncmp(var
, "afterburner", sizeof(var
)) == 0) {
776 aburn_valid_option
= TRUE
;
777 aburn_option_val
= val
;
780 if (strncmp(var
, "ampdu", sizeof(var
)) == 0) {
781 ampdu_valid_option
= TRUE
;
782 ampdu_option_val
= val
;
785 if (strncmp(var
, "amsdu", sizeof(var
)) == 0) {
786 amsdu_valid_option
= TRUE
;
787 amsdu_option_val
= val
;
791 if (nmode
!= OFF
) { /* N-mode is ON/AUTO */
793 if (aburn_valid_option
) { /* Turn off afterburner in N-mode */
794 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
797 if (ampdu_valid_option
) {
798 if (ampdu_option_val
!= OFF
) {
799 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
800 WL_IOVAR_SETINT(name
, "ampdu", ampdu_option_val
);
802 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
806 if (amsdu_valid_option
) {
807 if (amsdu_option_val
!= OFF
) { /* AMPDU (above) has priority over AMSDU */
808 if (ampdu_option_val
== OFF
) {
809 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
810 WL_IOVAR_SETINT(name
, "amsdu", amsdu_option_val
);
813 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
816 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
817 * if WME is off, set the afterburner based on the configured nvram setting.
819 wl_iovar_setint(name
, "amsdu", OFF
);
820 wl_iovar_setint(name
, "ampdu", OFF
);
821 if (wme_option_val
!= OFF
) { /* Can't have afterburner with WMM */
822 if (aburn_valid_option
) {
823 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
825 } else if (aburn_valid_option
) { /* Okay, use NVRam setting for afterburner */
826 WL_IOVAR_SETINT(name
, "afterburner_override", aburn_option_val
);
830 if (wme_option_val
) {
831 WL_IOVAR_SETINT(name
, "wme", wme_option_val
);
832 wlconf_set_wme(name
, prefix
);
835 return wme_option_val
;
838 #define VIFNAME_LEN 16
840 /* configure the specified wireless interface */
844 int restore_defaults
, val
, unit
, phytype
, bandtype
, gmode
= 0, ret
= 0;
846 int error_bg
, error_a
;
847 struct bsscfg_list
*bclist
= NULL
;
848 struct bsscfg_info
*bsscfg
;
849 char tmp
[100], prefix
[PREFIX_LEN
];
850 char var
[80], *next
, phy
[] = "a", *str
, *addr
= NULL
;
851 /* Pay attention to buffer length requirements when using this */
852 char buf
[WLC_IOCTL_SMLEN
];
856 struct maclist
*maclist
;
857 struct ether_addr
*ea
;
862 int ap
, apsta
, wds
, sta
= 0, wet
= 0, mac_spoof
= 0;
863 char country_code
[4];
864 int nas_will_run
= 0;
873 int wl_ap_build
= 0; /* wl compiled with AP capabilities */
874 char cap
[WLC_IOCTL_SMLEN
];
875 char caps
[WLC_IOCTL_SMLEN
];
878 uint nbw
= WL_CHANSPEC_BW_20
;
879 int nmode
= OFF
; /* 802.11n support */
880 char vif_addr
[WLC_IOCTL_SMLEN
];
884 bool ure_enab
= FALSE
;
885 bool radar_enab
= FALSE
;
887 /* wlconf doesn't work for virtual i/f, so if we are given a
888 * virtual i/f return 0 if that interface is in it's parent's "vifs"
889 * list otherwise return -1
891 if (get_ifname_unit(name
, &wlunit
, &wlsubunit
) == 0)
895 /* we have been given a virtual i/f,
896 * is it in it's parent i/f's virtual i/f list?
898 sprintf(tmp
, "wl%d_vifs", wlunit
);
900 if (strstr(nvram_safe_get(tmp
), name
) == NULL
)
901 return -1; /* config error */
912 memset(tmp
, 0, sizeof(tmp
));
914 /* because of ifdefs in wl driver, when we don't have AP capabilities we
915 * can't use the same iovars to configure the wl.
916 * so we use "wl_ap_build" to help us know how to configure the driver
918 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
921 foreach(cap
, caps
, next
) {
922 if (!strcmp(cap
, "ap")) {
925 else if (!strcmp(cap
, "mbss16"))
927 else if (!strcmp(cap
, "mbss4"))
931 /* Check interface (fail silently for non-wl interfaces) */
932 if ((ret
= wl_probe(name
)))
935 /* Get MAC address */
936 (void) wl_hwaddr(name
, (uchar
*)buf
);
937 memcpy(vif_addr
, buf
, ETHER_ADDR_LEN
);
940 WL_IOCTL(name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
));
941 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
943 /* Restore defaults if per-interface parameters do not exist */
944 restore_defaults
= !nvram_get(strcat_r(prefix
, "ifname", tmp
));
945 wlconf_validate_all(prefix
, restore_defaults
);
946 nvram_set(strcat_r(prefix
, "ifname", tmp
), name
);
947 nvram_set(strcat_r(prefix
, "hwaddr", tmp
), ether_etoa((uchar
*)buf
, eaddr
));
948 snprintf(buf
, sizeof(buf
), "%d", unit
);
949 nvram_set(strcat_r(prefix
, "unit", tmp
), buf
);
952 /* Bring the interface down */
953 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
955 /* Disable all BSS Configs */
956 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
957 struct {int bsscfg_idx
; int enable
;} setbuf
;
958 setbuf
.bsscfg_idx
= i
;
961 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
963 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
964 /* fail quietly on a range error since the driver may
965 * support fewer bsscfgs than we are prepared to configure
967 if (bcmerr
== BCME_RANGE
)
971 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
972 " (down) failed, ret = %d, bcmerr = %d\n",
973 __LINE__
, name
, i
, ret
, bcmerr
);
976 /* Get the list of BSS Configs */
977 bclist
= wlconf_get_bsscfgs(name
, prefix
);
978 if (bclist
== NULL
) {
984 /* create a wlX.Y_ifname nvram setting */
985 for (i
= 1; i
< bclist
->count
; i
++) {
986 bsscfg
= &bclist
->bsscfgs
[i
];
988 strcpy(var
, bsscfg
->ifname
);
990 nvram_set(strcat_r(bsscfg
->prefix
, "ifname", tmp
), var
);
993 /* If ure_disable is not present or is 1, ure is not enabled;
994 * that is, if it is present and 0, ure is enabled.
996 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
1000 /* Enable MBSS mode if appropriate */
1002 WL_IOVAR_SETINT(name
, "mbss", (bclist
->count
> 1));
1006 * Set SSID for each BSS Config
1008 for (i
= 0; i
< bclist
->count
; i
++) {
1009 bsscfg
= &bclist
->bsscfgs
[i
];
1010 strcat_r(bsscfg
->prefix
, "ssid", tmp
);
1011 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
1012 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
1013 ssid
.SSID_len
= sizeof(ssid
.SSID
);
1014 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
), ssid
.SSID_len
);
1015 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1016 "with SSID \"%s\"\n", name
, bsscfg
->idx
,
1017 bsscfg
->ifname
, nvram_safe_get(tmp
));
1018 WL_BSSIOVAR_SET(name
, "ssid", bsscfg
->idx
, &ssid
,
1023 /* Create addresses for VIFs */
1025 /* set local bit for our MBSS vif base */
1026 ETHER_SET_LOCALADDR(vif_addr
);
1028 /* construct and set other wlX.Y_hwaddr */
1029 for (i
= 1; i
< max_no_vifs
; i
++) {
1030 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr", unit
, i
);
1031 addr
= nvram_safe_get(tmp
);
1032 if (!strcmp(addr
, "")) {
1033 vif_addr
[5] = (vif_addr
[5] & ~(max_no_vifs
-1))
1034 | ((max_no_vifs
-1) & (vif_addr
[5]+1));
1036 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
,
1040 /* The addresses are available in NVRAM, so set them */
1041 for (i
= 1; i
< max_no_vifs
; i
++) {
1042 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_bss_enabled",
1044 if (!strcmp(nvram_safe_get(tmp
), "1")) {
1045 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr",
1047 ether_atoe(nvram_safe_get(tmp
), eaddr
);
1048 WL_BSSIOVAR_SET(name
, "cur_etheraddr", i
,
1049 eaddr
, ETHER_ADDR_LEN
);
1052 } else { /* URE is enabled */
1053 /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
1054 snprintf(tmp
, sizeof(tmp
), "wl%d.1_hwaddr", unit
);
1055 WL_BSSIOVAR_SET(name
, "cur_etheraddr", 1, vif_addr
,
1057 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
, eaddr
));
1060 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1061 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
1062 ap
= (!strcmp(str
, "") || !strcmp(str
, "ap"));
1063 apsta
= (!strcmp(str
, "apsta") ||
1064 ((!strcmp(str
, "sta") || !strcmp(str
, "wet")) &&
1065 bclist
->count
> 1));
1066 sta
= (!strcmp(str
, "sta") && bclist
->count
== 1);
1067 wds
= !strcmp(str
, "wds");
1068 wet
= !strcmp(str
, "wet");
1069 mac_spoof
= !strcmp(str
, "mac_spoof");
1072 val
= (ap
|| apsta
|| wds
) ? 1 : 0;
1073 WL_IOCTL(name
, WLC_SET_AP
, &val
, sizeof(val
));
1075 WL_IOVAR_SETINT(name
, "apsta", apsta
);
1079 WL_IOCTL(name
, WLC_SET_WET
, &wet
, sizeof(wet
));
1083 WL_IOVAR_SETINT(name
, "mac_spoof", 1);
1086 /* For STA configurations, configure association retry time.
1087 * Use specified time (capped), or mode-specific defaults.
1089 if (sta
|| wet
|| apsta
) {
1090 char *retry_time
= nvram_safe_get(strcat_r(prefix
, "sta_retry_time", tmp
));
1091 val
= atoi(retry_time
);
1092 WL_IOVAR_SETINT(name
, "sta_retry_time", val
);
1095 /* Retain remaining WET effects only if not APSTA */
1098 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1101 val
= atoi(nvram_safe_get(strcat_r(prefix
, "infra", tmp
)));
1102 WL_IOCTL(name
, WLC_SET_INFRA
, &val
, sizeof(val
));
1104 /* Set The AP MAX Associations Limit */
1106 max_assoc
= val
= atoi(nvram_safe_get(strcat_r(prefix
, "maxassoc", tmp
)));
1108 WL_IOVAR_SETINT(name
, "maxassoc", val
);
1109 } else { /* Get value from driver if not in nvram */
1110 WL_IOVAR_GETINT(name
, "maxassoc", &max_assoc
);
1114 for (i
= 0; i
< bclist
->count
; i
++) {
1116 bsscfg
= &bclist
->bsscfgs
[i
];
1119 /* XXXMBSS: The note about setting preauth now does not seem right.
1120 * NAS brings the BSS up if it runs, so setting the preauth value
1121 * will make it in the bcn/prb. If that is right, we can move this
1122 * chunk out of wlconf.
1125 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1126 * if we do it in the NAS we need to bring down the interface and up to make
1127 * it affect in the beacons
1129 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1131 preauth
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "preauth", tmp
));
1132 if (strlen (preauth
) != 0) {
1133 set_preauth
= atoi(preauth
);
1135 wlconf_set_preauth(name
, bsscfg
->idx
, set_preauth
);
1137 #endif /* BCMWPA2 */
1139 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1141 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1142 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "bss_maxassoc", tmp
)));
1144 WL_BSSIOVAR_SETINT(name
, "bss_maxassoc", bsscfg
->idx
, val
);
1145 } else if (max_assoc
> 0) { /* Set maxassoc same as global if not set */
1146 snprintf(var
, sizeof(var
), "%d", max_assoc
);
1147 nvram_set(tmp
, var
);
1151 /* Set network type */
1152 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "closed", tmp
)));
1153 WL_BSSIOVAR_SETINT(name
, "closednet", bsscfg
->idx
, val
);
1155 /* Set the ap isolate mode */
1156 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "ap_isolate", tmp
)));
1157 WL_BSSIOVAR_SETINT(name
, "ap_isolate", bsscfg
->idx
, val
);
1160 /* Set up the country code */
1161 (void) strcat_r(prefix
, "country_code", tmp
);
1162 country
= nvram_get(tmp
);
1163 if (country
&& country
[0] != '\0') {
1164 strncpy(country_code
, country
, sizeof(country_code
));
1165 WL_IOCTL(name
, WLC_SET_COUNTRY
, country_code
, strlen(country_code
)+1);
1167 /* Get the default country code if undefined */
1168 WL_IOCTL(name
, WLC_GET_COUNTRY
, country_code
, sizeof(country_code
));
1170 /* Add the new NVRAM variable */
1171 nvram_set("wl_country_code", country_code
);
1172 (void) strcat_r(prefix
, "country_code", tmp
);
1173 nvram_set(tmp
, country_code
);
1176 /* Change LED Duty Cycle */
1177 leddc
= (uint32
)strtoul(nvram_safe_get(strcat_r(prefix
, "leddc", tmp
)), NULL
, 16);
1179 WL_IOVAR_SETINT(name
, "leddc", leddc
);
1181 /* Enable or disable the radio */
1182 val
= nvram_match(strcat_r(prefix
, "radio", tmp
), "0");
1183 val
+= WL_RADIO_SW_DISABLE
<< 16;
1184 WL_IOCTL(name
, WLC_SET_RADIO
, &val
, sizeof(val
));
1186 /* Get supported phy types */
1187 WL_IOCTL(name
, WLC_GET_PHYLIST
, var
, sizeof(var
));
1188 nvram_set(strcat_r(prefix
, "phytypes", tmp
), var
);
1191 *(next
= buf
) = '\0';
1192 for (i
= 0; i
< strlen(var
); i
++) {
1193 /* Switch to band */
1195 val
= WLCONF_STR2PHYTYPE(phy
);
1196 if (val
== PHY_TYPE_N
) {
1197 WL_GETINT(name
, WLC_GET_BAND
, &val
);
1199 val
= WLCONF_PHYTYPE2BAND(val
);
1200 WL_IOCTL(name
, WLC_SET_BAND
, &val
, sizeof(val
));
1201 /* Get radio ID on this band */
1202 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1203 next
+= sprintf(next
, "%sBCM%X", i
? " " : "",
1204 (rev
.radiorev
& IDCODE_ID_MASK
) >> IDCODE_ID_SHIFT
);
1206 nvram_set(strcat_r(prefix
, "radioids", tmp
), buf
);
1209 str
= nvram_get(strcat_r(prefix
, "phytype", tmp
));
1210 val
= WLCONF_STR2PHYTYPE(str
);
1211 /* For NPHY use band value from NVRAM */
1212 if (val
== PHY_TYPE_N
) {
1213 str
= nvram_get(strcat_r(prefix
, "nband", tmp
));
1217 WL_GETINT(name
, WLC_GET_BAND
, &val
);
1220 val
= WLCONF_PHYTYPE2BAND(val
);
1222 WL_SETINT(name
, WLC_SET_BAND
, val
);
1224 /* Check errors (card may have changed) */
1226 /* default band to the first band in band list */
1228 val
= WLCONF_STR2PHYTYPE(phy
);
1229 val
= WLCONF_PHYTYPE2BAND(val
);
1230 WL_SETINT(name
, WLC_SET_BAND
, val
);
1233 /* Store the resolved bandtype */
1236 /* Get current core revision */
1237 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1238 snprintf(buf
, sizeof(buf
), "%d", rev
.corerev
);
1239 nvram_set(strcat_r(prefix
, "corerev", tmp
), buf
);
1241 /* Get current phy type */
1242 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
1243 snprintf(buf
, sizeof(buf
), "%s", WLCONF_PHYTYPE2STR(phytype
));
1244 nvram_set(strcat_r(prefix
, "phytype", tmp
), buf
);
1246 /* Setup regulatory mode */
1247 strcat_r(prefix
, "reg_mode", tmp
);
1248 if (nvram_match(tmp
, "off")) {
1250 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1251 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1252 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1253 } else if (nvram_match(tmp
, "h")) {
1255 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1257 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1259 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1261 /* Set the CAC parameters */
1262 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dfs_preism", tmp
)));
1263 wl_iovar_setint(name
, "dfs_preism", val
);
1264 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dfs_postism", tmp
)));
1265 wl_iovar_setint(name
, "dfs_postism", val
);
1266 val
= atoi(nvram_safe_get(strcat_r(prefix
, "tpc_db", tmp
)));
1267 WL_IOCTL(name
, WLC_SEND_PWR_CONSTRAINT
, &val
, sizeof(val
));
1269 } else if (nvram_match(tmp
, "d")) {
1271 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1272 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1274 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1277 /* set bandwidth capability for nphy and calculate nbw */
1278 if (phytype
== PHY_TYPE_N
) {
1279 /* Get the user nmode setting now */
1280 nmode
= AUTO
; /* enable by default for NPHY */
1282 strcat_r(prefix
, "nmode", tmp
);
1283 if (nvram_match(tmp
, "0"))
1286 val
= (nmode
!= OFF
) ? atoi(nvram_safe_get(strcat_r(prefix
, "nbw_cap", tmp
))) :
1289 WL_IOVAR_SETINT(name
, "nmode", (uint32
)nmode
);
1290 WL_IOVAR_SETINT(name
, "mimo_bw_cap", val
);
1292 if (((bandtype
== WLC_BAND_2G
) && (val
== WLC_N_BW_40ALL
)) ||
1293 ((bandtype
== WLC_BAND_5G
) &&
1294 (val
== WLC_N_BW_40ALL
|| val
== WLC_N_BW_20IN2G_40IN5G
)))
1295 nbw
= WL_CHANSPEC_BW_40
;
1297 nbw
= WL_CHANSPEC_BW_20
;
1300 /* Set channel before setting gmode or rateset */
1301 /* Manual Channel Selection - when channel # is not 0 */
1302 val
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
)));
1303 if (val
&& phytype
!= PHY_TYPE_N
) {
1304 WL_SETINT(name
, WLC_SET_CHANNEL
, val
);
1306 /* Use current channel (card may have changed) */
1307 WL_IOCTL(name
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
1308 snprintf(buf
, sizeof(buf
), "%d", ci
.target_channel
);
1309 nvram_set(strcat_r(prefix
, "channel", tmp
), buf
);
1311 } else if (val
&& phytype
== PHY_TYPE_N
) {
1312 chanspec_t chanspec
= 0;
1314 uint nctrlsb
= WL_CHANSPEC_CTL_SB_NONE
;
1318 /* Get Ctrl SB for 40MHz channel */
1319 if (nbw
== WL_CHANSPEC_BW_40
) {
1320 str
= nvram_safe_get(strcat_r(prefix
, "nctrlsb", tmp
));
1322 /* Adjust the channel to be center channel */
1323 if (!strcmp(str
, "lower")) {
1324 nctrlsb
= WL_CHANSPEC_CTL_SB_LOWER
;
1325 channel
= channel
+ 2;
1326 } else if (!strcmp(str
, "upper")) {
1327 nctrlsb
= WL_CHANSPEC_CTL_SB_UPPER
;
1328 channel
= channel
- 2;
1332 /* band | BW | CTRL SB | Channel */
1333 chanspec
|= ((bandtype
<< WL_CHANSPEC_BAND_SHIFT
) |
1334 (nbw
| nctrlsb
| channel
));
1336 WL_IOVAR_SETINT(name
, "chanspec", (uint32
)chanspec
);
1339 /* Set up number of Tx and Rx streams */
1340 if (phytype
== PHY_TYPE_N
) {
1344 wl_iovar_getint(name
, "txchain_cnt", &count
);
1345 /* update NVRAM with capabilities */
1346 snprintf(var
, sizeof(var
), "%d", count
);
1347 nvram_set(strcat_r(prefix
, "txchain_cnt", tmp
), var
);
1349 /* Verify that there is an NVRAM param for txstreams, if not create it and
1350 * set it to txchain_cnt
1352 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "txstreams", tmp
)));
1354 /* invalid - NVRAM needs to be fixed/initialized */
1355 nvram_set(strcat_r(prefix
, "txstreams", tmp
), var
);
1358 /* Apply user configured txstreams, use 1 if user disabled nmode */
1361 WL_IOVAR_SETINT(name
, "txstreams", streams
);
1363 wl_iovar_getint(name
, "rxchain_cnt", &count
);
1364 /* update NVRAM with capabilities */
1365 snprintf(var
, sizeof(var
), "%d", count
);
1366 nvram_set(strcat_r(prefix
, "rxchain_cnt", tmp
), var
);
1368 /* Verify that there is an NVRAM param for rxstreams, if not create it and
1369 * set it to txchain_cnt
1371 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "rxstreams", tmp
)));
1373 /* invalid - NVRAM needs to be fixed/initialized */
1374 nvram_set(strcat_r(prefix
, "rxstreams", tmp
), var
);
1378 /* Apply user configured rxstreams, use 1 if user disabled nmode */
1381 WL_IOVAR_SETINT(name
, "rxstreams", streams
);
1384 /* Reset to hardware rateset (band may have changed) */
1385 WL_IOCTL(name
, WLC_GET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1386 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1389 if (bandtype
== WLC_BAND_2G
) {
1390 int override
= WLC_G_PROTECTION_OFF
;
1391 int control
= WLC_G_PROTECTION_CTL_OFF
;
1394 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", tmp
)));
1395 WL_IOCTL(name
, WLC_SET_GMODE
, &gmode
, sizeof(gmode
));
1397 /* Set gmode protection override and control algorithm */
1398 strcat_r(prefix
, "gmode_protection", tmp
);
1399 if (nvram_match(tmp
, "auto")) {
1400 override
= WLC_G_PROTECTION_AUTO
;
1401 control
= WLC_G_PROTECTION_CTL_OVERLAP
;
1403 WL_IOCTL(name
, WLC_SET_GMODE_PROTECTION_OVERRIDE
, &override
, sizeof(override
));
1404 WL_IOCTL(name
, WLC_SET_GMODE_PROTECTION_CONTROL
, &control
, sizeof(control
));
1407 /* Set nmode_protection */
1408 if (phytype
== PHY_TYPE_N
) {
1409 int override
= WLC_PROTECTION_OFF
;
1410 int control
= WLC_PROTECTION_CTL_OFF
;
1412 /* Set n protection override and control algorithm */
1413 strcat_r(prefix
, "nmode_protection", tmp
);
1415 if (nvram_match(tmp
, "auto")) {
1416 override
= WLC_PROTECTION_AUTO
;
1417 control
= WLC_PROTECTION_CTL_OVERLAP
;
1420 WL_IOVAR_SETINT(name
, "nmode_protection_override",
1422 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
1425 /* Set 802.11n required */
1427 uint32 nreqd
= OFF
; /* default */
1429 strcat_r(prefix
, "nreqd", tmp
);
1431 if (nvram_match(tmp
, "1"))
1434 WL_IOVAR_SETINT(name
, "nreqd", nreqd
);
1437 /* Set vlan_prio_mode */
1439 uint32 mode
= OFF
; /* default */
1441 strcat_r(prefix
, "vlan_prio_mode", tmp
);
1443 if (nvram_match(tmp
, "on"))
1446 WL_IOVAR_SETINT(name
, "vlan_mode", mode
);
1449 /* Get bluetooth coexistance(BTC) mode */
1450 btc_mode
= atoi(nvram_safe_get(strcat_r(prefix
, "btc_mode", tmp
)));
1452 /* Set the afterburner, AMPDU and AMSDU options based on the N-mode */
1453 wme_global
= wlconf_aburn_ampdu_amsdu_set(name
, prefix
, nmode
, btc_mode
);
1455 /* Now that wme_global is known, check per-BSS disable settings */
1456 for (i
= 0; i
< bclist
->count
; i
++) {
1458 bsscfg
= &bclist
->bsscfgs
[i
];
1460 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1462 /* For each BSS, check WME; make sure wme is set properly for this interface */
1463 strcat_r(subprefix
, "wme", tmp
);
1464 nvram_set(tmp
, wme_global
? "on" : "off");
1466 str
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "wme_bss_disable", tmp
));
1467 val
= (str
[0] == '1') ? 1 : 0;
1468 WL_BSSIOVAR_SETINT(name
, "wme_bss_disable", bsscfg
->idx
, val
);
1472 /* Get current rateset (gmode may have changed) */
1473 WL_IOCTL(name
, WLC_GET_CURR_RATESET
, &rs
, sizeof(wl_rateset_t
));
1475 strcat_r(prefix
, "rateset", tmp
);
1476 if (nvram_match(tmp
, "all")) {
1477 /* Make all rates basic */
1478 for (i
= 0; i
< rs
.count
; i
++)
1479 rs
.rates
[i
] |= 0x80;
1480 } else if (nvram_match(tmp
, "12")) {
1481 /* Make 1 and 2 basic */
1482 for (i
= 0; i
< rs
.count
; i
++) {
1483 if ((rs
.rates
[i
] & 0x7f) == 2 || (rs
.rates
[i
] & 0x7f) == 4)
1484 rs
.rates
[i
] |= 0x80;
1486 rs
.rates
[i
] &= ~0x80;
1491 if (!wl_iovar_setint(name
, "btc_mode", btc_mode
)) {
1492 if (btc_mode
== WL_BTC_PREMPT
) {
1493 wl_rateset_t rs_tmp
= rs
;
1494 /* remove 1Mbps and 2 Mbps from rateset */
1495 for (i
= 0, rs
.count
= 0; i
< rs_tmp
.count
; i
++) {
1496 if ((rs_tmp
.rates
[i
] & 0x7f) == 2 || (rs_tmp
.rates
[i
] & 0x7f) == 4)
1498 rs
.rates
[rs
.count
++] = rs_tmp
.rates
[i
];
1504 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1506 /* Allow short preamble override for b cards */
1507 if (phytype
== PHY_TYPE_B
||
1508 (phytype
== PHY_TYPE_G
&& (gmode
== GMODE_LEGACY_B
|| gmode
== GMODE_AUTO
))) {
1509 strcat_r(prefix
, "plcphdr", tmp
);
1510 if (nvram_match(tmp
, "long"))
1511 val
= WLC_PLCP_AUTO
;
1513 val
= WLC_PLCP_SHORT
;
1514 WL_IOCTL(name
, WLC_SET_PLCPHDR
, &val
, sizeof(val
));
1517 /* Set rate in 500 Kbps units */
1518 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rate", tmp
))) / 500000;
1520 /* Convert Auto mcsidx to Auto rate */
1521 if (phytype
== PHY_TYPE_N
) {
1522 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
1524 /* -1 mcsidx used to designate AUTO rate */
1529 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1530 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
1531 /* Must b/g band. Set to 5.5Mbps */
1534 /* it is band-blind. try both band */
1535 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
1536 error_a
= wl_iovar_setint(name
, "a_rate", val
);
1538 if (error_bg
&& error_a
) {
1539 /* both failed. Try default rate (card may have changed) */
1542 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
1543 error_a
= wl_iovar_setint(name
, "a_rate", val
);
1545 snprintf(buf
, sizeof(buf
), "%d", val
);
1546 nvram_set(strcat_r(prefix
, "rate", tmp
), buf
);
1549 /* check if nrate needs to be applied */
1552 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
1553 bool ismcs
= (mcsidx
>= 0);
1555 /* mcsidx of 32 is valid only for 40 Mhz */
1556 if (mcsidx
== 32 && nbw
== WL_CHANSPEC_BW_20
) {
1559 nvram_set(strcat_r(prefix
, "nmcsidx", tmp
), "-1");
1562 /* Use nrate iovar only for MCS rate. */
1564 nrate
|= NRATE_MCS_INUSE
;
1565 nrate
|= mcsidx
& NRATE_RATE_MASK
;
1567 WL_IOVAR_SETINT(name
, "nrate", nrate
);
1571 /* Set multicast rate in 500 Kbps units */
1572 val
= atoi(nvram_safe_get(strcat_r(prefix
, "mrate", tmp
))) / 500000;
1573 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1574 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
1575 /* Must b/g band. Set to 5.5Mbps */
1578 /* it is band-blind. try both band */
1579 error_bg
= wl_iovar_setint(name
, "bg_mrate", val
);
1580 error_a
= wl_iovar_setint(name
, "a_mrate", val
);
1582 if (error_bg
&& error_a
) {
1583 /* Try default rate (card may have changed) */
1586 wl_iovar_setint(name
, "bg_mrate", val
);
1587 wl_iovar_setint(name
, "a_mrate", val
);
1589 snprintf(buf
, sizeof(buf
), "%d", val
);
1590 nvram_set(strcat_r(prefix
, "mrate", tmp
), buf
);
1593 /* Set fragmentation threshold */
1594 val
= atoi(nvram_safe_get(strcat_r(prefix
, "frag", tmp
)));
1595 wl_iovar_setint(name
, "fragthresh", val
);
1597 /* Set RTS threshold */
1598 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rts", tmp
)));
1599 wl_iovar_setint(name
, "rtsthresh", val
);
1601 /* Set DTIM period */
1602 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dtim", tmp
)));
1603 WL_IOCTL(name
, WLC_SET_DTIMPRD
, &val
, sizeof(val
));
1605 /* Set beacon period */
1606 val
= atoi(nvram_safe_get(strcat_r(prefix
, "bcn", tmp
)));
1607 WL_IOCTL(name
, WLC_SET_BCNPRD
, &val
, sizeof(val
));
1609 /* Set framebursting mode */
1610 if (btc_mode
== WL_BTC_PREMPT
)
1613 val
= nvram_match(strcat_r(prefix
, "frameburst", tmp
), "on");
1614 WL_IOCTL(name
, WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
1616 /* Set RIFS mode based on framebursting */
1617 if (phytype
== PHY_TYPE_N
) {
1618 char *nvram_str
= nvram_safe_get(strcat_r(prefix
, "rifs", tmp
));
1619 if (!strcmp(nvram_str
, "on"))
1620 wl_iovar_setint(name
, "rifs", ON
);
1621 else if (!strcmp(nvram_str
, "off"))
1622 wl_iovar_setint(name
, "rifs", OFF
);
1625 /* Override BA mode only if set to on/off */
1626 ba
= nvram_safe_get(strcat_r(prefix
, "ba", tmp
));
1627 if (!strcmp(ba
, "on"))
1628 wl_iovar_setint(name
, "ba", ON
);
1629 else if (!strcmp(ba
, "off"))
1630 wl_iovar_setint(name
, "ba", OFF
);
1632 if (phytype
== PHY_TYPE_N
) {
1633 val
= AVG_DMA_XFER_RATE
;
1634 wl_iovar_set(name
, "avg_dma_xfer_rate", &val
, sizeof(val
));
1637 /* Bring the interface back up */
1638 WL_IOCTL(name
, WLC_UP
, NULL
, 0);
1641 val
= atoi(nvram_safe_get(strcat_r(prefix
, "antdiv", tmp
)));
1642 WL_IOCTL(name
, WLC_SET_ANTDIV
, &val
, sizeof(val
));
1644 /* Set radar parameters if it is enabled */
1646 wlconf_set_radarthrs(name
, prefix
);
1649 /* Auto Channel Selection - when channel # is 0 in AP mode
1651 * The following condition(s) must be met in order for
1652 * Auto Channel Selection to work.
1653 * - the I/F must be up for the channel scan
1654 * - the AP must not be supporting a BSS (all BSS Configs must be disabled)
1657 if (!(val
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
))))) {
1658 if (phytype
== PHY_TYPE_N
) {
1659 chanspec_t chanspec
= wlconf_auto_chanspec(name
);
1661 WL_IOVAR_SETINT(name
, "chanspec", chanspec
);
1664 /* select a channel */
1665 val
= wlconf_auto_channel(name
);
1666 /* switch to the selected channel */
1668 WL_IOCTL(name
, WLC_SET_CHANNEL
, &val
, sizeof(val
));
1670 /* set the auto channel scan timer in the driver when in auto mode */
1671 val
= 15; /* 15 minutes for now */
1672 WL_IOCTL(name
, WLC_SET_CS_SCAN_TIMER
, &val
, sizeof(val
));
1675 /* reset the channel scan timer in the driver when not in auto mode */
1677 WL_IOCTL(name
, WLC_SET_CS_SCAN_TIMER
, &val
, sizeof(val
));
1681 /* Security settings for each BSS Configuration */
1682 for (i
= 0; i
< bclist
->count
; i
++) {
1683 bsscfg
= &bclist
->bsscfgs
[i
];
1684 wlconf_security_options(name
, bsscfg
->prefix
, bsscfg
->idx
, mac_spoof
);
1687 /* AP only config */
1688 if (ap
|| apsta
|| wds
) {
1689 /* Set lazy WDS mode */
1690 val
= atoi(nvram_safe_get(strcat_r(prefix
, "lazywds", tmp
)));
1691 WL_IOCTL(name
, WLC_SET_LAZYWDS
, &val
, sizeof(val
));
1693 /* Set the WDS list */
1694 maclist
= (struct maclist
*) buf
;
1697 foreach(var
, nvram_safe_get(strcat_r(prefix
, "wds", tmp
)), next
) {
1698 if (((char *)(ea
->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
1700 ether_atoe(var
, ea
->octet
);
1704 WL_IOCTL(name
, WLC_SET_WDSLIST
, buf
, sizeof(buf
));
1706 /* Set WDS link detection timeout */
1707 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wds_timeout", tmp
)));
1708 wl_iovar_setint(name
, "wdstimeout", val
);
1711 wl_iovar_setint(name
, "radio_init", 1);
1716 * Finally enable BSS Configs or Join BSS
1718 * AP: Enable BSS Config to bring AP up only when nas will not run
1719 * STA: Join the BSS regardless.
1721 for (i
= 0; i
< bclist
->count
; i
++) {
1722 struct {int bsscfg_idx
; int enable
;} setbuf
;
1723 char vifname
[VIFNAME_LEN
];
1724 char *name_ptr
= name
;
1726 setbuf
.bsscfg_idx
= bclist
->bsscfgs
[i
].idx
;
1729 bsscfg
= &bclist
->bsscfgs
[i
];
1730 if (nvram_match(strcat_r(bsscfg
->prefix
, "bss_enabled", tmp
), "1")) {
1734 /* Set the MAC list */
1735 maclist
= (struct maclist
*)buf
;
1737 if (!nvram_match(strcat_r(bsscfg
->prefix
, "macmode", tmp
), "disabled")) {
1739 foreach(var
, nvram_safe_get(strcat_r(bsscfg
->prefix
, "maclist", tmp
)),
1741 if (((char *)((&ea
[1])->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
1743 if (ether_atoe(var
, ea
->octet
)) {
1750 if (setbuf
.bsscfg_idx
== 0) {
1752 } else { /* Non-primary BSS; changes name syntax */
1753 char tmp
[VIFNAME_LEN
];
1756 /* Remove trailing _ if present */
1757 memset(tmp
, 0, sizeof(tmp
));
1758 strncpy(tmp
, bsscfg
->prefix
, VIFNAME_LEN
- 1);
1759 if (((len
= strlen(tmp
)) > 0) && (tmp
[len
- 1] == '_')) {
1762 nvifname_to_osifname(tmp
, vifname
, VIFNAME_LEN
);
1766 WL_IOCTL(name_ptr
, WLC_SET_MACLIST
, buf
, sizeof(buf
));
1768 /* Set macmode for each VIF */
1769 (void) strcat_r(bsscfg
->prefix
, "macmode", tmp
);
1771 if (nvram_match(tmp
, "deny"))
1772 val
= WLC_MACMODE_DENY
;
1773 else if (nvram_match(tmp
, "allow"))
1774 val
= WLC_MACMODE_ALLOW
;
1776 val
= WLC_MACMODE_DISABLED
;
1778 WL_IOCTL(name_ptr
, WLC_SET_MACMODE
, &val
, sizeof(val
));
1780 /* NAS runs if we have an AKM or radius authentication */
1781 nas_will_run
= wlconf_akm_options(bclist
->bsscfgs
[i
].prefix
) ||
1782 nvram_match(strcat_r(bclist
->bsscfgs
[i
].prefix
, "auth_mode", tmp
),
1785 if (((ap
|| apsta
) && !nas_will_run
) || sta
|| wet
) {
1786 for (ii
= 0; ii
< MAX_BSS_UP_RETRIES
; ii
++) {
1788 WL_IOVAR_SET(name
, "bss", &setbuf
, sizeof(setbuf
));
1791 strcat_r(prefix
, "ssid", tmp
);
1792 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
1793 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
1794 ssid
.SSID_len
= sizeof(ssid
.SSID
);
1795 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
),
1797 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
1799 if (apsta
&& (ret
!= 0))
1816 wlconf_down(char *name
)
1822 struct {int bsscfg_idx
; int enable
;} setbuf
;
1823 int wl_ap_build
= 0; /* 1 = wl compiled with AP capabilities */
1824 char cap
[WLC_IOCTL_SMLEN
];
1825 char caps
[WLC_IOCTL_SMLEN
];
1829 /* wlconf doesn't work for virtual i/f */
1830 if (get_ifname_unit(name
, NULL
, &wlsubunit
) == 0 && wlsubunit
>= 0) {
1831 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name
);
1835 /* Check interface (fail silently for non-wl interfaces) */
1836 if ((ret
= wl_probe(name
)))
1839 /* because of ifdefs in wl driver, when we don't have AP capabilities we
1840 * can't use the same iovars to configure the wl.
1841 * so we use "wl_ap_build" to help us know how to configure the driver
1843 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
1846 foreach(cap
, caps
, next
) {
1847 if (!strcmp(cap
, "ap")) {
1853 /* Bring down the interface */
1854 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
1856 /* Disable all BSS Configs */
1857 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
1858 setbuf
.bsscfg_idx
= i
;
1861 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
1863 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
1864 /* fail quietly on a range error since the driver may
1865 * support fewer bsscfgs than we are prepared to configure
1867 if (bcmerr
== BCME_RANGE
)
1873 WL_IOCTL(name
, WLC_GET_UP
, &val
, sizeof(val
));
1877 ssid
.SSID
[0] = '\0';
1878 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
1880 /* Bring down the interface */
1881 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
1885 /* Nuke the WDS list */
1886 wlconf_wds_clear(name
);
1893 main(int argc
, char *argv
[])
1895 /* Check parameters and branch based on action */
1896 if (argc
== 3 && !strcmp(argv
[2], "up"))
1897 return wlconf(argv
[1]);
1898 else if (argc
== 3 && !strcmp(argv
[2], "down"))
1899 return wlconf_down(argv
[1]);
1901 fprintf(stderr
, "Usage: wlconf <ifname> up|down\n");