2 * Wireless Network Adapter Configuration Utility
4 * Copyright (C) 2014, 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.
12 * $Id: wlconf.c 454872 2014-02-12 02:49:54Z $
22 #include <bcmparams.h>
27 #include <proto/802.1d.h>
28 #include <bcmconfig.h>
29 #include <bcmwifi_channels.h>
32 #include <arpa/inet.h>
35 #include <sys/utsname.h>
44 #define PHY_TYPE_SSN 6
46 #define PHY_TYPE_LCN 8
47 #define PHY_TYPE_AC 11
48 #define PHY_TYPE_NULL 0xf
50 /* how many times to attempt to bring up a virtual i/f when
51 * we are in APSTA mode and IOVAR set of "bss" "up" returns busy
53 #define MAX_BSS_UP_RETRIES 5
55 /* notify the average dma xfer rate (in kbps) to the driver */
56 #define AVG_DMA_XFER_RATE 120000
58 /* parts of an idcode: */
59 #define IDCODE_MFG_MASK 0x00000fff
60 #define IDCODE_MFG_SHIFT 0
61 #define IDCODE_ID_MASK 0x0ffff000
62 #define IDCODE_ID_SHIFT 12
63 #define IDCODE_REV_MASK 0xf0000000
64 #define IDCODE_REV_SHIFT 28
70 #define WLCONF_DBG(fmt, arg...) printf("%s: "fmt, __FUNCTION__ , ## arg)
71 #define WL_IOCTL(ifname, cmd, buf, len) \
72 if ((ret = wl_ioctl(ifname, cmd, buf, len))) \
73 fprintf(stderr, "%s:%d:(%s): %s failed, err = %d\n", \
74 __FUNCTION__, __LINE__, ifname, #cmd, ret);
75 #define WL_SETINT(ifname, cmd, val) \
76 if ((ret = wlconf_setint(ifname, cmd, val))) \
77 fprintf(stderr, "%s:%d:(%s): setting %s to %d (0x%x) failed, err = %d\n", \
78 __FUNCTION__, __LINE__, ifname, #cmd, (int)val, (unsigned int)val, ret);
79 #define WL_GETINT(ifname, cmd, pval) \
80 if ((ret = wlconf_getint(ifname, cmd, pval))) \
81 fprintf(stderr, "%s:%d:(%s): getting %s failed, err = %d\n", \
82 __FUNCTION__, __LINE__, ifname, #cmd, ret);
83 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) \
84 if ((ret = wl_iovar_set(ifname, iovar, param, paramlen))) \
85 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" failed, err = %d\n", \
86 __FUNCTION__, __LINE__, ifname, iovar, ret);
87 #define WL_IOVAR_GET(ifname, iovar, param, paramlen) \
88 if ((ret = wl_iovar_get(ifname, iovar, param, paramlen))) \
89 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \
90 __FUNCTION__, __LINE__, ifname, iovar, ret);
91 #define WL_IOVAR_SETINT(ifname, iovar, val) \
92 if ((ret = wl_iovar_setint(ifname, iovar, val))) \
93 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" to 0x%x failed, err = %d\n", \
94 __FUNCTION__, __LINE__, ifname, iovar, (unsigned int)val, ret);
95 #define WL_IOVAR_GETINT(ifname, iovar, val) \
96 if ((ret = wl_iovar_getint(ifname, iovar, val))) \
97 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \
98 __FUNCTION__, __LINE__, ifname, iovar, ret);
99 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
100 if ((ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))) \
101 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
102 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
103 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
104 if ((ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))) \
105 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
106 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
107 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
108 if ((ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))) \
109 fprintf(stderr, "%s:%d:(%s): getting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
110 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
111 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) \
112 if ((ret = wl_bssiovar_setint(ifname, iovar, bssidx, val))) \
113 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" " \
114 "to val 0x%x failed, err = %d\n", \
115 __FUNCTION__, __LINE__, ifname, bssidx, iovar, (unsigned int)val, ret);
117 #define WLCONF_DBG(fmt, arg...)
118 #define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len))
119 #define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val))
120 #define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval))
121 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \
123 #define WL_IOVAR_GET(ifname, iovar, param, paramlen) (ret = wl_iovar_get(ifname, iovar, \
125 #define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val))
126 #define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val))
127 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
128 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))
129 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
130 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))
131 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
132 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))
133 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \
137 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
140 struct bsscfg_list
*wlconf_get_bsscfgs(char* ifname
, char* prefix
);
141 int wlconf(char *name
);
142 int wlconf_down(char *name
);
145 wlconf_getint(char* ifname
, int cmd
, int *pval
)
147 return wl_ioctl(ifname
, cmd
, pval
, sizeof(int));
151 wlconf_setint(char* ifname
, int cmd
, int val
)
153 return wl_ioctl(ifname
, cmd
, &val
, sizeof(int));
157 wlconf_wds_clear(char *name
)
159 struct maclist maclist
;
163 WL_IOCTL(name
, WLC_SET_WDSLIST
, &maclist
, sizeof(maclist
));
170 wlconf_set_wep_key(char *name
, char *prefix
, int bsscfg_idx
, int i
)
173 char wl_key
[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
174 char *keystr
, hex
[] = "XX";
175 unsigned char *data
= key
.data
;
178 memset(&key
, 0, sizeof(key
));
180 sprintf(wl_key
, "%skey%d", prefix
, i
);
181 keystr
= nvram_safe_get(wl_key
);
183 switch (strlen(keystr
)) {
185 case WEP128_KEY_SIZE
:
186 key
.len
= strlen(keystr
);
187 strcpy((char *)key
.data
, keystr
);
189 case WEP1_KEY_HEX_SIZE
:
190 case WEP128_KEY_HEX_SIZE
:
191 key
.len
= strlen(keystr
) / 2;
193 strncpy(hex
, keystr
, 2);
194 *data
++ = (unsigned char) strtoul(hex
, NULL
, 16);
203 /* Set current WEP key */
204 if (key
.len
&& i
== atoi(nvram_safe_get(strcat_r(prefix
, "key", wl_key
))))
205 key
.flags
= WL_PRIMARY_KEY
;
207 WL_BSSIOVAR_SET(name
, "wsec_key", bsscfg_idx
, &key
, sizeof(key
));
213 wlconf_akm_options(char *prefix
)
221 wl_akm
= nvram_safe_get(strcat_r(prefix
, "akm", comb
));
222 foreach(akm
, wl_akm
, next
) {
223 if (!strcmp(akm
, "wpa"))
224 akm_ret_val
|= WPA_AUTH_UNSPECIFIED
;
225 if (!strcmp(akm
, "psk"))
226 akm_ret_val
|= WPA_AUTH_PSK
;
227 if (!strcmp(akm
, "wpa2"))
228 akm_ret_val
|= WPA2_AUTH_UNSPECIFIED
;
229 if (!strcmp(akm
, "psk2"))
230 akm_ret_val
|= WPA2_AUTH_PSK
;
231 if (!strcmp(akm
, "brcm_psk"))
232 akm_ret_val
|= BRCM_AUTH_PSK
;
239 wlconf_set_wsec(char *ifname
, char *prefix
, int bsscfg_idx
)
246 /* Set wsec bitvec */
247 akm_val
= wlconf_akm_options(prefix
);
249 if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "tkip"))
251 else if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "aes"))
253 else if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "tkip+aes"))
254 val
= TKIP_ENABLED
| AES_ENABLED
;
256 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled"))
258 WL_BSSIOVAR_SETINT(ifname
, "wsec", bsscfg_idx
, val
);
259 /* Set wsec restrict if WSEC_ENABLED */
260 WL_BSSIOVAR_SETINT(ifname
, "wsec_restrict", bsscfg_idx
, val
? 1 : 0);
266 wlconf_set_preauth(char *name
, int bsscfg_idx
, int preauth
)
271 WL_BSSIOVAR_GET(name
, "wpa_cap", bsscfg_idx
, &cap
, sizeof(uint
));
272 if (ret
!= 0) return -1;
275 cap
|= WPA_CAP_WPA2_PREAUTH
;
277 cap
&= ~WPA_CAP_WPA2_PREAUTH
;
279 WL_BSSIOVAR_SETINT(name
, "wpa_cap", bsscfg_idx
, cap
);
285 wlconf_set_radarthrs(char *name
, char *prefix
)
287 wl_radar_thr_t radar_thr
;
289 char nv_buf
[NVRAM_MAX_VALUE_LEN
], *rargs
, *v
, *endptr
;
290 char buf
[WLC_IOCTL_SMLEN
];
292 char *version
= NULL
;
293 char *thr0_20_lo
= NULL
, *thr1_20_lo
= NULL
;
294 char *thr0_40_lo
= NULL
, *thr1_40_lo
= NULL
;
295 char *thr0_80_lo
= NULL
, *thr1_80_lo
= NULL
;
296 char *thr0_20_hi
= NULL
, *thr1_20_hi
= NULL
;
297 char *thr0_40_hi
= NULL
, *thr1_40_hi
= NULL
;
298 char *thr0_80_hi
= NULL
, *thr1_80_hi
= NULL
;
300 char **locals
[] = { &version
, &thr0_20_lo
, &thr1_20_lo
, &thr0_40_lo
, &thr1_40_lo
,
301 &thr0_80_lo
, &thr1_80_lo
, &thr0_20_hi
, &thr1_20_hi
,
302 &thr0_40_hi
, &thr1_40_hi
, &thr0_80_hi
, &thr1_80_hi
};
304 rargs
= nvram_safe_get(strcat_r(prefix
, "radarthrs", nv_buf
));
309 if ((len
> NVRAM_MAX_VALUE_LEN
) || (len
== 0))
312 memset(nv_buf
, 0, sizeof(nv_buf
));
313 strncpy(nv_buf
, rargs
, len
);
315 for (i
= 0; i
< (sizeof(locals
) / sizeof(locals
[0])); i
++) {
317 while (*v
&& *v
!= ' ') {
324 if (v
>= (nv_buf
+ len
)) /* Check for complete list, if not caught later */
328 /* Start building request */
329 memset(buf
, 0, sizeof(buf
));
330 strcpy(buf
, "radarthrs");
331 /* Retrieve radar thrs parameters */
334 radar_thr
.version
= atoi(version
);
335 if (radar_thr
.version
> WL_RADAR_THR_VERSION
)
338 /* Retrieve ver 0 params */
341 radar_thr
.thresh0_20_lo
= (uint16
)strtol(thr0_20_lo
, &endptr
, 0);
347 radar_thr
.thresh1_20_lo
= (uint16
)strtol(thr1_20_lo
, &endptr
, 0);
353 radar_thr
.thresh0_40_lo
= (uint16
)strtol(thr0_40_lo
, &endptr
, 0);
359 radar_thr
.thresh1_40_lo
= (uint16
)strtol(thr1_40_lo
, &endptr
, 0);
365 radar_thr
.thresh0_80_lo
= (uint16
)strtol(thr0_80_lo
, &endptr
, 0);
371 radar_thr
.thresh1_80_lo
= (uint16
)strtol(thr1_80_lo
, &endptr
, 0);
376 if (radar_thr
.version
== 0) {
378 * Attempt a best effort update of ver 0 to ver 1 by updating
379 * the appropriate values with the specified defaults. The defaults
380 * are from the reference design.
382 radar_thr
.version
= WL_RADAR_THR_VERSION
; /* avoid driver rejecting it */
383 radar_thr
.thresh0_20_hi
= 0x6ac;
384 radar_thr
.thresh1_20_hi
= 0x6cc;
385 radar_thr
.thresh0_40_hi
= 0x6bc;
386 radar_thr
.thresh1_40_hi
= 0x6e0;
387 radar_thr
.thresh0_80_hi
= 0x6b0;
388 radar_thr
.thresh1_80_hi
= 0x30;
390 /* Retrieve ver 1 params */
393 radar_thr
.thresh0_20_hi
= (uint16
)strtol(thr0_20_hi
, &endptr
, 0);
399 radar_thr
.thresh1_20_hi
= (uint16
)strtol(thr1_20_hi
, &endptr
, 0);
405 radar_thr
.thresh0_40_hi
= (uint16
)strtol(thr0_40_hi
, &endptr
, 0);
411 radar_thr
.thresh1_40_hi
= (uint16
)strtol(thr1_40_hi
, &endptr
, 0);
417 radar_thr
.thresh0_80_hi
= (uint16
)strtol(thr0_80_hi
, &endptr
, 0);
423 radar_thr
.thresh1_80_hi
= (uint16
)strtol(thr1_80_hi
, &endptr
, 0);
429 /* Copy radar parameters into buffer and plug them to the driver */
430 memcpy((char*)(buf
+ strlen(buf
) + 1), (char*)&radar_thr
, sizeof(wl_radar_thr_t
));
431 WL_IOCTL(name
, WLC_SET_VAR
, buf
, sizeof(buf
));
436 WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n");
441 * This allows phy antenna selection to be retrieved from NVRAM
444 wlconf_set_antsel(char *name
, char *prefix
)
446 int i
, j
, len
, argc
, ret
;
447 char buf
[WLC_IOCTL_SMLEN
];
448 wlc_antselcfg_t val
= { {0}, 0};
449 char *argv
[ANT_SELCFG_MAX
] = {};
450 char nv_buf
[NVRAM_MAX_VALUE_LEN
], *argstr
, *v
, *endptr
;
452 argstr
= nvram_safe_get(strcat_r(prefix
, "phy_antsel", nv_buf
));
456 len
= strlen(argstr
);
457 if ((len
== 0) || (len
> NVRAM_MAX_VALUE_LEN
)) {
461 memset(nv_buf
, 0, sizeof(nv_buf
));
462 strncpy(nv_buf
, argstr
, len
);
464 for (argc
= 0; argc
< ANT_SELCFG_MAX
; ) {
466 while (*v
&& *v
!= ' ') {
473 if (v
>= (nv_buf
+ len
)) {
477 if ((argc
!= 1) && (argc
!= ANT_SELCFG_MAX
)) {
478 WLCONF_DBG("phy_antsel requires 1 or %d arguments\n", ANT_SELCFG_MAX
);
482 memset(buf
, 0, sizeof(buf
));
483 strcpy(buf
, "phy_antsel");
484 for (i
= 0, j
= 0; i
< ANT_SELCFG_MAX
; i
++) {
485 val
.ant_config
[i
] = (uint8
)strtol(argv
[j
], &endptr
, 0);
486 if (*endptr
!= '\0') {
487 WLCONF_DBG("Invalid antsel argument\n");
491 /* ANT_SELCFG_MAX argument format */
496 /* Copy antsel parameters into buffer and plug them to the driver */
497 memcpy((char*)(buf
+ strlen(buf
) + 1), (char*)&val
, sizeof(wlc_antselcfg_t
));
498 WL_IOCTL(name
, WLC_SET_VAR
, buf
, sizeof(buf
));
506 wlconf_set_current_txparam_into_nvram(char *name
, char *prefix
)
509 wme_tx_params_t txparams
[AC_COUNT
];
510 char *nv
[] = {"wme_txp_be", "wme_txp_bk", "wme_txp_vi", "wme_txp_vo"};
511 char data
[50], tmp
[50];
513 /* get the WME tx parameters */
514 WL_IOVAR_GET(name
, "wme_tx_params", txparams
, sizeof(txparams
));
516 /* Set nvram accordingly */
517 for (aci
= 0; aci
< AC_COUNT
; aci
++) {
518 sprintf(data
, "%d %d %d %d %d", txparams
[aci
].short_retry
,
519 txparams
[aci
].short_fallback
,
520 txparams
[aci
].long_retry
,
521 txparams
[aci
].long_fallback
,
522 txparams
[aci
].max_rate
);
524 nvram_set(strcat_r(prefix
, nv
[aci
], tmp
), data
);
530 wlconf_set_wme(char *name
, char *prefix
)
534 int phytype
, gmode
, no_ack
, apsd
, dp
[2];
535 edcf_acparam_t
*acparams
;
536 /* Pay attention to buffer length requirements when using this */
537 char buf
[WLC_IOCTL_SMLEN
*2];
538 char *v
, *nv_value
, nv
[100];
539 char nv_name
[] = "%swme_%s_%s";
540 char *ac
[] = {"be", "bk", "vi", "vo"};
541 char *cwmin
, *cwmax
, *aifsn
, *txop_b
, *txop_ag
, *admin_forced
, *oldest_first
;
542 char **locals
[] = { &cwmin
, &cwmax
, &aifsn
, &txop_b
, &txop_ag
, &admin_forced
,
544 struct {char *req
; char *str
;} mode
[] = {{"wme_ac_ap", "ap"}, {"wme_ac_sta", "sta"},
545 {"wme_tx_params", "txp"}};
547 /* query the phy type */
548 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
550 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", nv
)));
552 /* WME sta setting first */
553 for (i
= 0; i
< 2; i
++) {
554 /* build request block */
555 memset(buf
, 0, sizeof(buf
));
556 strcpy(buf
, mode
[i
].req
);
557 /* put push wmeac params after "wme-ac" in buf */
558 acparams
= (edcf_acparam_t
*)(buf
+ strlen(buf
) + 1);
560 for (j
= 0; j
< AC_COUNT
; j
++) {
561 /* get packed nvram parameter */
562 snprintf(nv
, sizeof(nv
), nv_name
, prefix
, mode
[i
].str
, ac
[j
]);
563 nv_value
= nvram_safe_get(nv
);
564 strcpy(nv
, nv_value
);
567 for (k
= 0; k
< (sizeof(locals
) / sizeof(locals
[0])); k
++) {
569 while (*v
&& *v
!= ' ')
578 acparams
->ECW
&= ~EDCF_ECWMIN_MASK
;
580 for (val
++, k
= 0; val
; val
>>= 1, k
++);
581 acparams
->ECW
|= (k
? k
- 1 : 0) & EDCF_ECWMIN_MASK
;
583 acparams
->ECW
&= ~EDCF_ECWMAX_MASK
;
585 for (val
++, k
= 0; val
; val
>>= 1, k
++);
586 acparams
->ECW
|= ((k
? k
- 1 : 0) << EDCF_ECWMAX_SHIFT
) & EDCF_ECWMAX_MASK
;
588 acparams
->ACI
&= ~EDCF_AIFSN_MASK
;
589 acparams
->ACI
|= atoi(aifsn
) & EDCF_AIFSN_MASK
;
591 acparams
->ACI
&= ~EDCF_ACI_MASK
;
592 acparams
->ACI
|= j
<< EDCF_ACI_SHIFT
;
594 if (phytype
== PHY_TYPE_B
|| gmode
== 0)
598 acparams
->TXOP
= val
/ 32;
600 acparams
->ACI
&= ~EDCF_ACM_MASK
;
601 val
= strcmp(admin_forced
, "on") ? 0 : 1;
602 acparams
->ACI
|= val
<< 4;
604 /* configure driver */
605 WL_IOCTL(name
, WLC_SET_VAR
, buf
, sizeof(buf
));
610 v
= nvram_safe_get(strcat_r(prefix
, "wme_no_ack", nv
));
611 no_ack
= strcmp(v
, "on") ? 0 : 1;
612 WL_IOVAR_SETINT(name
, "wme_noack", no_ack
);
615 v
= nvram_safe_get(strcat_r(prefix
, "wme_apsd", nv
));
616 apsd
= strcmp(v
, "on") ? 0 : 1;
617 WL_IOVAR_SETINT(name
, "wme_apsd", apsd
);
619 /* set per-AC discard policy */
620 strcpy(buf
, "wme_dp");
621 WL_IOVAR_SETINT(name
, "wme_dp", dp
[1]);
623 /* WME Tx parameters setting */
625 wme_tx_params_t txparams
[AC_COUNT
];
626 char *srl
, *sfbl
, *lrl
, *lfbl
, *maxrate
;
627 char **locals
[] = { &srl
, &sfbl
, &lrl
, &lfbl
, &maxrate
};
629 /* build request block */
630 memset(txparams
, 0, sizeof(txparams
));
632 for (j
= 0; j
< AC_COUNT
; j
++) {
633 /* get packed nvram parameter */
634 snprintf(nv
, sizeof(nv
), nv_name
, prefix
, mode
[2].str
, ac
[j
]);
635 nv_value
= nvram_safe_get(nv
);
636 strcpy(nv
, nv_value
);
639 for (k
= 0; k
< (sizeof(locals
) / sizeof(locals
[0])); k
++) {
641 while (*v
&& *v
!= ' ')
649 /* update short retry limit */
650 txparams
[j
].short_retry
= atoi(srl
);
652 /* update short fallback limit */
653 txparams
[j
].short_fallback
= atoi(sfbl
);
655 /* update long retry limit */
656 txparams
[j
].long_retry
= atoi(lrl
);
658 /* update long fallback limit */
659 txparams
[j
].long_fallback
= atoi(lfbl
);
661 /* update max rate */
662 txparams
[j
].max_rate
= atoi(maxrate
);
665 /* set the WME tx parameters */
666 WL_IOVAR_SET(name
, mode
[2].req
, txparams
, sizeof(txparams
));
672 #if defined(linux) || defined(__NetBSD__)
675 sleep_ms(const unsigned int ms
)
679 #elif defined(__ECOS)
681 sleep_ms(const unsigned int ms
)
683 cyg_tick_count_t ostick
;
686 cyg_thread_delay(ostick
);
689 #error "sleep_ms() not defined for this OS!!!"
690 #endif /* defined(linux) */
693 * The following condition(s) must be met when Auto Channel Selection
695 * - the I/F is up (change radio channel requires it is up?)
696 * - the AP must not be associated (setting SSID to empty should
697 * make sure it for us)
700 wlconf_auto_channel(char *name
)
703 wl_uint32_list_t request
;
708 /* query the phy type */
709 WL_GETINT(name
, WLC_GET_PHYTYPE
, &phytype
);
711 request
.count
= 0; /* let the ioctl decide */
712 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
714 sleep_ms(phytype
== PHY_TYPE_A
? 1000 : 750);
715 for (i
= 0; i
< 100; i
++) {
716 WL_GETINT(name
, WLC_GET_CHANNEL_SEL
, &chosen
);
722 WLCONF_DBG("interface %s: channel selected %d\n", name
, chosen
);
727 wlconf_auto_chanspec(char *name
)
729 chanspec_t chosen
= 0;
731 wl_uint32_list_t request
;
735 request
.count
= 0; /* let the ioctl decide */
736 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
738 /* this time needs to be < 1000 to prevent mpc kicking in for 2nd radio */
740 for (i
= 0; i
< 100; i
++) {
741 WL_IOVAR_GETINT(name
, "apcschspec", &temp
);
748 chosen
= (chanspec_t
) temp
;
749 WLCONF_DBG("interface %s: chanspec selected %04x\n", name
, chosen
);
753 /* PHY type/BAND conversion */
754 #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
755 /* PHY type conversion */
756 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
757 (phy) == PHY_TYPE_B ? "b" : \
758 (phy) == PHY_TYPE_LP ? "l" : \
759 (phy) == PHY_TYPE_G ? "g" : \
760 (phy) == PHY_TYPE_SSN ? "s" : \
761 (phy) == PHY_TYPE_HT ? "h" : \
762 (phy) == PHY_TYPE_AC ? "v" : \
763 (phy) == PHY_TYPE_LCN ? "c" : "n")
764 #define WLCONF_STR2PHYTYPE(ch) ((ch) == 'a' ? PHY_TYPE_A : \
765 (ch) == 'b' ? PHY_TYPE_B : \
766 (ch) == 'l' ? PHY_TYPE_LP : \
767 (ch) == 'g' ? PHY_TYPE_G : \
768 (ch) == 's' ? PHY_TYPE_SSN : \
769 (ch) == 'h' ? PHY_TYPE_HT : \
770 (ch) == 'v' ? PHY_TYPE_AC : \
771 (ch) == 'c' ? PHY_TYPE_LCN : PHY_TYPE_N)
773 #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */
775 #define WLCONF_PHYTYPE_11N(phy) ((phy) == PHY_TYPE_N || (phy) == PHY_TYPE_SSN || \
776 (phy) == PHY_TYPE_LCN || (phy) == PHY_TYPE_HT || \
777 (phy) == PHY_TYPE_AC)
780 int idx
; /* bsscfg index */
781 char ifname
[PREFIX_LEN
]; /* OS name of interface (debug only) */
782 char prefix
[PREFIX_LEN
]; /* prefix for nvram params (eg. "wl0.1_") */
787 struct bsscfg_info bsscfgs
[WL_MAXBSSCFG
];
791 wlconf_get_bsscfgs(char* ifname
, char* prefix
)
797 struct bsscfg_list
*bclist
;
798 struct bsscfg_info
*bsscfg
;
800 bclist
= (struct bsscfg_list
*)malloc(sizeof(struct bsscfg_list
));
803 memset(bclist
, 0, sizeof(struct bsscfg_list
));
805 /* Set up Primary BSS Config information */
806 bsscfg
= &bclist
->bsscfgs
[0];
808 strncpy(bsscfg
->ifname
, ifname
, PREFIX_LEN
-1);
809 strcpy(bsscfg
->prefix
, prefix
);
812 /* additional virtual BSS Configs from wlX_vifs */
813 foreach(var
, nvram_safe_get(strcat_r(prefix
, "vifs", tmp
)), next
) {
814 if (bclist
->count
== WL_MAXBSSCFG
) {
815 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
817 "while configuring interface \"%s\"\n",
818 ifname
, WL_MAXBSSCFG
, strcat_r(prefix
, "vifs", tmp
), var
);
821 bsscfg
= &bclist
->bsscfgs
[bclist
->count
];
822 if (get_ifname_unit(var
, NULL
, &bsscfg
->idx
) != 0) {
823 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
828 strncpy(bsscfg
->ifname
, var
, PREFIX_LEN
-1);
829 snprintf(bsscfg
->prefix
, PREFIX_LEN
, "%s_", bsscfg
->ifname
);
837 wlconf_config_join_pref(char *name
, int bsscfg_idx
, int auth_val
)
841 if ((auth_val
& (WPA_AUTH_UNSPECIFIED
| WPA2_AUTH_UNSPECIFIED
)) ||
842 CHECK_PSK(auth_val
)) {
844 /* WPA pref, 14 tuples */
845 0x02, 0xaa, 0x00, 0x0e,
846 /* WPA2 AES (unicast) AES (multicast) */
847 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x04,
848 /* WPA AES (unicast) AES (multicast) */
849 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x04,
850 /* WPA2 AES (unicast) TKIP (multicast) */
851 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x02,
852 /* WPA AES (unicast) TKIP (multicast) */
853 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x02,
854 /* WPA2 AES (unicast) WEP-40 (multicast) */
855 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x01,
856 /* WPA AES (unicast) WEP-40 (multicast) */
857 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x01,
858 /* WPA2 AES (unicast) WEP-128 (multicast) */
859 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x05,
860 /* WPA AES (unicast) WEP-128 (multicast) */
861 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x05,
862 /* WPA2 TKIP (unicast) TKIP (multicast) */
863 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x02,
864 /* WPA TKIP (unicast) TKIP (multicast) */
865 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x02,
866 /* WPA2 TKIP (unicast) WEP-40 (multicast) */
867 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x01,
868 /* WPA TKIP (unicast) WEP-40 (multicast) */
869 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x01,
870 /* WPA2 TKIP (unicast) WEP-128 (multicast) */
871 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x05,
872 /* WPA TKIP (unicast) WEP-128 (multicast) */
873 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x05,
875 0x01, 0x02, 0x00, 0x00,
878 if (CHECK_PSK(auth_val
)) {
879 for (i
= 0; i
< pref
[3]; i
++)
880 pref
[7 + i
* 12] = 0x02;
883 WL_BSSIOVAR_SET(name
, "join_pref", bsscfg_idx
, pref
, sizeof(pref
));
889 wlconf_security_options(char *name
, char *prefix
, int bsscfg_idx
, bool id_supp
,
890 bool check_join_pref
)
896 bool need_join_pref
= FALSE
;
897 #define AUTOWPA(cfg) ((cfg) == (WPA_AUTH_PSK | WPA2_AUTH_PSK))
901 * Need to check errors (card may have changed) and change to
902 * defaults since the new chip may not support the requested
903 * encryptions after the card has been changed.
905 if (wlconf_set_wsec(name
, prefix
, bsscfg_idx
)) {
906 /* change nvram only, code below will pass them on */
907 nvram_restore_var(prefix
, "auth_mode");
908 nvram_restore_var(prefix
, "auth");
909 /* reset wep to default */
910 nvram_restore_var(prefix
, "crypto");
911 nvram_restore_var(prefix
, "wep");
912 wlconf_set_wsec(name
, prefix
, bsscfg_idx
);
915 val
= wlconf_akm_options(prefix
);
916 if (!nvram_match(strcat_r(prefix
, "mode", tmp
), "ap"))
917 need_join_pref
= (check_join_pref
|| id_supp
) && AUTOWPA(val
);
920 wlconf_config_join_pref(name
, bsscfg_idx
, val
);
922 /* enable in-driver wpa supplicant? */
923 if (id_supp
&& (CHECK_PSK(val
))) {
927 if (((key
= nvram_get(strcat_r(prefix
, "wpa_psk", tmp
))) != NULL
) &&
928 (strlen(key
) < WSEC_MAX_PSK_LEN
)) {
929 psk
.key_len
= (ushort
) strlen(key
);
930 psk
.flags
= WSEC_PASSPHRASE
;
931 strcpy((char *)psk
.key
, key
);
932 WL_IOCTL(name
, WLC_SET_WSEC_PMK
, &psk
, sizeof(psk
));
934 wl_iovar_setint(name
, "sup_wpa", 1);
938 WL_BSSIOVAR_SETINT(name
, "wpa_auth", bsscfg_idx
, val
);
940 /* EAP Restrict if we have an AKM or radius authentication */
941 val
= ((val
!= 0) || (nvram_match(strcat_r(prefix
, "auth_mode", tmp
), "radius")));
942 WL_BSSIOVAR_SETINT(name
, "eap_restrict", bsscfg_idx
, val
);
945 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled")) {
946 for (i
= 1; i
<= DOT11_MAX_DEFAULT_KEYS
; i
++)
947 wlconf_set_wep_key(name
, prefix
, bsscfg_idx
, i
);
950 /* Set 802.11 authentication mode - open/shared */
951 val
= atoi(nvram_safe_get(strcat_r(prefix
, "auth", tmp
)));
952 WL_BSSIOVAR_SETINT(name
, "auth", bsscfg_idx
, val
);
955 val
= WPA_AUTH_DISABLED
;
956 WL_BSSIOVAR_GET(name
, "wpa_auth", bsscfg_idx
, &val
, sizeof(val
));
957 if (val
& (WPA2_AUTH_PSK
| WPA2_AUTH_UNSPECIFIED
)) {
958 val
= atoi(nvram_safe_get(strcat_r(prefix
, "mfp", tmp
)));
959 WL_BSSIOVAR_SETINT(name
, "mfp", bsscfg_idx
, val
);
965 wlconf_set_ampdu_retry_limit(char *name
, char *prefix
)
967 int i
, j
, ret
, nv_len
;
968 struct ampdu_retry_tid retry_limit
;
969 char *nv_name
[2] = {"ampdu_rtylimit_tid", "ampdu_rr_rtylimit_tid"};
970 char *iov_name
[2] = {"ampdu_retry_limit_tid", "ampdu_rr_retry_limit_tid"};
971 char *retry
, *v
, *nv_value
, nv
[100], tmp
[100];
973 /* Get packed AMPDU (rr) retry limit per-tid from NVRAM if present */
974 for (i
= 0; i
< 2; i
++) {
975 nv_value
= nvram_safe_get(strcat_r(prefix
, nv_name
[i
], tmp
));
976 nv_len
= strlen(nv_value
);
977 strcpy(nv
, nv_value
);
981 for (j
= 0; nv_len
>= 0 && j
< NUMPRIO
; j
++) {
983 while (*v
&& *v
!= ' ') {
992 /* set the AMPDU retry limit per-tid */
994 retry_limit
.retry
= atoi(retry
);
995 WL_IOVAR_SET(name
, iov_name
[i
], &retry_limit
, sizeof(retry_limit
));
1003 * When N-mode is ON, AMPDU, AMSDU are enabled/disabled
1004 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
1005 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off.
1007 * WME/WMM is also set in this procedure as it depends on N.
1008 * N ==> WMM is on by default
1010 * Returns WME setting.
1013 wlconf_ampdu_amsdu_set(char *name
, char prefix
[PREFIX_LEN
], int nmode
, int btc_mode
, int ap
)
1015 bool ampdu_valid_option
= FALSE
;
1016 bool amsdu_valid_option
= FALSE
;
1017 int val
, ampdu_option_val
= OFF
, amsdu_option_val
= OFF
;
1018 int rx_amsdu_in_ampdu_option_val
= OFF
;
1019 int wme_option_val
= ON
; /* On by default */
1020 char caps
[WLC_IOCTL_MEDLEN
], var
[80], *next
, *wme_val
;
1021 char buf
[WLC_IOCTL_SMLEN
];
1022 int len
= (sizeof("amsdu") - 1);
1026 struct utsname unamebuf
;
1031 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1033 WL_GETINT(name
, WLC_GET_PHYTYPE
, &phytype
);
1035 /* First, clear WMM settings to avoid conflicts */
1036 WL_IOVAR_SETINT(name
, "wme", OFF
);
1038 /* Get WME setting from NVRAM if present */
1039 wme_val
= nvram_get(strcat_r(prefix
, "wme", caps
));
1040 if (wme_val
&& !strcmp(wme_val
, "off")) {
1041 wme_option_val
= OFF
;
1044 /* Set options based on capability */
1045 wl_iovar_get(name
, "cap", (void *)caps
, sizeof(caps
));
1046 foreach(var
, caps
, next
) {
1050 /* Check for the capabilitiy 'amsdutx' */
1051 if (strncmp(var
, "amsdutx", sizeof(var
)) == 0) {
1055 nvram_str
= nvram_get(strcat_r(prefix
, var
, buf
));
1059 if (!strcmp(nvram_str
, "on"))
1061 else if (!strcmp(nvram_str
, "off"))
1063 else if (!strcmp(nvram_str
, "auto"))
1068 if (strncmp(var
, "ampdu", sizeof(var
)) == 0) {
1069 ampdu_valid_option
= TRUE
;
1070 ampdu_option_val
= val
;
1074 amsdu_valid_option
= TRUE
;
1075 amsdu_option_val
= val
;
1077 nvram_str
= nvram_get(strcat_r(prefix
, "rx_amsdu_in_ampdu", buf
));
1079 if (!strcmp(nvram_str
, "on"))
1080 rx_amsdu_in_ampdu_option_val
= ON
;
1081 else if (!strcmp(nvram_str
, "auto"))
1082 rx_amsdu_in_ampdu_option_val
= AUTO
;
1086 * Some tests show problems when AMSDU is enabled on TX
1087 * side together with ps-pretend.
1088 * Ps-pretend is used on AP only.
1089 * Let's disable AMSDU downstream unconditionally
1091 * When ps-pretend be OK with AMSDU, below statement
1092 * need to be removed.
1094 if (ap
&& !strcmp(nvram_safe_get("devicemode"), "1")) {
1095 amsdu_option_val
= OFF
;
1100 if (nmode
!= OFF
) { /* N-mode is ON/AUTO */
1101 if (ampdu_valid_option
) {
1102 if (ampdu_option_val
!= OFF
) {
1103 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
1104 WL_IOVAR_SETINT(name
, "ampdu", ampdu_option_val
);
1106 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
1109 wlconf_set_ampdu_retry_limit(name
, prefix
);
1112 /* For MIPS routers set the num mpdu per ampdu limit to 32. We observed
1113 * that having this value at 32 helps with bi-di thru'put as well.
1115 if ((phytype
== PHY_TYPE_AC
) &&
1116 (strncmp(unamebuf
.machine
, "mips", 4) == 0)) {
1117 #ifndef __CONFIG_USBAP__
1118 WL_IOVAR_SETINT(name
, "ampdu_mpdu", 32);
1119 #endif /* __CONFIG_USBAP__ */
1124 if (amsdu_valid_option
) {
1125 if (amsdu_option_val
!= OFF
) { /* AMPDU (above) has priority over AMSDU */
1126 if (rev
.corerev
>= 40) {
1127 WL_IOVAR_SETINT(name
, "amsdu", amsdu_option_val
);
1128 } else if (ampdu_option_val
== OFF
) {
1129 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
1130 WL_IOVAR_SETINT(name
, "amsdu", amsdu_option_val
);
1133 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
1136 WL_IOVAR_SETINT(name
, "rx_amsdu_in_ampdu", rx_amsdu_in_ampdu_option_val
);
1138 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
1140 wl_iovar_setint(name
, "amsdu", OFF
);
1141 wl_iovar_setint(name
, "ampdu", OFF
);
1144 if (wme_option_val
) {
1145 WL_IOVAR_SETINT(name
, "wme", wme_option_val
);
1146 wlconf_set_wme(name
, prefix
);
1149 return wme_option_val
;
1152 /* Get configured bandwidth cap. */
1154 wlconf_bw_cap(char *prefix
, int bandtype
)
1156 char *str
, tmp
[100];
1157 int bw_cap
= WLC_BW_CAP_20MHZ
;
1159 if ((str
= nvram_get(strcat_r(prefix
, "bw_cap", tmp
))) != NULL
)
1162 /* Backward compatibility. Map to bandwidth cap bitmap values. */
1163 int val
= atoi(nvram_safe_get(strcat_r(prefix
, "nbw_cap", tmp
)));
1165 if (((bandtype
== WLC_BAND_2G
) && (val
== WLC_N_BW_40ALL
)) ||
1166 ((bandtype
== WLC_BAND_5G
) &&
1167 (val
== WLC_N_BW_40ALL
|| val
== WLC_N_BW_20IN2G_40IN5G
)))
1168 bw_cap
= WLC_BW_CAP_40MHZ
;
1170 bw_cap
= WLC_BW_CAP_20MHZ
;
1176 /* Set up TxBF. Called when i/f is down. */
1177 static void wlconf_set_txbf(char *name
, char *prefix
)
1179 char *str
, tmp
[100];
1181 uint32 txbf_bfe_cap
= 0;
1182 uint32 txbf_bfr_cap
= 0;
1185 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1187 if (rev
.corerev
< 40) return; /* TxBF unsupported */
1189 if ((str
= nvram_get(strcat_r(prefix
, "txbf_bfr_cap", tmp
))) != NULL
) {
1190 txbf_bfr_cap
= atoi(str
);
1193 /* Turning TxBF on (order matters) */
1194 WL_IOVAR_SETINT(name
, "txbf_bfr_cap", 1);
1195 WL_IOVAR_SETINT(name
, "txbf", 1);
1197 /* Similarly, turning TxBF off in reverse order */
1198 WL_IOVAR_SETINT(name
, "txbf", 0);
1199 WL_IOVAR_SETINT(name
, "txbf_bfr_cap", 0);
1203 if ((str
= nvram_get(strcat_r(prefix
, "txbf_bfe_cap", tmp
))) != NULL
) {
1204 txbf_bfe_cap
= atoi(str
);
1206 WL_IOVAR_SETINT(name
, "txbf_bfe_cap", txbf_bfe_cap
? 1 : 0);
1210 /* Set up TxBF timer. Called when i/f is up. */
1211 static void wlconf_set_txbf_timer(char *name
, char *prefix
)
1213 char *str
, tmp
[100];
1215 uint32 txbf_timer
= 0;
1218 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1220 if (rev
.corerev
< 40) return; /* TxBF unsupported */
1222 if ((str
= nvram_get(strcat_r(prefix
, "txbf_timer", tmp
))) != NULL
) {
1223 txbf_timer
= (uint32
) atoi(str
);
1224 WL_IOVAR_SETINT(name
, "txbf_timer", txbf_timer
);
1228 /* Apply Traffic Management filter settings stored in NVRAM */
1230 trf_mgmt_settings(char *prefix
, bool dwm_supported
)
1232 char buffer
[sizeof(trf_mgmt_filter_t
)*(MAX_NUM_TRF_MGMT_RULES
+1)];
1233 char iobuff
[sizeof(trf_mgmt_filter_t
)*(MAX_NUM_TRF_MGMT_RULES
+1)+32];
1234 int i
, filterlen
, ret
= 0;
1235 trf_mgmt_config_t trf_mgmt_config
;
1236 trf_mgmt_filter_list_t
*trf_mgmt_filter_list
;
1237 netconf_trmgmt_t nettrm
;
1238 trf_mgmt_filter_t
*trfmgmt
;
1240 struct in_addr ipaddr
, ipmask
;
1241 char nvram_ifname
[32];
1242 bool tm_filters_configured
= FALSE
;
1244 bool dwm_filters_configured
= FALSE
;
1245 char dscp_filter_buffer
[sizeof(trf_mgmt_filter_t
)*(MAX_NUM_TRF_MGMT_DWM_RULES
)];
1246 char dscp_filter_iobuff
[sizeof(trf_mgmt_filter_t
)*(MAX_NUM_TRF_MGMT_DWM_RULES
)+
1247 sizeof("trf_mgmt_filters_add") + OFFSETOF(trf_mgmt_filter_list_t
, filter
)];
1249 trf_mgmt_filter_t
*trf_mgmt_dwm_filter
;
1250 trf_mgmt_filter_list_t
*trf_mgmt_dwm_filter_list
= NULL
;
1251 netconf_trmgmt_t nettrm_dwm
;
1253 snprintf(nvram_ifname
, sizeof(nvram_ifname
), "%sifname", prefix
);
1254 wlifname
= nvram_get(nvram_ifname
);
1259 trf_mgmt_filter_list
= (trf_mgmt_filter_list_t
*)buffer
;
1260 trfmgmt
= &trf_mgmt_filter_list
->filter
[0];
1262 /* Initialize the common parameters */
1263 memset(buffer
, 0, sizeof(buffer
));
1264 memset(&trf_mgmt_config
, 0, sizeof(trf_mgmt_config_t
));
1266 /* no-rx packets, local subnet, don't override priority and no-traffic shape */
1267 trf_mgmt_config
.flags
= (TRF_MGMT_FLAG_NO_RX
|
1268 TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC
|
1269 TRF_MGMT_FLAG_DISABLE_SHAPING
);
1270 (void) inet_aton("192.168.1.1", &ipaddr
); /* Dummy value */
1271 (void) inet_aton("255.255.255.0", &ipmask
); /* Dummy value */
1272 trf_mgmt_config
.host_ip_addr
= ipaddr
.s_addr
; /* Dummy value */
1273 trf_mgmt_config
.host_subnet_mask
= ipmask
.s_addr
; /* Dummy value */
1274 trf_mgmt_config
.downlink_bandwidth
= 1; /* Dummy value */
1275 trf_mgmt_config
.uplink_bandwidth
= 1; /* Dummy value */
1277 /* Read up to NUM_TFF_MGMT_FILTERS entries from NVRAM */
1278 for (i
= 0; i
< MAX_NUM_TRF_MGMT_RULES
; i
++) {
1279 if (get_trf_mgmt_port(prefix
, i
, &nettrm
) == FALSE
) {
1282 if (nettrm
.match
.flags
== NETCONF_DISABLED
) {
1285 trfmgmt
->dst_port
= ntohs(nettrm
.match
.dst
.ports
[0]);
1286 trfmgmt
->src_port
= ntohs(nettrm
.match
.src
.ports
[0]);
1287 trfmgmt
->prot
= nettrm
.match
.ipproto
;
1288 if (nettrm
.favored
) {
1289 trfmgmt
->flags
|= TRF_FILTER_FAVORED
;
1291 trfmgmt
->priority
= nettrm
.prio
;
1292 memcpy(&trfmgmt
->dst_ether_addr
, &nettrm
.match
.mac
, sizeof(struct ether_addr
));
1293 if (nettrm
.match
.ipproto
== IPPROTO_IP
) {
1294 /* Enable MAC filter */
1295 trf_mgmt_config
.flags
|= TRF_MGMT_FLAG_FILTER_ON_MACADDR
;
1296 trfmgmt
->flags
|= TRF_FILTER_MAC_ADDR
;
1298 trf_mgmt_filter_list
->num_filters
+= 1;
1301 if (trf_mgmt_filter_list
->num_filters
)
1302 tm_filters_configured
= TRUE
;
1304 if (dwm_supported
) {
1305 trf_mgmt_dwm_filter_list
= (trf_mgmt_filter_list_t
*)dscp_filter_buffer
;
1306 trf_mgmt_dwm_filter
= &trf_mgmt_dwm_filter_list
->filter
[0];
1307 memset(dscp_filter_buffer
, 0, sizeof(dscp_filter_buffer
));
1309 /* Read up to NUM_TFF_MGMT_FILTERS entries from NVRAM */
1310 for (i
= 0; i
< MAX_NUM_TRF_MGMT_DWM_RULES
; i
++) {
1311 if (get_trf_mgmt_dwm(prefix
, i
, &nettrm_dwm
) == FALSE
) {
1314 if (nettrm_dwm
.match
.flags
== NETCONF_DISABLED
) {
1318 trf_mgmt_dwm_filter
->dscp
= nettrm_dwm
.match
.dscp
;
1319 if (nettrm_dwm
.favored
)
1320 trf_mgmt_dwm_filter
->flags
|= TRF_FILTER_FAVORED
;
1321 trf_mgmt_dwm_filter
->flags
|= TRF_FILTER_DWM
;
1322 trf_mgmt_dwm_filter
->priority
= nettrm_dwm
.prio
;
1323 trf_mgmt_dwm_filter
++;
1324 trf_mgmt_dwm_filter_list
->num_filters
+= 1;
1326 if (trf_mgmt_dwm_filter_list
->num_filters
)
1327 dwm_filters_configured
= TRUE
;
1330 /* Disable traffic management module to initial known state */
1331 trf_mgmt_config
.trf_mgmt_enabled
= 0;
1332 WL_IOVAR_SET(wlifname
, "trf_mgmt_config", &trf_mgmt_config
, sizeof(trf_mgmt_config_t
));
1334 /* Add traffic management filter entries */
1335 if (tm_filters_configured
|| dwm_filters_configured
) {
1336 /* Enable traffic management module before adding filter mappings */
1337 trf_mgmt_config
.trf_mgmt_enabled
= 1;
1338 WL_IOVAR_SET(wlifname
, "trf_mgmt_config", &trf_mgmt_config
,
1339 sizeof(trf_mgmt_config_t
));
1341 if (tm_filters_configured
) {
1342 /* Configure TM module filters mappings */
1343 filterlen
= trf_mgmt_filter_list
->num_filters
*
1344 sizeof(trf_mgmt_filter_t
) +
1345 OFFSETOF(trf_mgmt_filter_list_t
, filter
);
1346 wl_iovar_setbuf(wlifname
, "trf_mgmt_filters_add", trf_mgmt_filter_list
,
1347 filterlen
, iobuff
, sizeof(iobuff
));
1350 if (dwm_filters_configured
) {
1351 dscp_filterlen
= trf_mgmt_dwm_filter_list
->num_filters
*
1352 sizeof(trf_mgmt_filter_t
) +
1353 OFFSETOF(trf_mgmt_filter_list_t
, filter
);
1354 wl_iovar_setbuf(wlifname
, "trf_mgmt_filters_add", trf_mgmt_dwm_filter_list
,
1355 dscp_filterlen
, dscp_filter_iobuff
, sizeof(dscp_filter_iobuff
));
1360 #ifdef TRAFFIC_MGMT_RSSI_POLICY
1362 trf_mgmt_rssi_policy(char *prefix
)
1365 char nvram_ifname
[32];
1366 char rssi_policy
[64];
1367 uint32 rssi_policy_value
, ret
;
1369 /* Get wl interface name */
1370 snprintf(nvram_ifname
, sizeof(nvram_ifname
), "%sifname", prefix
);
1371 if ((wlifname
= nvram_get(nvram_ifname
)) == NULL
) {
1375 /* Get RSSI policy from NVRAM variable wlx_trf_mgmt_rssi_policy */
1376 snprintf(rssi_policy
, sizeof(rssi_policy
), "%strf_mgmt_rssi_policy", prefix
);
1377 if (!nvram_invmatch(rssi_policy
, ""))
1379 rssi_policy_value
= atoi(nvram_get(rssi_policy
));
1381 /* Enable/Disable RSSI policy depending on value of rssi_policy_value */
1382 WL_IOVAR_SETINT(wlifname
, "trf_mgmt_rssi_policy", rssi_policy_value
);
1384 #endif /* TRAFFIC_MGMT_RSSI_POLICY */
1387 wlconf_del_brcm_syscap_ie(char *name
, int bsscfg_idx
, char *oui
)
1390 vndr_ie_setbuf_t
*ie_setbuf
= NULL
;
1393 char getbuf
[2048] = {0};
1394 vndr_ie_buf_t
*iebuf
;
1395 vndr_ie_info_t
*ieinfo
;
1403 frametype
= VNDR_IE_BEACON_FLAG
;
1405 WL_BSSIOVAR_GET(name
, "vndr_ie", bsscfg_idx
, getbuf
, 2048);
1406 iebuf
= (vndr_ie_buf_t
*)getbuf
;
1408 bufaddr
= (char*)iebuf
->vndr_ie_list
;
1410 for (i
= 0; i
< iebuf
->iecount
; i
++) {
1411 ieinfo
= (vndr_ie_info_t
*)bufaddr
;
1412 bcopy((char*)&ieinfo
->pktflag
, (char*)&pktflag
, (int)sizeof(uint32
));
1413 if (pktflag
== frametype
) {
1414 if (!memcmp(ieinfo
->vndr_ie_data
.oui
, oui
, DOT11_OUI_LEN
)) {
1416 bufaddr
= (char*) &ieinfo
->vndr_ie_data
;
1417 buflen
= (int)ieinfo
->vndr_ie_data
.len
+ VNDR_IE_HDR_LEN
;
1421 bufaddr
= (char *)(ieinfo
->vndr_ie_data
.oui
+ ieinfo
->vndr_ie_data
.len
);
1427 iebuf_len
= buflen
+ sizeof(vndr_ie_setbuf_t
) - sizeof(vndr_ie_t
);
1428 ie_setbuf
= (vndr_ie_setbuf_t
*)malloc(iebuf_len
);
1430 WLCONF_DBG("memory alloc failure\n");
1435 memset(ie_setbuf
, 0, iebuf_len
);
1437 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1438 strcpy(ie_setbuf
->cmd
, "del");
1440 /* Buffer contains only 1 IE */
1442 memcpy(&ie_setbuf
->vndr_ie_buffer
.iecount
, &iecount
, sizeof(int));
1444 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].pktflag
, &frametype
, sizeof(uint32
));
1446 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
, bufaddr
, buflen
);
1448 WL_BSSIOVAR_SET(name
, "vndr_ie", bsscfg_idx
, ie_setbuf
, iebuf_len
);
1458 wlconf_set_brcm_syscap_ie(char *name
, int bsscfg_idx
, char *oui
, uchar
*data
, int datalen
)
1460 vndr_ie_setbuf_t
*ie_setbuf
= NULL
;
1461 unsigned int pktflag
;
1462 int buflen
, iecount
;
1465 pktflag
= VNDR_IE_BEACON_FLAG
;
1467 buflen
= sizeof(vndr_ie_setbuf_t
) + datalen
- 1;
1468 ie_setbuf
= (vndr_ie_setbuf_t
*)malloc(buflen
);
1470 WLCONF_DBG("memory alloc failure\n");
1475 memset(ie_setbuf
, 0, buflen
);
1477 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1478 strcpy(ie_setbuf
->cmd
, "add");
1480 /* Buffer contains only 1 IE */
1482 memcpy(&ie_setbuf
->vndr_ie_buffer
.iecount
, &iecount
, sizeof(int));
1484 /* The packet flag bit field indicates the packets that will contain this IE */
1485 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].pktflag
, &pktflag
, sizeof(uint32
));
1487 /* Now, add the IE to the buffer, +1: one byte OUI_TYPE */
1488 ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.len
= DOT11_OUI_LEN
+ datalen
;
1490 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.oui
[0], oui
, DOT11_OUI_LEN
);
1492 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.data
[0], data
,
1495 ret
= wlconf_del_brcm_syscap_ie(name
, bsscfg_idx
, oui
);
1499 WL_BSSIOVAR_SET(name
, "vndr_ie", (int)bsscfg_idx
, ie_setbuf
, buflen
);
1509 * wlconf_process_sta_config_entry() - process a single sta_config settings entry.
1511 * This function processes a single sta_config settings entry by parsing the entry and
1512 * calling the appropriate IOVAR(s) to apply the settings in the driver.
1515 * params - address of a nul terminated ascii string buffer containing a single sta_config
1516 * settings entry in the form "xx:xx:xx:xx:xx:xx,prio[,steerflag]".
1518 * At least the mac address of the station to which the settings are to be applied needs
1519 * to be present, with one or more setting values, in a specific order. New settings must
1520 * be added at the end. Alternatively, we could allow "prio=<value>,steerflag=<value>" and
1521 * so on, but that would take some more parsing and use more nvram space.
1524 * Driver settings may be updated.
1527 * This function returns a BCME_xxx status indicating success (BCME_OK) or failure.
1529 * Side effects: The input buffer is trashed by the strsep() function.
1533 wlconf_process_sta_config_entry(char *ifname
, char *param_list
)
1535 enum { /* Parameter index in comma-separated list of settings. */
1536 PARAM_MACADDRESS
= 0,
1538 PARAM_STEERFLAG
= 2,
1540 } param_idx
= PARAM_MACADDRESS
;
1542 struct ether_addr ea
;
1546 while ((param
= strsep(¶m_list
, ","))) {
1547 switch (param_idx
) {
1549 case PARAM_MACADDRESS
: /* MAC Address - parse into ea */
1550 if (!param
|| !ether_atoe(param
, &ea
.octet
[0])) {
1551 return BCME_BADADDR
;
1555 case PARAM_PRIO
: /* prio value - parse and apply through "staprio" iovar */
1556 if (*param
) { /* If no value is provided, do not configure the prio */
1557 wl_staprio_cfg_t staprio_arg
;
1560 value
= strtol(param
, &end
, 0);
1564 memset(&staprio_arg
, 0, sizeof(staprio_arg
));
1565 memcpy(&staprio_arg
.ea
, &ea
, sizeof(ea
));
1566 staprio_arg
.prio
= value
; /* prio is byte sized, no htod() needed */
1567 WL_IOVAR_SET(ifname
, "staprio", &staprio_arg
, sizeof(staprio_arg
));
1571 case PARAM_STEERFLAG
:
1573 value
= strtol(param
, &end
, 0);
1581 /* Future use parameter already set in nvram config - ignore. */
1587 if (param_idx
<= PARAM_PRIO
) { /* No mac address and/or no parameters at all, forget it. */
1594 #define VIFNAME_LEN 16
1596 /* configure the specified wireless interface */
1600 int restore_defaults
, val
, unit
, phytype
, bandtype
, gmode
= 0, ret
= 0;
1602 int error_bg
, error_a
;
1603 struct bsscfg_list
*bclist
= NULL
;
1604 struct bsscfg_info
*bsscfg
= NULL
;
1605 char tmp
[100], tmp2
[100], prefix
[PREFIX_LEN
];
1606 char var
[80], *next
, *str
, *addr
= NULL
;
1607 /* Pay attention to buffer length requirements when using this */
1608 char buf
[WLC_IOCTL_SMLEN
*2] __attribute__ ((aligned(4)));
1613 struct maclist
*maclist
;
1614 struct ether_addr
*ea
;
1619 int ap
, apsta
, wds
, sta
= 0, wet
= 0, mac_spoof
= 0, wmf
= 0;
1620 int rxchain_pwrsave
= 0, radio_pwrsave
= 0;
1621 wl_country_t country_spec
= {{0}, 0, {0}};
1627 int wl_ap_build
= 0; /* wl compiled with AP capabilities */
1628 char cap
[WLC_IOCTL_SMLEN
];
1629 char caps
[WLC_IOCTL_MEDLEN
];
1632 uint nbw
= WL_CHANSPEC_BW_20
;
1633 int nmode
= OFF
; /* 802.11n support */
1634 char vif_addr
[WLC_IOCTL_SMLEN
];
1635 int max_no_vifs
= 0;
1638 bool ure_enab
= FALSE
;
1639 bool radar_enab
= FALSE
;
1640 bool obss_coex
= FALSE
, psta
, psr
;
1641 chanspec_t chanspec
= 0;
1642 int wet_tunnel_cap
= 0, wet_tunnel_enable
= 0;
1643 brcm_prop_ie_t brcm_syscap_ie
;
1645 /* wlconf doesn't work for virtual i/f, so if we are given a
1646 * virtual i/f return 0 if that interface is in it's parent's "vifs"
1647 * list otherwise return -1
1649 if (get_ifname_unit(name
, &wlunit
, &wlsubunit
) == 0) {
1650 if (wlsubunit
>= 0) {
1651 /* we have been given a virtual i/f,
1652 * is it in it's parent i/f's virtual i/f list?
1654 sprintf(tmp
, "wl%d_vifs", wlunit
);
1656 if (strstr(nvram_safe_get(tmp
), name
) == NULL
)
1657 return -1; /* config error */
1659 return 0; /* okay */
1666 memset(tmp
, 0, sizeof(tmp
));
1668 /* because of ifdefs in wl driver, when we don't have AP capabilities we
1669 * can't use the same iovars to configure the wl.
1670 * so we use "wl_ap_build" to help us know how to configure the driver
1672 if (wl_iovar_get(name
, "cap", (void *)caps
, sizeof(caps
)))
1675 foreach(cap
, caps
, next
) {
1676 if (!strcmp(cap
, "ap")) {
1678 } else if (!strcmp(cap
, "mbss16"))
1680 else if (!strcmp(cap
, "mbss8"))
1682 else if (!strcmp(cap
, "mbss4"))
1684 else if (!strcmp(cap
, "wmf"))
1686 else if (!strcmp(cap
, "rxchain_pwrsave"))
1687 rxchain_pwrsave
= 1;
1688 else if (!strcmp(cap
, "radio_pwrsave"))
1690 else if (!strcmp(cap
, "wet_tunnel"))
1694 /* Check interface (fail silently for non-wl interfaces) */
1695 if ((ret
= wl_probe(name
)))
1698 /* Get MAC address */
1699 (void) wl_hwaddr(name
, (uchar
*)buf
);
1700 memcpy(vif_addr
, buf
, ETHER_ADDR_LEN
);
1703 WL_IOCTL(name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
));
1704 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
1706 /* Restore defaults if per-interface parameters do not exist */
1707 // restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
1708 restore_defaults
= !strlen(nvram_safe_get(strcat_r(prefix
, "ifname", tmp
)));
1709 // nvram_validate_all(prefix, restore_defaults);
1710 nvram_set(strcat_r(prefix
, "ifname", tmp
), name
);
1711 nvram_set(strcat_r(prefix
, "hwaddr", tmp
), ether_etoa((uchar
*)buf
, eaddr
));
1712 snprintf(buf
, sizeof(buf
), "%d", unit
);
1713 nvram_set(strcat_r(prefix
, "unit", tmp
), buf
);
1715 if (restore_defaults
) {
1716 wlconf_set_current_txparam_into_nvram(name
, prefix
);
1719 /* Apply message level */
1720 if (nvram_invmatch("wl_msglevel", "")) {
1721 val
= (int)strtoul(nvram_get("wl_msglevel"), NULL
, 0);
1723 if (nvram_invmatch("wl_msglevel2", "")) {
1724 struct wl_msglevel2 msglevel64
;
1725 msglevel64
.low
= val
;
1726 val
= (int)strtoul(nvram_get("wl_msglevel2"), NULL
, 0);
1727 msglevel64
.high
= val
;
1728 WL_IOVAR_SET(name
, "msglevel", &msglevel64
, sizeof(struct wl_msglevel2
));
1731 WL_IOCTL(name
, WLC_SET_MSGLEVEL
, &val
, sizeof(val
));
1735 /* Bring the interface down */
1736 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
1738 /* Disable all BSS Configs */
1739 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
1740 struct {int bsscfg_idx
; int enable
;} setbuf
;
1741 setbuf
.bsscfg_idx
= i
;
1744 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
1746 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
1747 /* fail quietly on a range error since the driver may
1748 * support fewer bsscfgs than we are prepared to configure
1750 if (bcmerr
== BCME_RANGE
)
1754 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
1755 " (down) failed, ret = %d, bcmerr = %d\n",
1756 __LINE__
, name
, i
, ret
, bcmerr
);
1760 /* Get the list of BSS Configs */
1761 bclist
= wlconf_get_bsscfgs(name
, prefix
);
1762 if (bclist
== NULL
) {
1768 strcat_r(prefix
, "vifs", tmp
);
1769 printf("BSS Config summary: primary -> \"%s\", %s -> \"%s\"\n", name
, tmp
,
1770 nvram_safe_get(tmp
));
1771 for (i
= 0; i
< bclist
->count
; i
++) {
1772 printf("BSS Config \"%s\": index %d\n",
1773 bclist
->bsscfgs
[i
].ifname
, bclist
->bsscfgs
[i
].idx
);
1777 /* create a wlX.Y_ifname nvram setting */
1778 for (i
= 1; i
< bclist
->count
; i
++) {
1779 bsscfg
= &bclist
->bsscfgs
[i
];
1780 #if defined(linux) || defined(__ECOS) || defined(__NetBSD__)
1781 strcpy(var
, bsscfg
->ifname
);
1783 nvram_set(strcat_r(bsscfg
->prefix
, "ifname", tmp
), var
);
1786 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
1788 /* If ure_disable is not present or is 1, ure is not enabled;
1789 * that is, if it is present and 0, ure is enabled.
1791 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
1795 /* Enable MBSS mode if appropriate. */
1796 if (!ure_enab
&& strcmp(str
, "psr")) {
1797 #ifndef __CONFIG_USBAP__
1798 WL_IOVAR_SETINT(name
, "mbss", (bclist
->count
>= 1));
1800 WL_IOVAR_SETINT(name
, "mbss", (bclist
->count
>= 2));
1803 WL_IOVAR_SETINT(name
, "mbss", 0);
1806 * Set SSID for each BSS Config
1808 for (i
= 0; i
< bclist
->count
; i
++) {
1809 bsscfg
= &bclist
->bsscfgs
[i
];
1810 strcat_r(bsscfg
->prefix
, "ssid", tmp
);
1811 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
1812 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
1813 ssid
.SSID_len
= sizeof(ssid
.SSID
);
1814 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
), ssid
.SSID_len
);
1815 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1816 "with SSID \"%s\"\n", name
, bsscfg
->idx
,
1817 bsscfg
->ifname
, nvram_safe_get(tmp
));
1818 WL_BSSIOVAR_SET(name
, "ssid", bsscfg
->idx
, &ssid
,
1823 /* Create addresses for VIFs */
1824 if (!ure_enab
&& strcmp(str
, "psr")) {
1825 /* set local bit for our MBSS vif base */
1826 ETHER_SET_LOCALADDR(vif_addr
);
1828 /* construct and set other wlX.Y_hwaddr */
1829 for (i
= 1; i
< max_no_vifs
; i
++) {
1830 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr", unit
, i
);
1831 addr
= nvram_safe_get(tmp
);
1832 if (!strcmp(addr
, "")) {
1833 vif_addr
[5] = (vif_addr
[5] & ~(max_no_vifs
-1))
1834 | ((max_no_vifs
-1) & (vif_addr
[5]+1));
1836 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
, eaddr
));
1840 for (i
= 0; i
< bclist
->count
; i
++) {
1841 bsscfg
= &bclist
->bsscfgs
[i
];
1842 /* Ignore primary */
1843 if (bsscfg
->idx
== 0)
1846 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr", unit
, bsscfg
->idx
);
1847 ether_atoe(nvram_safe_get(tmp
), (unsigned char *)eaddr
);
1848 WL_BSSIOVAR_SET(name
, "cur_etheraddr", bsscfg
->idx
, eaddr
, ETHER_ADDR_LEN
);
1850 } else { /* One of URE or Proxy STA Repeater is enabled */
1851 /* URE/PSR is on, so set wlX.1 hwaddr is same as that of primary interface */
1852 snprintf(tmp
, sizeof(tmp
), "wl%d.1_hwaddr", unit
);
1853 WL_BSSIOVAR_SET(name
, "cur_etheraddr", 1, vif_addr
,
1855 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
, eaddr
));
1858 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1859 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
1860 ap
= (!strcmp(str
, "") || !strcmp(str
, "ap"));
1861 apsta
= (!strcmp(str
, "apsta") ||
1862 ((!strcmp(str
, "sta") || !strcmp(str
, "psr") || !strcmp(str
, "wet")) &&
1863 bclist
->count
> 1));
1864 sta
= (!strcmp(str
, "sta") && bclist
->count
== 1);
1865 wds
= !strcmp(str
, "wds");
1866 wet
= !strcmp(str
, "wet");
1867 mac_spoof
= !strcmp(str
, "mac_spoof");
1868 psta
= !strcmp(str
, "psta");
1869 psr
= !strcmp(str
, "psr");
1871 /* set apsta var first, because APSTA mode takes precedence */
1872 WL_IOVAR_SETINT(name
, "apsta", apsta
);
1875 val
= (ap
|| apsta
|| wds
) ? 1 : 0;
1876 WL_IOCTL(name
, WLC_SET_AP
, &val
, sizeof(val
));
1878 /* Turn WET mode ON or OFF based on selected mode */
1879 WL_IOCTL(name
, WLC_SET_WET
, &wet
, sizeof(wet
));
1883 WL_IOVAR_SETINT(name
, "mac_spoof", 1);
1886 /* For STA configurations, configure association retry time.
1887 * Use specified time (capped), or mode-specific defaults.
1889 if (sta
|| wet
|| apsta
|| psta
|| psr
) {
1890 char *sta_retry_time_name
= "sta_retry_time";
1891 char *assoc_retry_max_name
= "assoc_retry_max";
1897 str
= nvram_safe_get(strcat_r(prefix
, sta_retry_time_name
, tmp
));
1898 WL_IOVAR_SETINT(name
, sta_retry_time_name
, atoi(str
));
1900 /* Set the wlX_assoc_retry_max, but only if one was specified. */
1901 if ((str
= nvram_get(strcat_r(prefix
, assoc_retry_max_name
, tmp
)))) {
1902 WL_IOVAR_SETINT(name
, assoc_retry_max_name
, atoi(str
));
1905 roam
.val
= WLC_ROAM_NEVER_ROAM_TRIGGER
;
1906 roam
.band
= WLC_BAND_ALL
;
1907 WL_IOCTL(name
, WLC_SET_ROAM_TRIGGER
, &roam
, sizeof(roam
));
1910 /* Retain remaining WET effects only if not APSTA */
1913 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1915 if (wet
|| sta
|| psta
|| psr
)
1916 val
= atoi(nvram_safe_get(strcat_r(prefix
, "infra", tmp
)));
1917 WL_IOCTL(name
, WLC_SET_INFRA
, &val
, sizeof(val
));
1919 /* Set DWDS only for AP or STA modes */
1920 for (i
= 0; i
< bclist
->count
; i
++) {
1922 bsscfg
= &bclist
->bsscfgs
[i
];
1924 if (ap
|| sta
|| psta
|| psr
|| (apsta
&& !wet
)) {
1925 strcat_r(bsscfg
->prefix
, "dwds", tmp
);
1926 val
= atoi(nvram_safe_get(tmp
));
1928 WL_BSSIOVAR_SETINT(name
, "dwds", bsscfg
->idx
, val
);
1931 /* Set The AP MAX Associations Limit */
1933 max_assoc
= val
= atoi(nvram_safe_get(strcat_r(prefix
, "maxassoc", tmp
)));
1935 WL_IOVAR_SETINT(name
, "maxassoc", val
);
1936 } else { /* Get value from driver if not in nvram */
1937 WL_IOVAR_GETINT(name
, "maxassoc", &max_assoc
);
1941 WL_IOVAR_SETINT(name
, "mpc", OFF
);
1943 /* Set the Proxy STA or Repeater mode */
1945 WL_IOVAR_SETINT(name
, "psta", PSTA_MODE_PROXY
);
1947 WL_IOVAR_SETINT(name
, "psta", PSTA_MODE_REPEATER
);
1948 val
= atoi(nvram_safe_get(strcat_r(prefix
, "psr_mrpt", tmp
)));
1949 WL_IOVAR_SETINT(name
, "psta_mrpt", val
);
1951 WL_IOVAR_SETINT(name
, "psta", PSTA_MODE_DISABLED
);
1954 /* Turn WET tunnel mode ON or OFF */
1955 if ((ap
|| apsta
) && (wet_tunnel_cap
)) {
1956 if (atoi(nvram_safe_get(strcat_r(prefix
, "wet_tunnel", tmp
))) == 1) {
1957 WL_IOVAR_SETINT(name
, "wet_tunnel", 1);
1958 wet_tunnel_enable
= 1;
1960 WL_IOVAR_SETINT(name
, "wet_tunnel", 0);
1964 for (i
= 0; i
< bclist
->count
; i
++) {
1966 bsscfg
= &bclist
->bsscfgs
[i
];
1968 /* XXXMSSID: The note about setting preauth now does not seem right.
1969 * NAS brings the BSS up if it runs, so setting the preauth value
1970 * will make it in the bcn/prb. If that is right, we can move this
1971 * chunk out of wlconf.
1974 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1975 * if we do it in the NAS we need to bring down the interface and up to make
1976 * it affect in the beacons
1978 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1980 preauth
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "preauth", tmp
));
1981 if (strlen (preauth
) != 0) {
1982 set_preauth
= atoi(preauth
);
1984 wlconf_set_preauth(name
, bsscfg
->idx
, set_preauth
);
1987 /* Clear BRCM System level Capability IE */
1988 memset(&brcm_syscap_ie
, 0, sizeof(brcm_prop_ie_t
));
1989 brcm_syscap_ie
.type
= BRCM_SYSCAP_IE_TYPE
;
1991 /* Add WET TUNNEL to IE */
1992 if (wet_tunnel_enable
)
1993 brcm_syscap_ie
.cap
|= BRCM_SYSCAP_WET_TUNNEL
;
1995 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1997 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1998 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "bss_maxassoc", tmp
)));
2000 WL_BSSIOVAR_SETINT(name
, "bss_maxassoc", bsscfg
->idx
, val
);
2001 } else if (max_assoc
> 0) { /* Set maxassoc same as global if not set */
2002 snprintf(var
, sizeof(var
), "%d", max_assoc
);
2003 nvram_set(tmp
, var
);
2007 /* Set network type */
2008 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "closed", tmp
)));
2009 WL_BSSIOVAR_SETINT(name
, "closednet", bsscfg
->idx
, val
);
2011 /* Set the ap isolate mode */
2012 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "ap_isolate", tmp
)));
2013 WL_BSSIOVAR_SETINT(name
, "ap_isolate", bsscfg
->idx
, val
);
2015 /* Set the WMF enable mode */
2017 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "wmf_bss_enable", tmp
)));
2018 WL_BSSIOVAR_SETINT(name
, "wmf_bss_enable", bsscfg
->idx
, val
);
2020 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
2021 "wmf_psta_disable", tmp
)));
2022 WL_BSSIOVAR_SETINT(name
, "wmf_psta_disable", bsscfg
->idx
, val
);
2025 /* Set the Multicast Reverse Translation enable mode */
2026 if (wet
|| psta
|| psr
) {
2027 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
2028 "mcast_regen_bss_enable", tmp
)));
2029 WL_BSSIOVAR_SETINT(name
, "mcast_regen_bss_enable", bsscfg
->idx
, val
);
2032 if (rxchain_pwrsave
) {
2033 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "rxchain_pwrsave_enable",
2035 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_enable", bsscfg
->idx
, val
);
2037 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
2038 "rxchain_pwrsave_quiet_time", tmp
)));
2039 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_quiet_time", bsscfg
->idx
, val
);
2041 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "rxchain_pwrsave_pps",
2043 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_pps", bsscfg
->idx
, val
);
2045 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
2046 "rxchain_pwrsave_stas_assoc_check", tmp
)));
2047 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_stas_assoc_check", bsscfg
->idx
,
2051 if (radio_pwrsave
) {
2052 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "radio_pwrsave_enable",
2054 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_enable", bsscfg
->idx
, val
);
2056 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
2057 "radio_pwrsave_quiet_time", tmp
)));
2058 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_quiet_time", bsscfg
->idx
, val
);
2060 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "radio_pwrsave_pps",
2062 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_pps", bsscfg
->idx
, val
);
2063 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "radio_pwrsave_level",
2065 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_level", bsscfg
->idx
, val
);
2067 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
2068 "radio_pwrsave_stas_assoc_check", tmp
)));
2069 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_stas_assoc_check", bsscfg
->idx
,
2072 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "aspm", tmp
)));
2073 WL_BSSIOVAR_SETINT(name
, "aspm", bsscfg
->idx
, val
);
2075 /* Configure SYSCAP IE to driver */
2076 if (brcm_syscap_ie
.cap
) {
2077 wlconf_set_brcm_syscap_ie(name
, bsscfg
->idx
,
2078 BRCM_PROP_OUI
, (uchar
*)&(brcm_syscap_ie
.type
),
2079 sizeof(brcm_syscap_ie
.type
) +
2080 sizeof(brcm_syscap_ie
.cap
));
2084 /* Set up the country code */
2085 (void) strcat_r(prefix
, "country_code", tmp
);
2086 country
= nvram_get(tmp
);
2087 (void) strcat_r(prefix
, "country_rev", tmp2
);
2088 country_rev
= nvram_get(tmp2
);
2089 if ((country
&& country
[0] != '\0') && (country_rev
&& country_rev
[0] != '\0')) {
2090 /* Initialize the wl country parameter */
2091 strncpy(country_spec
.country_abbrev
, country
, WLC_CNTRY_BUF_SZ
-1);
2092 country_spec
.country_abbrev
[WLC_CNTRY_BUF_SZ
-1] = '\0';
2093 strncpy(country_spec
.ccode
, country
, WLC_CNTRY_BUF_SZ
-1);
2094 country_spec
.ccode
[WLC_CNTRY_BUF_SZ
-1] = '\0';
2095 country_spec
.rev
= atoi(country_rev
);
2097 WL_IOVAR_SET(name
, "country", &country_spec
, sizeof(country_spec
));
2099 /* Get the default country code if undefined */
2100 wl_iovar_get(name
, "country", &country_spec
, sizeof(country_spec
));
2102 /* Add the new NVRAM variable */
2103 nvram_set("wl_country_code", country_spec
.ccode
);
2104 (void) strcat_r(prefix
, "country_code", tmp
);
2105 nvram_set(tmp
, country_spec
.ccode
);
2106 snprintf(buf
, sizeof(buf
), "%d", country_spec
.rev
);
2107 nvram_set("wl_country_rev", buf
);
2108 (void) strcat_r(prefix
, "country_rev", tmp
);
2109 nvram_set(tmp
, buf
);
2112 /* Change LED Duty Cycle */
2113 leddc
= (uint32
)strtoul(nvram_safe_get(strcat_r(prefix
, "leddc", tmp
)), NULL
, 16);
2115 WL_IOVAR_SETINT(name
, "leddc", leddc
);
2117 /* Enable or disable the radio */
2118 val
= nvram_match(strcat_r(prefix
, "radio", tmp
), "0");
2119 val
+= WL_RADIO_SW_DISABLE
<< 16;
2120 WL_IOCTL(name
, WLC_SET_RADIO
, &val
, sizeof(val
));
2122 /* Get supported phy types */
2123 WL_IOCTL(name
, WLC_GET_PHYLIST
, var
, sizeof(var
));
2124 nvram_set(strcat_r(prefix
, "phytypes", tmp
), var
);
2127 *(next
= buf
) = '\0';
2128 for (i
= 0; i
< strlen(var
); i
++) {
2129 /* Switch to band */
2130 val
= WLCONF_STR2PHYTYPE(var
[i
]);
2131 if (WLCONF_PHYTYPE_11N(val
)) {
2132 WL_GETINT(name
, WLC_GET_BAND
, &val
);
2134 val
= WLCONF_PHYTYPE2BAND(val
);
2135 WL_IOCTL(name
, WLC_SET_BAND
, &val
, sizeof(val
));
2136 /* Get radio ID on this band */
2137 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
2138 next
+= sprintf(next
, "%sBCM%X", i
? " " : "",
2139 (rev
.radiorev
& IDCODE_ID_MASK
) >> IDCODE_ID_SHIFT
);
2141 nvram_set(strcat_r(prefix
, "radioids", tmp
), buf
);
2144 str
= nvram_get(strcat_r(prefix
, "phytype", tmp
));
2145 val
= str
? WLCONF_STR2PHYTYPE(str
[0]) : PHY_TYPE_G
;
2146 /* For NPHY use band value from NVRAM */
2147 if (WLCONF_PHYTYPE_11N(val
)) {
2148 str
= nvram_get(strcat_r(prefix
, "nband", tmp
));
2152 WL_GETINT(name
, WLC_GET_BAND
, &val
);
2155 val
= WLCONF_PHYTYPE2BAND(val
);
2157 WL_SETINT(name
, WLC_SET_BAND
, val
);
2159 /* Check errors (card may have changed) */
2161 /* default band to the first band in band list */
2162 val
= WLCONF_STR2PHYTYPE(var
[0]);
2163 val
= WLCONF_PHYTYPE2BAND(val
);
2164 WL_SETINT(name
, WLC_SET_BAND
, val
);
2167 /* Store the resolved bandtype */
2170 /* Check errors again (will cover 5Ghz-only cards) */
2174 /* default band to the first band in band list */
2175 wl_ioctl(name
, WLC_GET_BANDLIST
, list
, sizeof(list
));
2176 WL_SETINT(name
, WLC_SET_BAND
, list
[1]);
2178 /* Read it back, and set bandtype accordingly */
2179 WL_GETINT(name
, WLC_GET_BAND
, &bandtype
);
2182 /* Get current core revision */
2183 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
2184 snprintf(buf
, sizeof(buf
), "%d", rev
.corerev
);
2185 nvram_set(strcat_r(prefix
, "corerev", tmp
), buf
);
2187 if ((rev
.chipnum
== BCM4716_CHIP_ID
) || (rev
.chipnum
== BCM47162_CHIP_ID
) ||
2188 (rev
.chipnum
== BCM4748_CHIP_ID
) || (rev
.chipnum
== BCM4331_CHIP_ID
) ||
2189 (rev
.chipnum
== BCM43431_CHIP_ID
) || (rev
.chipnum
== BCM5357_CHIP_ID
) ||
2190 (rev
.chipnum
== BCM53572_CHIP_ID
) || (rev
.chipnum
== BCM43236_CHIP_ID
)) {
2191 int pam_mode
= WLC_N_PREAMBLE_GF_BRCM
; /* default GF-BRCM */
2193 strcat_r(prefix
, "mimo_preamble", tmp
);
2194 if (nvram_match(tmp
, "mm"))
2195 pam_mode
= WLC_N_PREAMBLE_MIXEDMODE
;
2196 else if (nvram_match(tmp
, "gf"))
2197 pam_mode
= WLC_N_PREAMBLE_GF
;
2198 else if (nvram_match(tmp
, "auto"))
2200 WL_IOVAR_SETINT(name
, "mimo_preamble", pam_mode
);
2203 if ((rev
.chipnum
== BCM5357_CHIP_ID
) || (rev
.chipnum
== BCM53572_CHIP_ID
)) {
2204 val
= atoi(nvram_safe_get("coma_sleep"));
2206 struct {int sleep
; int delay
;} setbuf
;
2207 nvram_unset("coma_sleep");
2211 WL_IOVAR_SET(name
, "coma", &setbuf
, sizeof(setbuf
));
2215 /* Get current phy type */
2216 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
2217 snprintf(buf
, sizeof(buf
), "%s", WLCONF_PHYTYPE2STR(phytype
));
2218 nvram_set(strcat_r(prefix
, "phytype", tmp
), buf
);
2220 /* Setup regulatory mode */
2221 strcat_r(prefix
, "reg_mode", tmp
);
2222 if (nvram_match(tmp
, "off")) {
2224 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
2225 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
2226 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
2227 } else if (nvram_match(tmp
, "h") || nvram_match(tmp
, "strict_h")) {
2229 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
2231 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
2233 if (nvram_match(tmp
, "h"))
2237 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
2239 /* Set the CAC parameters, if they exist in nvram. */
2240 if ((str
= nvram_get(strcat_r(prefix
, "dfs_preism", tmp
)))) {
2242 wl_iovar_setint(name
, "dfs_preism", val
);
2244 if ((str
= nvram_get(strcat_r(prefix
, "dfs_postism", tmp
)))) {
2246 wl_iovar_setint(name
, "dfs_postism", val
);
2248 val
= atoi(nvram_safe_get(strcat_r(prefix
, "tpc_db", tmp
)));
2249 WL_IOCTL(name
, WLC_SEND_PWR_CONSTRAINT
, &val
, sizeof(val
));
2251 } else if (nvram_match(tmp
, "d")) {
2253 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
2254 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
2256 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
2259 /* set bandwidth capability for nphy and calculate nbw */
2260 if (WLCONF_PHYTYPE_11N(phytype
)) {
2266 /* Get the user nmode setting now */
2267 nmode
= AUTO
; /* enable by default for NPHY */
2269 strcat_r(prefix
, "nmode", tmp
);
2270 if (nvram_match(tmp
, "0"))
2273 WL_IOVAR_SETINT(name
, "nmode", (uint32
)nmode
);
2276 val
= WLC_BW_CAP_20MHZ
;
2278 val
= wlconf_bw_cap(prefix
, bandtype
);
2280 /* record the bw here */
2281 if (val
== WLC_BW_CAP_80MHZ
)
2282 nbw
= WL_CHANSPEC_BW_80
;
2283 else if (val
== WLC_BW_CAP_40MHZ
)
2284 nbw
= WL_CHANSPEC_BW_40
;
2286 param
.bandtype
= bandtype
;
2287 param
.bw_cap
= (uint8
) val
;
2289 WL_IOVAR_SET(name
, "bw_cap", ¶m
, sizeof(param
));
2291 /* Save n mode to OFF */
2292 nvram_set(strcat_r(prefix
, "nmode", tmp
), "0");
2295 /* Use chanspec to set the channel */
2296 if ((str
= nvram_get(strcat_r(prefix
, "chanspec", tmp
))) != NULL
) {
2297 chanspec
= wf_chspec_aton(str
);
2300 WL_IOVAR_SETINT(name
, "chanspec", (uint32
)chanspec
);
2304 /* Legacy method of setting channels (for compatibility) */
2305 /* Set channel before setting gmode or rateset */
2306 /* Manual Channel Selection - when channel # is not 0 */
2307 val
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
)));
2308 if ((chanspec
== 0) && val
&& !WLCONF_PHYTYPE_11N(phytype
)) {
2309 WL_SETINT(name
, WLC_SET_CHANNEL
, val
);
2311 /* Use current channel (card may have changed) */
2312 WL_IOCTL(name
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
2313 snprintf(buf
, sizeof(buf
), "%d", ci
.target_channel
);
2314 nvram_set(strcat_r(prefix
, "channel", tmp
), buf
);
2316 } else if ((chanspec
== 0) && val
&& WLCONF_PHYTYPE_11N(phytype
)) {
2319 uint cspecbw
= (bandtype
== WLC_BAND_2G
) ?
2320 WL_CHANSPEC_BAND_2G
:WL_CHANSPEC_BAND_5G
;
2324 if (nbw
== WL_CHANSPEC_BW_80
) {
2325 /* Get Ctrl SB for 80MHz channel */
2326 str
= nvram_safe_get(strcat_r(prefix
, "nctrlsb", tmp
));
2328 /* Adjust the channel to be center channel */
2329 channel
= channel
+ CH_40MHZ_APART
- CH_10MHZ_APART
;
2331 if (!strcmp(str
, "ll")) {
2332 nctrlsb
= WL_CHANSPEC_CTL_SB_LL
;
2333 } else if (!strcmp(str
, "lu")) {
2334 nctrlsb
= WL_CHANSPEC_CTL_SB_LU
;
2335 channel
-= CH_20MHZ_APART
;
2336 } else if (!strcmp(str
, "ul")) {
2337 nctrlsb
= WL_CHANSPEC_CTL_SB_UL
;
2338 channel
-= 2 * CH_20MHZ_APART
;
2339 } else if (!strcmp(str
, "uu")) {
2340 nctrlsb
= WL_CHANSPEC_CTL_SB_UU
;
2341 channel
-= 3 * CH_20MHZ_APART
;
2344 } else if (nbw
== WL_CHANSPEC_BW_40
) {
2345 /* Get Ctrl SB for 40MHz channel */
2346 str
= nvram_safe_get(strcat_r(prefix
, "nctrlsb", tmp
));
2348 /* Adjust the channel to be center channel */
2349 if (!strcmp(str
, "lower")) {
2350 nctrlsb
= WL_CHANSPEC_CTL_SB_LOWER
;
2351 channel
= channel
+ 2;
2352 } else if (!strcmp(str
, "upper")) {
2353 nctrlsb
= WL_CHANSPEC_CTL_SB_UPPER
;
2354 channel
= channel
- 2;
2358 /* band | BW | CTRL SB | Channel */
2359 chanspec
|= (cspecbw
| nbw
| nctrlsb
| channel
);
2360 WL_IOVAR_SETINT(name
, "chanspec", (uint32
)chanspec
);
2363 /* Set up number of Tx and Rx streams */
2364 if (WLCONF_PHYTYPE_11N(phytype
)) {
2368 /* Get the number of tx chains supported by the hardware */
2369 wl_iovar_getint(name
, "hw_txchain", &count
);
2370 /* update NVRAM with capabilities */
2371 snprintf(var
, sizeof(var
), "%d", count
);
2372 nvram_set(strcat_r(prefix
, "hw_txchain", tmp
), var
);
2374 /* Verify that there is an NVRAM param for txstreams, if not create it and
2375 * set it to hw_txchain
2377 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "txchain", tmp
)));
2379 /* invalid - NVRAM needs to be fixed/initialized */
2380 nvram_set(strcat_r(prefix
, "txchain", tmp
), var
);
2383 /* Apply user configured txstreams, use 1 if user disabled nmode */
2384 WL_IOVAR_SETINT(name
, "txchain", streams
);
2386 wl_iovar_getint(name
, "hw_rxchain", &count
);
2387 /* update NVRAM with capabilities */
2388 snprintf(var
, sizeof(var
), "%d", count
);
2389 nvram_set(strcat_r(prefix
, "hw_rxchain", tmp
), var
);
2391 /* Verify that there is an NVRAM param for rxstreams, if not create it and
2392 * set it to hw_txchain
2394 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "rxchain", tmp
)));
2396 /* invalid - NVRAM needs to be fixed/initialized */
2397 nvram_set(strcat_r(prefix
, "rxchain", tmp
), var
);
2401 /* Apply user configured rxstreams, use 1 if user disabled nmode */
2402 WL_IOVAR_SETINT(name
, "rxchain", streams
);
2405 /* Reset to hardware rateset (band may have changed) */
2406 WL_IOCTL(name
, WLC_GET_RATESET
, &rs
, sizeof(wl_rateset_t
));
2407 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
2410 if (bandtype
== WLC_BAND_2G
) {
2411 int override
= WLC_PROTECTION_OFF
;
2412 int control
= WLC_PROTECTION_CTL_OFF
;
2415 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", tmp
)));
2416 WL_IOCTL(name
, WLC_SET_GMODE
, &gmode
, sizeof(gmode
));
2418 /* Set gmode protection override and control algorithm */
2419 strcat_r(prefix
, "gmode_protection", tmp
);
2420 if (nvram_match(tmp
, "auto")) {
2421 override
= WLC_PROTECTION_AUTO
;
2422 control
= WLC_PROTECTION_CTL_OVERLAP
;
2424 WL_IOCTL(name
, WLC_SET_GMODE_PROTECTION_OVERRIDE
, &override
, sizeof(override
));
2425 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
2428 /* Set nmode_protection */
2429 if (WLCONF_PHYTYPE_11N(phytype
)) {
2430 int override
= WLC_PROTECTION_OFF
;
2431 int control
= WLC_PROTECTION_CTL_OFF
;
2433 /* Set n protection override and control algorithm */
2434 str
= nvram_get(strcat_r(prefix
, "nmode_protection", tmp
));
2435 if (!str
|| !strcmp(str
, "auto")) {
2436 override
= WLC_PROTECTION_AUTO
;
2437 control
= WLC_PROTECTION_CTL_OVERLAP
;
2440 WL_IOVAR_SETINT(name
, "nmode_protection_override",
2442 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
2445 /* Set vlan_prio_mode */
2447 uint32 mode
= OFF
; /* default */
2449 strcat_r(prefix
, "vlan_prio_mode", tmp
);
2451 if (nvram_match(tmp
, "on"))
2454 WL_IOVAR_SETINT(name
, "vlan_mode", mode
);
2457 /* Get bluetooth coexistance(BTC) mode */
2458 btc_mode
= atoi(nvram_safe_get(strcat_r(prefix
, "btc_mode", tmp
)));
2460 /* Set the AMPDU and AMSDU options based on the N-mode */
2461 wme_global
= wlconf_ampdu_amsdu_set(name
, prefix
, nmode
, btc_mode
, ap
);
2463 /* Now that wme_global is known, check per-BSS disable settings */
2464 for (i
= 0; i
< bclist
->count
; i
++) {
2466 bsscfg
= &bclist
->bsscfgs
[i
];
2468 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
2470 /* For each BSS, check WME; make sure wme is set properly for this interface */
2471 strcat_r(subprefix
, "wme", tmp
);
2472 nvram_set(tmp
, wme_global
? "on" : "off");
2474 str
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "wme_bss_disable", tmp
));
2475 val
= (str
[0] == '1') ? 1 : 0;
2476 WL_BSSIOVAR_SETINT(name
, "wme_bss_disable", bsscfg
->idx
, val
);
2480 * Set operational capabilities required for stations
2481 * to associate to the BSS. Per-BSS setting.
2483 for (i
= 0; i
< bclist
->count
; i
++) {
2484 bsscfg
= &bclist
->bsscfgs
[i
];
2485 str
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "bss_opmode_cap_reqd", tmp
));
2487 WL_BSSIOVAR_SETINT(name
, "mode_reqd", bsscfg
->idx
, val
);
2491 /* Get current rateset (gmode may have changed) */
2492 WL_IOCTL(name
, WLC_GET_CURR_RATESET
, &rs
, sizeof(wl_rateset_t
));
2494 strcat_r(prefix
, "rateset", tmp
);
2495 if (nvram_match(tmp
, "all")) {
2496 /* Make all rates basic */
2497 for (i
= 0; i
< rs
.count
; i
++)
2498 rs
.rates
[i
] |= 0x80;
2499 } else if (nvram_match(tmp
, "12")) {
2500 /* Make 1 and 2 basic */
2501 for (i
= 0; i
< rs
.count
; i
++) {
2502 if ((rs
.rates
[i
] & 0x7f) == 2 || (rs
.rates
[i
] & 0x7f) == 4)
2503 rs
.rates
[i
] |= 0x80;
2505 rs
.rates
[i
] &= ~0x80;
2509 if (phytype
!= PHY_TYPE_SSN
&& phytype
!= PHY_TYPE_LCN
) {
2511 if (!wl_iovar_setint(name
, "btc_mode", btc_mode
)) {
2512 if (btc_mode
== WL_BTC_PREMPT
) {
2513 wl_rateset_t rs_tmp
= rs
;
2514 /* remove 1Mbps and 2 Mbps from rateset */
2515 for (i
= 0, rs
.count
= 0; i
< rs_tmp
.count
; i
++) {
2516 if ((rs_tmp
.rates
[i
] & 0x7f) == 2 ||
2517 (rs_tmp
.rates
[i
] & 0x7f) == 4)
2519 rs
.rates
[rs
.count
++] = rs_tmp
.rates
[i
];
2526 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
2528 /* Allow short preamble settings for the following:
2530 * 11g - short /long in GMODE_LEGACY_B and GMODE_AUTO gmodes
2531 * GMODE_PERFORMANCE and GMODE_LRS will use short and long
2532 * preambles respectively, by default
2533 * 11n - short/long applicable in 2.4G band only
2535 if (phytype
== PHY_TYPE_B
||
2536 (WLCONF_PHYTYPE_11N(phytype
) && (bandtype
== WLC_BAND_2G
)) ||
2537 ((phytype
== PHY_TYPE_G
|| phytype
== PHY_TYPE_LP
) &&
2538 (gmode
== GMODE_LEGACY_B
|| gmode
== GMODE_AUTO
))) {
2539 strcat_r(prefix
, "plcphdr", tmp
);
2540 if (nvram_match(tmp
, "long"))
2541 val
= WLC_PLCP_AUTO
;
2543 val
= WLC_PLCP_SHORT
;
2544 WL_IOCTL(name
, WLC_SET_PLCPHDR
, &val
, sizeof(val
));
2547 /* Set rate in 500 Kbps units */
2548 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rate", tmp
))) / 500000;
2550 /* Convert Auto mcsidx to Auto rate */
2551 if (WLCONF_PHYTYPE_11N(phytype
)) {
2552 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
2554 /* -1 mcsidx used to designate AUTO rate */
2559 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
2560 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
2561 /* Must b/g band. Set to 5.5Mbps */
2564 /* it is band-blind. try both band */
2565 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
2566 error_a
= wl_iovar_setint(name
, "a_rate", val
);
2568 if (error_bg
&& error_a
) {
2569 /* both failed. Try default rate (card may have changed) */
2572 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
2573 error_a
= wl_iovar_setint(name
, "a_rate", val
);
2575 snprintf(buf
, sizeof(buf
), "%d", val
);
2576 nvram_set(strcat_r(prefix
, "rate", tmp
), buf
);
2579 /* check if nrate needs to be applied */
2582 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
2583 bool ismcs
= (mcsidx
>= 0);
2585 /* mcsidx of 32 is valid only for 40 Mhz */
2586 if (mcsidx
== 32 && nbw
== WL_CHANSPEC_BW_20
) {
2589 nvram_set(strcat_r(prefix
, "nmcsidx", tmp
), "-1");
2592 /* Use nrate iovar only for MCS rate. */
2594 nrate
|= WL_RSPEC_ENCODE_HT
;
2595 nrate
|= mcsidx
& WL_RSPEC_RATE_MASK
;
2597 WL_IOVAR_SETINT(name
, "nrate", nrate
);
2601 /* Set multicast rate in 500 Kbps units */
2602 val
= atoi(nvram_safe_get(strcat_r(prefix
, "mrate", tmp
))) / 500000;
2603 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
2604 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
2605 /* Must b/g band. Set to 5.5Mbps */
2608 /* it is band-blind. try both band */
2609 error_bg
= wl_iovar_setint(name
, "bg_mrate", val
);
2610 error_a
= wl_iovar_setint(name
, "a_mrate", val
);
2612 if (error_bg
&& error_a
) {
2613 /* Try default rate (card may have changed) */
2616 wl_iovar_setint(name
, "bg_mrate", val
);
2617 wl_iovar_setint(name
, "a_mrate", val
);
2619 snprintf(buf
, sizeof(buf
), "%d", val
);
2620 nvram_set(strcat_r(prefix
, "mrate", tmp
), buf
);
2623 /* Set fragmentation threshold */
2624 val
= atoi(nvram_safe_get(strcat_r(prefix
, "frag", tmp
)));
2625 wl_iovar_setint(name
, "fragthresh", val
);
2627 /* Set RTS threshold */
2628 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rts", tmp
)));
2629 wl_iovar_setint(name
, "rtsthresh", val
);
2631 /* Set DTIM period */
2632 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dtim", tmp
)));
2633 WL_IOCTL(name
, WLC_SET_DTIMPRD
, &val
, sizeof(val
));
2635 /* Set beacon period */
2636 val
= atoi(nvram_safe_get(strcat_r(prefix
, "bcn", tmp
)));
2637 WL_IOCTL(name
, WLC_SET_BCNPRD
, &val
, sizeof(val
));
2639 /* Set beacon rotation */
2640 str
= nvram_get(strcat_r(prefix
, "bcn_rotate", tmp
));
2642 /* No nvram variable found, use the default */
2643 str
= nvram_default_get(strcat_r(prefix
, "bcn_rotate", tmp
));
2646 wl_iovar_setint(name
, "bcn_rotate", val
);
2648 /* Set framebursting mode */
2649 if (btc_mode
== WL_BTC_PREMPT
)
2652 val
= nvram_match(strcat_r(prefix
, "frameburst", tmp
), "on");
2653 WL_IOCTL(name
, WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
2655 /* Set dynamic frameburst max station limit */
2656 str
= nvram_get(strcat_r(prefix
, "frameburst_dyn_max_stations", tmp
));
2657 if (!str
) { /* Fall back to previous name, frameburst_dyn */
2658 str
= nvram_safe_get("frameburst_dyn");
2660 wl_iovar_setint(name
, "frameburst_dyn_max_stations", atoi(str
));
2662 /* Set STBC tx and rx mode */
2663 if (phytype
== PHY_TYPE_N
||
2664 phytype
== PHY_TYPE_HT
||
2665 phytype
== PHY_TYPE_AC
) {
2666 char *nvram_str
= nvram_safe_get(strcat_r(prefix
, "stbc_tx", tmp
));
2668 if (!strcmp(nvram_str
, "auto")) {
2669 WL_IOVAR_SETINT(name
, "stbc_tx", AUTO
);
2670 } else if (!strcmp(nvram_str
, "on")) {
2671 WL_IOVAR_SETINT(name
, "stbc_tx", ON
);
2672 } else if (!strcmp(nvram_str
, "off")) {
2673 WL_IOVAR_SETINT(name
, "stbc_tx", OFF
);
2675 val
= atoi(nvram_safe_get(strcat_r(prefix
, "stbc_rx", tmp
)));
2676 WL_IOVAR_SETINT(name
, "stbc_rx", val
);
2679 /* Set RIFS mode based on framebursting */
2680 if (WLCONF_PHYTYPE_11N(phytype
)) {
2681 char *nvram_str
= nvram_safe_get(strcat_r(prefix
, "rifs", tmp
));
2682 if (!strcmp(nvram_str
, "on"))
2683 wl_iovar_setint(name
, "rifs", ON
);
2684 else if (!strcmp(nvram_str
, "off"))
2685 wl_iovar_setint(name
, "rifs", OFF
);
2687 /* RIFS mode advertisement */
2688 nvram_str
= nvram_safe_get(strcat_r(prefix
, "rifs_advert", tmp
));
2689 if (!strcmp(nvram_str
, "auto"))
2690 wl_iovar_setint(name
, "rifs_advert", AUTO
);
2691 else if (!strcmp(nvram_str
, "off"))
2692 wl_iovar_setint(name
, "rifs_advert", OFF
);
2695 /* Override BA mode only if set to on/off */
2696 ba
= nvram_safe_get(strcat_r(prefix
, "ba", tmp
));
2697 if (!strcmp(ba
, "on"))
2698 wl_iovar_setint(name
, "ba", ON
);
2699 else if (!strcmp(ba
, "off"))
2700 wl_iovar_setint(name
, "ba", OFF
);
2702 if (WLCONF_PHYTYPE_11N(phytype
)) {
2703 val
= AVG_DMA_XFER_RATE
;
2704 wl_iovar_set(name
, "avg_dma_xfer_rate", &val
, sizeof(val
));
2708 * If no nvram variable exists to force non-aggregated mpdu regulation on/off,
2709 * limit to 2G interfaces.
2711 str
= nvram_get(strcat_r(prefix
, "nar", tmp
));
2715 val
= (bandtype
== WLC_BAND_2G
) ? 1 : 0;
2717 WLCONF_DBG("%sabling non-aggregated regulation on band %d\n", (val
) ? "En":"Dis", bandtype
);
2718 WL_IOVAR_SETINT(name
, "nar", val
);
2720 /* nar is enabled on this interface, add tuneable parameters */
2721 str
= nvram_get(strcat_r(prefix
, "nar_handle_ampdu", tmp
));
2723 WL_IOVAR_SETINT(name
, "nar_handle_ampdu", atoi(str
));
2725 str
= nvram_get(strcat_r(prefix
, "nar_transit_limit", tmp
));
2727 WL_IOVAR_SETINT(name
, "nar_transit_limit", atoi(str
));
2732 wlconf_set_txbf(name
, prefix
);
2734 /* set airtime fairness */
2736 str
= nvram_get(strcat_r(prefix
, "atf", tmp
));
2740 WL_IOVAR_SETINT(name
, "atf", val
);
2742 str
= nvram_get(strcat_r(prefix
, "ampdu_atf_us", tmp
));
2746 WL_IOVAR_SETINT(name
, "ampdu_atf_us", val
);
2747 WL_IOVAR_SETINT(name
, "nar_atf_us", val
);
2753 str
= nvram_get(strcat_r(prefix
, "taf_enable", tmp
));
2754 if (str
&& (bandtype
== WLC_BAND_5G
)) {
2757 WL_IOVAR_SETINT(name
, "taf", val
);
2760 str
= nvram_get(strcat_r(prefix
, "taf_rule", tmp
));
2762 val
= strtoul(str
, NULL
, 0);
2763 WL_IOVAR_SETINT(name
, "taf_rule", val
);
2766 /* Bring the interface back up */
2767 WL_IOCTL(name
, WLC_UP
, NULL
, 0);
2769 /* set ebos, interface must be up */
2771 str
= nvram_get(strcat_r(prefix
, "ebos_enable", tmp
));
2775 WL_IOVAR_SETINT(name
, "ebos_enable", val
);
2778 str
= nvram_get(strcat_r(prefix
, "ebos_flags", tmp
));
2780 val
= strtoul(str
, NULL
, 0);
2781 WL_IOVAR_SETINT(name
, "ebos_flags", val
);
2785 str
= nvram_get(strcat_r(prefix
, "ebos_prr_threshold", tmp
));
2787 val
= strtoul(str
, NULL
, 0);
2788 WL_IOVAR_SETINT(name
, "ebos_prr_threshold", val
);
2792 str
= nvram_get(strcat_r(prefix
, "ebos_prr_flags", tmp
));
2794 val
= strtoul(str
, NULL
, 0);
2795 WL_IOVAR_SETINT(name
, "ebos_prr_flags", val
);
2799 str
= nvram_get(strcat_r(prefix
, "ebos_prr_transit", tmp
));
2801 val
= strtol(str
, NULL
, 0);
2802 WL_IOVAR_SETINT(name
, "ebos_prr_transit", val
);
2806 str
= nvram_get(strcat_r(prefix
, "ebos_transit", tmp
));
2808 val
= strtol(str
, NULL
, 0);
2809 WL_IOVAR_SETINT(name
, "ebos_transit", val
);
2812 /* set phy_percal_delay */
2813 val
= atoi(nvram_safe_get(strcat_r(prefix
, "percal_delay", tmp
)));
2815 wl_iovar_set(name
, "phy_percal_delay", &val
, sizeof(val
));
2818 /* Set phy periodic cal if nvram present. Otherwise, use driver defaults. */
2819 str
= nvram_get(strcat_r(prefix
, "cal_period", tmp
));
2821 /* user specified phy cal period. */
2823 WL_IOVAR_SET(name
, "cal_period", &val
, sizeof(val
));
2827 val
= atoi(nvram_safe_get(strcat_r(prefix
, "antdiv", tmp
)));
2828 WL_IOCTL(name
, WLC_SET_ANTDIV
, &val
, sizeof(val
));
2830 /* Set antenna selection */
2831 wlconf_set_antsel(name
, prefix
);
2833 /* Set radar parameters if it is enabled */
2835 wlconf_set_radarthrs(name
, prefix
);
2841 /* Set pspretend for multi-ssid bss */
2842 for (i
= 0; i
< bclist
->count
; i
++) {
2843 bsscfg
= &bclist
->bsscfgs
[i
];
2844 str
= nvram_safe_get(strcat_r(bsscfg
->prefix
,
2845 "pspretend_retry_limit", tmp
));
2848 WL_BSSIOVAR_SETINT(name
, "pspretend_retry_limit", bsscfg
->idx
, val
);
2852 /* now set it for primary bss */
2854 str
= nvram_get(strcat_r(prefix
, "pspretend_retry_limit", tmp
));
2859 WL_IOVAR_SETINT(name
, "pspretend_retry_limit", val
);
2863 str
= nvram_get(strcat_r(prefix
, "pspretend_threshold", tmp
));
2868 WL_IOVAR_SETINT(name
, "pspretend_threshold", val
);
2870 /* Set channel interference threshold value if it is enabled */
2872 str
= nvram_get(strcat_r(prefix
, "glitchthres", tmp
));
2875 int glitch_thres
= atoi(str
);
2876 if (glitch_thres
> 0)
2877 WL_IOVAR_SETINT(name
, "chanim_glitchthres", glitch_thres
);
2880 str
= nvram_get(strcat_r(prefix
, "ccathres", tmp
));
2883 int cca_thres
= atoi(str
);
2885 WL_IOVAR_SETINT(name
, "chanim_ccathres", cca_thres
);
2888 str
= nvram_get(strcat_r(prefix
, "chanimmode", tmp
));
2891 int chanim_mode
= atoi(str
);
2892 if (chanim_mode
>= 0)
2893 WL_IOVAR_SETINT(name
, "chanim_mode", chanim_mode
);
2896 /* bcm_dcs (dynamic channel selection) settings */
2897 str
= nvram_safe_get(strcat_r(prefix
, "bcmdcs", tmp
));
2898 if (!strcmp(str
, "on"))
2899 wl_iovar_setint(name
, "bcm_dcs", ON
);
2900 else if (!strcmp(str
, "off"))
2901 wl_iovar_setint(name
, "bcm_dcs", OFF
);
2903 /* Overlapping BSS Coexistence aka 20/40 Coex. aka OBSS Coex.
2904 * For an AP - Only use if 2G band AND user wants a 40Mhz chanspec.
2905 * For a STA - Always
2907 if (WLCONF_PHYTYPE_11N(phytype
)) {
2909 ((ap
|| apsta
) && (nbw
== WL_CHANSPEC_BW_40
) && (bandtype
== WLC_BAND_2G
))) {
2910 str
= nvram_safe_get(strcat_r(prefix
, "obss_coex", tmp
));
2912 /* No nvram variable found, use the default */
2913 str
= nvram_default_get(strcat_r(prefix
, "obss_coex", tmp
));
2915 obss_coex
= atoi(str
);
2917 /* Need to disable obss coex in case of 20MHz and/or
2923 /* force coex off for msgtest build */
2926 WL_IOVAR_SETINT(name
, "obss_coex", obss_coex
);
2929 /* Set up TxBF timer */
2930 wlconf_set_txbf_timer(name
, prefix
);
2932 /* Auto Channel Selection:
2933 * 1. When channel # is 0 in AP mode, this determines our channel and 20Mhz vs. 40Mhz
2934 * 2. If we're running OBSS Coex and the user specified a channel, Autochannel runs to
2935 * do an initial scan to help us make decisions about whether we can create a 40Mhz AP
2937 /* The following condition(s) must be met in order for Auto Channel Selection to work.
2938 * - the I/F must be up for the channel scan
2939 * - the AP must not be supporting a BSS (all BSS Configs must be disabled)
2942 int channel
= chanspec
? wf_chspec_ctlchan(chanspec
) : 0;
2948 str_val
= nvram_safe_get("acs_mode");
2949 if (!strcmp(str_val
, "legacy"))
2952 snprintf(tmp
, sizeof(tmp
), "acs_ifnames");
2953 ptr
= nvram_get(tmp
);
2955 snprintf(buf
, sizeof(buf
), "%s %s", ptr
, name
);
2957 strncpy(buf
, name
, sizeof(buf
));
2958 nvram_set(tmp
, buf
);
2959 WL_IOVAR_SETINT(name
, "chanim_mode", CHANIM_EXT
);
2963 #endif /* EXT_ACS */
2964 if (obss_coex
|| channel
== 0) {
2965 if (WLCONF_PHYTYPE_11N(phytype
)) {
2966 chanspec_t chanspec
;
2970 /* assumes that initial chanspec has been set earlier */
2971 /* Maybe we expand scope of chanspec from above so
2972 * that we don't have to do the iovar_get here?
2975 /* We're not doing auto-channel, give the driver
2976 * the preferred chanspec.
2978 WL_IOVAR_GETINT(name
, "chanspec", &pref_chspec
);
2979 WL_IOVAR_SETINT(name
, "pref_chanspec", pref_chspec
);
2981 WL_IOVAR_SETINT(name
, "pref_chanspec", 0);
2984 chanspec
= wlconf_auto_chanspec(name
);
2986 WL_IOVAR_SETINT(name
, "chanspec", chanspec
);
2988 /* select a channel */
2989 val
= wlconf_auto_channel(name
);
2990 /* switch to the selected channel */
2992 WL_IOCTL(name
, WLC_SET_CHANNEL
, &val
, sizeof(val
));
2994 /* set the auto channel scan timer in the driver when in auto mode */
2996 val
= 15; /* 15 minutes for now */
3001 /* reset the channel scan timer in the driver when not in auto mode */
3005 WL_IOCTL(name
, WLC_SET_CS_SCAN_TIMER
, &val
, sizeof(val
));
3006 WL_IOVAR_SETINT(name
, "chanim_mode", CHANIM_ACT
);
3010 #endif /* EXT_ACS */
3011 /* Apply sta_config configuration settings for this interface */
3012 foreach(var
, nvram_safe_get("sta_config"), next
) {
3013 wlconf_process_sta_config_entry(name
, var
);
3018 /* Security settings for each BSS Configuration */
3019 for (i
= 0; i
< bclist
->count
; i
++) {
3020 bsscfg
= &bclist
->bsscfgs
[i
];
3021 wlconf_security_options(name
, bsscfg
->prefix
, bsscfg
->idx
,
3022 mac_spoof
, wet
|| sta
|| apsta
|| psta
|| psr
);
3026 * Finally enable BSS Configs or Join BSS
3028 * AP: Enable BSS Config to bring AP up only when nas will not run
3029 * STA: Join the BSS regardless.
3031 for (i
= 0; i
< bclist
->count
; i
++) {
3032 struct {int bsscfg_idx
; int enable
;} setbuf
;
3033 char vifname
[VIFNAME_LEN
];
3034 char *name_ptr
= name
;
3036 setbuf
.bsscfg_idx
= bclist
->bsscfgs
[i
].idx
;
3039 bsscfg
= &bclist
->bsscfgs
[i
];
3040 if (nvram_match(strcat_r(bsscfg
->prefix
, "bss_enabled", tmp
), "1")) {
3044 /* Set the MAC list */
3045 maclist
= (struct maclist
*)buf
;
3047 if (!nvram_match(strcat_r(bsscfg
->prefix
, "macmode", tmp
), "disabled")) {
3049 foreach(var
, nvram_safe_get(strcat_r(bsscfg
->prefix
, "maclist", tmp
)),
3051 if (((char *)((&ea
[1])->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
3053 if (ether_atoe(var
, ea
->octet
)) {
3060 if (setbuf
.bsscfg_idx
== 0) {
3062 } else { /* Non-primary BSS; changes name syntax */
3063 char tmp
[VIFNAME_LEN
];
3066 /* Remove trailing _ if present */
3067 memset(tmp
, 0, sizeof(tmp
));
3068 strncpy(tmp
, bsscfg
->prefix
, VIFNAME_LEN
- 1);
3069 if (((len
= strlen(tmp
)) > 0) && (tmp
[len
- 1] == '_')) {
3072 nvifname_to_osifname(tmp
, vifname
, VIFNAME_LEN
);
3076 WL_IOCTL(name_ptr
, WLC_SET_MACLIST
, buf
, sizeof(buf
));
3078 /* Set macmode for each VIF */
3079 (void) strcat_r(bsscfg
->prefix
, "macmode", tmp
);
3081 if (nvram_match(tmp
, "deny"))
3082 val
= WLC_MACMODE_DENY
;
3083 else if (nvram_match(tmp
, "allow"))
3084 val
= WLC_MACMODE_ALLOW
;
3086 val
= WLC_MACMODE_DISABLED
;
3088 WL_IOCTL(name_ptr
, WLC_SET_MACMODE
, &val
, sizeof(val
));
3100 wlconf_down(char *name
)
3106 struct {int bsscfg_idx
; int enable
;} setbuf
;
3107 int wl_ap_build
= 0; /* 1 = wl compiled with AP capabilities */
3108 char cap
[WLC_IOCTL_SMLEN
];
3109 char caps
[WLC_IOCTL_MEDLEN
];
3113 /* wlconf doesn't work for virtual i/f */
3114 if (get_ifname_unit(name
, NULL
, &wlsubunit
) == 0 && wlsubunit
>= 0) {
3115 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name
);
3119 /* Check interface (fail silently for non-wl interfaces) */
3120 if ((ret
= wl_probe(name
)))
3123 /* because of ifdefs in wl driver, when we don't have AP capabilities we
3124 * can't use the same iovars to configure the wl.
3125 * so we use "wl_ap_build" to help us know how to configure the driver
3127 if (wl_iovar_get(name
, "cap", (void *)caps
, sizeof(caps
)))
3130 foreach(cap
, caps
, next
) {
3131 if (!strcmp(cap
, "ap")) {
3137 /* Bring down the interface */
3138 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
3140 /* Disable all BSS Configs */
3141 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
3142 setbuf
.bsscfg_idx
= i
;
3145 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
3147 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
3148 /* fail quietly on a range error since the driver may
3149 * support fewer bsscfgs than we are prepared to configure
3151 if (bcmerr
== BCME_RANGE
)
3156 WL_IOCTL(name
, WLC_GET_UP
, &val
, sizeof(val
));
3160 ssid
.SSID
[0] = '\0';
3161 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
3163 /* Bring down the interface */
3164 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
3168 /* Nuke the WDS list */
3169 wlconf_wds_clear(name
);
3175 wlconf_start(char *name
)
3177 int i
, ii
, unit
, val
, ret
= 0;
3180 int ap
, apsta
, wds
, sta
= 0, wet
= 0;
3181 int wl_ap_build
= 0; /* wl compiled with AP capabilities */
3182 char buf
[WLC_IOCTL_SMLEN
];
3183 struct maclist
*maclist
;
3184 struct ether_addr
*ea
;
3185 struct bsscfg_list
*bclist
= NULL
;
3186 struct bsscfg_info
*bsscfg
= NULL
;
3188 char cap
[WLC_IOCTL_SMLEN
], caps
[WLC_IOCTL_MEDLEN
];
3189 char var
[80], tmp
[100], prefix
[PREFIX_LEN
], *str
, *next
;
3190 int trf_mgmt_cap
= 0, trf_mgmt_dwm_cap
= 0;
3191 bool dwm_supported
= FALSE
;
3193 /* Check interface (fail silently for non-wl interfaces) */
3194 if ((ret
= wl_probe(name
)))
3197 /* wlconf doesn't work for virtual i/f, so if we are given a
3198 * virtual i/f return 0 if that interface is in it's parent's "vifs"
3199 * list otherwise return -1
3201 memset(tmp
, 0, sizeof(tmp
));
3202 if (get_ifname_unit(name
, &wlunit
, &wlsubunit
) == 0) {
3203 if (wlsubunit
>= 0) {
3204 /* we have been given a virtual i/f,
3205 * is it in it's parent i/f's virtual i/f list?
3207 sprintf(tmp
, "wl%d_vifs", wlunit
);
3209 if (strstr(nvram_safe_get(tmp
), name
) == NULL
)
3210 return -1; /* config error */
3212 return 0; /* okay */
3219 /* because of ifdefs in wl driver, when we don't have AP capabilities we
3220 * can't use the same iovars to configure the wl.
3221 * so we use "wl_ap_build" to help us know how to configure the driver
3223 if (wl_iovar_get(name
, "cap", (void *)caps
, sizeof(caps
)))
3226 foreach(cap
, caps
, next
) {
3227 if (!strcmp(cap
, "ap"))
3230 if (!strcmp(cap
, "traffic-mgmt"))
3233 if (!strcmp(cap
, "traffic-mgmt-dwm"))
3234 trf_mgmt_dwm_cap
= 1;
3238 WL_IOCTL(name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
));
3239 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
3242 /* Get the list of BSS Configs */
3243 if (!(bclist
= wlconf_get_bsscfgs(name
, prefix
)))
3246 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
3247 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
3248 ap
= (!strcmp(str
, "") || !strcmp(str
, "ap"));
3249 apsta
= (!strcmp(str
, "apsta") ||
3250 ((!strcmp(str
, "sta") || !strcmp(str
, "psr") || !strcmp(str
, "wet")) &&
3251 bclist
->count
> 1));
3252 sta
= (!strcmp(str
, "sta") && bclist
->count
== 1);
3253 wds
= !strcmp(str
, "wds");
3254 wet
= !strcmp(str
, "wet");
3255 if (!strcmp(str
, "mac_spoof") || !strcmp(str
, "psta") || !strcmp(str
, "psr"))
3258 /* Retain remaining WET effects only if not APSTA */
3261 /* AP only config, code copied as-is from wlconf function */
3262 if (ap
|| apsta
|| wds
) {
3263 /* Set lazy WDS mode */
3264 val
= atoi(nvram_safe_get(strcat_r(prefix
, "lazywds", tmp
)));
3265 WL_IOCTL(name
, WLC_SET_LAZYWDS
, &val
, sizeof(val
));
3267 /* Set the WDS list */
3268 maclist
= (struct maclist
*) buf
;
3271 foreach(var
, nvram_safe_get(strcat_r(prefix
, "wds", tmp
)), next
) {
3272 if (((char *)(ea
->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
3274 ether_atoe(var
, ea
->octet
);
3278 WL_IOCTL(name
, WLC_SET_WDSLIST
, buf
, sizeof(buf
));
3280 /* Set WDS link detection timeout */
3281 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wds_timeout", tmp
)));
3282 wl_iovar_setint(name
, "wdstimeout", val
);
3286 * Finally enable BSS Configs or Join BSS
3287 * code copied as-is from wlconf function
3289 for (i
= 0; i
< bclist
->count
; i
++) {
3290 struct {int bsscfg_idx
; int enable
;} setbuf
;
3292 setbuf
.bsscfg_idx
= bclist
->bsscfgs
[i
].idx
;
3295 bsscfg
= &bclist
->bsscfgs
[i
];
3296 if (nvram_match(strcat_r(bsscfg
->prefix
, "bss_enabled", tmp
), "1")) {
3301 if (ap
|| apsta
|| sta
|| wet
) {
3302 for (ii
= 0; ii
< MAX_BSS_UP_RETRIES
; ii
++) {
3304 WL_IOVAR_SET(name
, "bss", &setbuf
, sizeof(setbuf
));
3307 strcat_r(prefix
, "ssid", tmp
);
3308 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
3309 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
3310 ssid
.SSID_len
= sizeof(ssid
.SSID
);
3311 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
),
3313 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
3315 if (apsta
&& (ret
!= 0))
3323 if ((ap
|| apsta
|| sta
) && (trf_mgmt_cap
)) {
3324 if (trf_mgmt_dwm_cap
&& ap
)
3325 dwm_supported
= TRUE
;
3326 trf_mgmt_settings(prefix
, dwm_supported
);
3329 #ifdef TRAFFIC_MGMT_RSSI_POLICY
3330 if ((ap
|| apsta
) && (trf_mgmt_cap
)) {
3331 trf_mgmt_rssi_policy(prefix
);
3333 #endif /* TRAFFIC_MGMT_RSSI_POLICY */
3335 #ifdef __CONFIG_EMF__
3336 if (nvram_match(strcat_r(bsscfg
->prefix
, "wmf_bss_enable", tmp
), "1")) {
3337 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wmf_ucigmp_query", tmp
)));
3338 wl_iovar_setint(name
, "wmf_ucast_igmp_query", val
);
3339 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wmf_mdata_sendup", tmp
)));
3340 wl_iovar_setint(name
, "wmf_mcast_data_sendup", val
);
3341 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wmf_ucast_upnp", tmp
)));
3342 wl_iovar_setint(name
, "wmf_ucast_upnp", val
);
3343 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wmf_igmpq_filter", tmp
)));
3344 wl_iovar_setint(name
, "wmf_igmpq_filter", val
);
3346 #endif /* __CONFIG_EMF__ */
3356 wlconf_security(char *name
)
3358 int unit
, bsscfg_idx
;
3359 char prefix
[PREFIX_LEN
];
3360 char tmp
[100], *str
;
3362 /* Get the interface subunit */
3363 if (get_ifname_unit(name
, &unit
, &bsscfg_idx
) != 0) {
3364 WLCONF_DBG("wlconfig(%s): unable to parse unit.subunit in interface "
3365 "name \"%s\"\n", name
, name
);
3369 /* Configure security parameters for the newly created interface */
3370 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
3371 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
3372 wlconf_security_options(name
, prefix
, bsscfg_idx
, FALSE
,
3373 !strcmp(str
, "psta") || !strcmp(str
, "psr"));
3379 main(int argc
, char *argv
[])
3381 /* Check parameters and branch based on action */
3382 if (argc
== 3 && !strcmp(argv
[2], "up"))
3383 return wlconf(argv
[1]);
3384 else if (argc
== 3 && !strcmp(argv
[2], "down"))
3385 return wlconf_down(argv
[1]);
3386 else if (argc
== 3 && !strcmp(argv
[2], "start"))
3387 return wlconf_start(argv
[1]);
3388 else if (argc
== 3 && !strcmp(argv
[2], "security"))
3389 return wlconf_security(argv
[1]);
3391 fprintf(stderr
, "Usage: wlconf <ifname> up|down\n");
3395 #endif /* defined(linux) */