2 * Wireless Network Adapter Configuration Utility
4 * Copyright (C) 2010, 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,v 1.187.2.40 2011-02-11 22:07:17 Exp $
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
24 #include <bcmparams.h>
29 #include <proto/802.1d.h>
32 #ifndef BCM4331_CHIP_ID
33 #define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */
42 #define PHY_TYPE_SSN 6
44 #define PHY_TYPE_LCN 8
45 #define PHY_TYPE_NULL 0xf
47 /* how many times to attempt to bring up a virtual i/f when
48 * we are in APSTA mode and IOVAR set of "bss" "up" returns busy
50 #define MAX_BSS_UP_RETRIES 5
52 /* notify the average dma xfer rate (in kbps) to the driver */
53 #define AVG_DMA_XFER_RATE 120000
55 /* parts of an idcode: */
56 #define IDCODE_MFG_MASK 0x00000fff
57 #define IDCODE_MFG_SHIFT 0
58 #define IDCODE_ID_MASK 0x0ffff000
59 #define IDCODE_ID_SHIFT 12
60 #define IDCODE_REV_MASK 0xf0000000
61 #define IDCODE_REV_SHIFT 28
63 /* Length of the wl capabilities string */
64 #define CAP_STR_LEN 250
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_SETINT(ifname, iovar, val) \
88 if ((ret = wl_iovar_setint(ifname, iovar, val))) \
89 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" to 0x%x failed, err = %d\n", \
90 __FUNCTION__, __LINE__, ifname, iovar, (unsigned int)val, ret);
91 #define WL_IOVAR_GETINT(ifname, iovar, val) \
92 if ((ret = wl_iovar_getint(ifname, iovar, val))) \
93 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \
94 __FUNCTION__, __LINE__, ifname, iovar, ret);
95 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
96 if ((ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))) \
97 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
98 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
99 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
100 if ((ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))) \
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_GET(ifname, iovar, bssidx, param, paramlen) \
104 if ((ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))) \
105 fprintf(stderr, "%s:%d:(%s): getting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
106 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
107 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) \
108 if ((ret = wl_bssiovar_setint(ifname, iovar, bssidx, val))) \
109 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" " \
110 "to val 0x%x failed, err = %d\n", \
111 __FUNCTION__, __LINE__, ifname, bssidx, iovar, (unsigned int)val, ret);
113 #define WLCONF_DBG(fmt, arg...)
114 #define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len))
115 #define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val))
116 #define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval))
117 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \
119 #define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val))
120 #define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val))
121 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
122 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))
123 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
124 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))
125 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
126 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))
127 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \
132 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
134 #define CHECK_PSK(mode) ((mode) & WPA_AUTH_PSK)
138 struct bsscfg_list
*wlconf_get_bsscfgs(char* ifname
, char* prefix
);
139 int wlconf(char *name
);
140 int wlconf_down(char *name
);
143 wlconf_getint(char* ifname
, int cmd
, int *pval
)
145 return wl_ioctl(ifname
, cmd
, pval
, sizeof(int));
149 wlconf_setint(char* ifname
, int cmd
, int val
)
151 return wl_ioctl(ifname
, cmd
, &val
, sizeof(int));
155 wlconf_wds_clear(char *name
)
157 struct maclist maclist
;
161 WL_IOCTL(name
, WLC_SET_WDSLIST
, &maclist
, sizeof(maclist
));
168 wlconf_set_wep_key(char *name
, char *prefix
, int bsscfg_idx
, int i
)
171 char wl_key
[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
172 char *keystr
, hex
[] = "XX";
173 unsigned char *data
= key
.data
;
176 memset(&key
, 0, sizeof(key
));
178 sprintf(wl_key
, "%skey%d", prefix
, i
);
179 keystr
= nvram_safe_get(wl_key
);
181 switch (strlen(keystr
)) {
183 case WEP128_KEY_SIZE
:
184 key
.len
= strlen(keystr
);
185 strcpy((char *)key
.data
, keystr
);
187 case WEP1_KEY_HEX_SIZE
:
188 case WEP128_KEY_HEX_SIZE
:
189 key
.len
= strlen(keystr
) / 2;
191 strncpy(hex
, keystr
, 2);
192 *data
++ = (unsigned char) strtoul(hex
, NULL
, 16);
201 /* Set current WEP key */
202 if (key
.len
&& i
== atoi(nvram_safe_get(strcat_r(prefix
, "key", wl_key
))))
203 key
.flags
= WL_PRIMARY_KEY
;
205 WL_BSSIOVAR_SET(name
, "wsec_key", bsscfg_idx
, &key
, sizeof(key
));
210 extern struct nvram_tuple router_defaults
[];
212 /* validate/restore all per-interface related variables */
214 wlconf_validate_all(char *prefix
, bool restore
)
216 struct nvram_tuple
*t
;
219 for (t
= router_defaults
; t
->name
; t
++) {
220 if (!strncmp(t
->name
, "wl_", 3)) {
221 strcat_r(prefix
, &t
->name
[3], tmp
);
222 if (!restore
&& nvram_get(tmp
))
224 v
= nvram_get(t
->name
);
225 nvram_set(tmp
, v
? v
: t
->value
);
230 /* restore specific per-interface variable */
232 wlconf_restore_var(char *prefix
, char *name
)
234 struct nvram_tuple
*t
;
236 for (t
= router_defaults
; t
->name
; t
++) {
237 if (!strncmp(t
->name
, "wl_", 3) && !strcmp(&t
->name
[3], name
)) {
238 nvram_set(strcat_r(prefix
, name
, tmp
), t
->value
);
244 wlconf_akm_options(char *prefix
)
252 wl_akm
= nvram_safe_get(strcat_r(prefix
, "akm", comb
));
253 foreach(akm
, wl_akm
, next
) {
254 if (!strcmp(akm
, "wpa"))
255 akm_ret_val
|= WPA_AUTH_UNSPECIFIED
;
256 if (!strcmp(akm
, "psk"))
257 akm_ret_val
|= WPA_AUTH_PSK
;
259 if (!strcmp(akm
, "wpa2"))
260 akm_ret_val
|= WPA2_AUTH_UNSPECIFIED
;
261 if (!strcmp(akm
, "psk2"))
262 akm_ret_val
|= WPA2_AUTH_PSK
;
263 if (!strcmp(akm
, "brcm_psk"))
264 akm_ret_val
|= BRCM_AUTH_PSK
;
272 wlconf_set_wsec(char *ifname
, char *prefix
, int bsscfg_idx
)
279 /* Set wsec bitvec */
280 akm_val
= wlconf_akm_options(prefix
);
282 if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "tkip"))
284 else if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "aes"))
286 else if (nvram_match(strcat_r(prefix
, "crypto", tmp
), "tkip+aes"))
287 val
= TKIP_ENABLED
| AES_ENABLED
;
289 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled"))
291 WL_BSSIOVAR_SETINT(ifname
, "wsec", bsscfg_idx
, val
);
292 /* Set wsec restrict if WSEC_ENABLED */
293 WL_BSSIOVAR_SETINT(ifname
, "wsec_restrict", bsscfg_idx
, val
? 1 : 0);
300 wlconf_set_preauth(char *name
, int bsscfg_idx
, int preauth
)
305 WL_BSSIOVAR_GET(name
, "wpa_cap", bsscfg_idx
, &cap
, sizeof(uint
));
306 if (ret
!= 0) return -1;
309 cap
|= WPA_CAP_WPA2_PREAUTH
;
311 cap
&= ~WPA_CAP_WPA2_PREAUTH
;
313 WL_BSSIOVAR_SETINT(name
, "wpa_cap", bsscfg_idx
, cap
);
320 wlconf_set_radarthrs(char *name
, char *prefix
)
322 wl_radar_thr_t radar_thr
;
324 char nv_buf
[NVRAM_MAX_VALUE_LEN
], *rargs
, *v
, *endptr
;
325 char buf
[WLC_IOCTL_SMLEN
];
326 char *version
= NULL
, *thr0_20_lo
= NULL
, *thr1_20_lo
= NULL
, *thr0_40_lo
= NULL
;
327 char *thr1_40_lo
= NULL
, *thr0_20_hi
= NULL
, *thr1_20_hi
= NULL
, *thr0_40_hi
= NULL
;
328 char *thr1_40_hi
= NULL
;
329 char **locals
[] = { &version
, &thr0_20_lo
, &thr1_20_lo
, &thr0_40_lo
, &thr1_40_lo
,
330 &thr0_20_hi
, &thr1_20_hi
, &thr0_40_hi
, &thr1_40_hi
};
332 rargs
= nvram_safe_get(strcat_r(prefix
, "radarthrs", nv_buf
));
337 if ((len
> NVRAM_MAX_VALUE_LEN
) || (len
== 0))
340 memset(nv_buf
, 0, sizeof(nv_buf
));
341 strncpy(nv_buf
, rargs
, len
);
343 for (i
= 0; i
< (sizeof(locals
) / sizeof(locals
[0])); i
++) {
345 while (*v
&& *v
!= ' ') {
352 if (v
>= (nv_buf
+ len
)) /* Check for complete list, if not caught later */
356 /* Start building request */
357 memset(buf
, 0, sizeof(buf
));
358 strcpy(buf
, "radarthrs");
359 /* Retrieve radar thrs parameters */
362 radar_thr
.version
= atoi(version
);
363 if (radar_thr
.version
> WL_RADAR_THR_VERSION
)
366 /* Retrieve ver 0 params */
369 radar_thr
.thresh0_20_lo
= (uint16
)strtol(thr0_20_lo
, &endptr
, 0);
375 radar_thr
.thresh1_20_lo
= (uint16
)strtol(thr1_20_lo
, &endptr
, 0);
381 radar_thr
.thresh0_40_lo
= (uint16
)strtol(thr0_40_lo
, &endptr
, 0);
387 radar_thr
.thresh1_40_lo
= (uint16
)strtol(thr1_40_lo
, &endptr
, 0);
391 if (radar_thr
.version
== 0) {
393 * Attempt a best effort update of ver 0 to ver 1 by updating
394 * the appropriate values with the specified defaults. The defaults
395 * are from the reference design.
397 radar_thr
.version
= WL_RADAR_THR_VERSION
; /* avoid driver rejecting it */
398 radar_thr
.thresh0_20_hi
= 0x6ac;
399 radar_thr
.thresh1_20_hi
= 0x6cc;
400 radar_thr
.thresh0_40_hi
= 0x6bc;
401 radar_thr
.thresh1_40_hi
= 0x6e0;
403 /* Retrieve ver 1 params */
406 radar_thr
.thresh0_20_hi
= (uint16
)strtol(thr0_20_hi
, &endptr
, 0);
412 radar_thr
.thresh1_20_hi
= (uint16
)strtol(thr1_20_hi
, &endptr
, 0);
418 radar_thr
.thresh0_40_hi
= (uint16
)strtol(thr0_40_hi
, &endptr
, 0);
424 radar_thr
.thresh1_40_hi
= (uint16
)strtol(thr1_40_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");
443 wlconf_set_wme(char *name
, char *prefix
)
447 int phytype
, gmode
, no_ack
, apsd
, dp
[2];
448 edcf_acparam_t
*acparams
;
449 /* Pay attention to buffer length requirements when using this */
450 char buf
[WLC_IOCTL_SMLEN
];
451 char *v
, *nv_value
, nv
[100];
452 char nv_name
[] = "%swme_%s_%s";
453 char *ac
[] = {"be", "bk", "vi", "vo"};
454 char *cwmin
, *cwmax
, *aifsn
, *txop_b
, *txop_ag
, *admin_forced
, *oldest_first
;
455 char **locals
[] = { &cwmin
, &cwmax
, &aifsn
, &txop_b
, &txop_ag
, &admin_forced
,
457 struct {char *req
; char *str
;} mode
[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"},
458 {"wme_tx_params", "txp"}};
460 /* query the phy type */
461 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
463 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", nv
)));
465 /* WME sta setting first */
466 for (i
= 0; i
< 2; i
++) {
467 /* build request block */
468 memset(buf
, 0, sizeof(buf
));
469 strcpy(buf
, mode
[i
].req
);
470 /* put push wmeac params after "wme-ac" in buf */
471 acparams
= (edcf_acparam_t
*)(buf
+ strlen(buf
) + 1);
473 for (j
= 0; j
< AC_COUNT
; j
++) {
474 /* get packed nvram parameter */
475 snprintf(nv
, sizeof(nv
), nv_name
, prefix
, mode
[i
].str
, ac
[j
]);
476 nv_value
= nvram_safe_get(nv
);
477 strcpy(nv
, nv_value
);
480 for (k
= 0; k
< (sizeof(locals
) / sizeof(locals
[0])); k
++) {
482 while (*v
&& *v
!= ' ')
491 acparams
->ECW
&= ~EDCF_ECWMIN_MASK
;
493 for (val
++, k
= 0; val
; val
>>= 1, k
++);
494 acparams
->ECW
|= (k
? k
- 1 : 0) & EDCF_ECWMIN_MASK
;
496 acparams
->ECW
&= ~EDCF_ECWMAX_MASK
;
498 for (val
++, k
= 0; val
; val
>>= 1, k
++);
499 acparams
->ECW
|= ((k
? k
- 1 : 0) << EDCF_ECWMAX_SHIFT
) & EDCF_ECWMAX_MASK
;
501 acparams
->ACI
&= ~EDCF_AIFSN_MASK
;
502 acparams
->ACI
|= atoi(aifsn
) & EDCF_AIFSN_MASK
;
504 acparams
->ACI
&= ~EDCF_ACI_MASK
;
505 acparams
->ACI
|= j
<< EDCF_ACI_SHIFT
;
507 if (phytype
== PHY_TYPE_B
|| gmode
== 0)
511 acparams
->TXOP
= val
/ 32;
513 acparams
->ACI
&= ~EDCF_ACM_MASK
;
514 val
= strcmp(admin_forced
, "on") ? 0 : 1;
515 acparams
->ACI
|= val
<< 4;
517 /* configure driver */
518 WL_IOCTL(name
, WLC_SET_VAR
, buf
, sizeof(buf
));
523 v
= nvram_safe_get(strcat_r(prefix
, "wme_no_ack", nv
));
524 no_ack
= strcmp(v
, "on") ? 0 : 1;
525 WL_IOVAR_SETINT(name
, "wme_noack", no_ack
);
528 v
= nvram_safe_get(strcat_r(prefix
, "wme_apsd", nv
));
529 apsd
= strcmp(v
, "on") ? 0 : 1;
530 WL_IOVAR_SETINT(name
, "wme_apsd", apsd
);
532 /* set per-AC discard policy */
533 strcpy(buf
, "wme_dp");
534 WL_IOVAR_SETINT(name
, "wme_dp", dp
[1]);
536 /* WME Tx parameters setting */
538 wme_tx_params_t txparams
[AC_COUNT
];
539 char *srl
, *sfbl
, *lrl
, *lfbl
, *maxrate
;
540 char **locals
[] = { &srl
, &sfbl
, &lrl
, &lfbl
, &maxrate
};
542 /* build request block */
543 memset(txparams
, 0, sizeof(txparams
));
545 for (j
= 0; j
< AC_COUNT
; j
++) {
546 /* get packed nvram parameter */
547 snprintf(nv
, sizeof(nv
), nv_name
, prefix
, mode
[2].str
, ac
[j
]);
548 nv_value
= nvram_safe_get(nv
);
549 strcpy(nv
, nv_value
);
552 for (k
= 0; k
< (sizeof(locals
) / sizeof(locals
[0])); k
++) {
554 while (*v
&& *v
!= ' ')
562 /* update short retry limit */
563 txparams
[j
].short_retry
= atoi(srl
);
565 /* update short fallback limit */
566 txparams
[j
].short_fallback
= atoi(sfbl
);
568 /* update long retry limit */
569 txparams
[j
].long_retry
= atoi(lrl
);
571 /* update long fallback limit */
572 txparams
[j
].long_fallback
= atoi(lfbl
);
574 /* update max rate */
575 txparams
[j
].max_rate
= atoi(maxrate
);
578 /* set the WME tx parameters */
579 WL_IOVAR_SET(name
, mode
[2].req
, txparams
, sizeof(txparams
));
585 #if defined(linux) || defined(__NetBSD__)
588 sleep_ms(const unsigned int ms
)
592 #elif defined(__ECOS)
594 sleep_ms(const unsigned int ms
)
596 cyg_tick_count_t ostick
;
599 cyg_thread_delay(ostick
);
602 #error "sleep_ms() not defined for this OS!!!"
603 #endif /* defined(linux) */
606 * The following condition(s) must be met when Auto Channel Selection
608 * - the I/F is up (change radio channel requires it is up?)
609 * - the AP must not be associated (setting SSID to empty should
610 * make sure it for us)
613 wlconf_auto_channel(char *name
)
616 wl_uint32_list_t request
;
621 /* query the phy type */
622 WL_GETINT(name
, WLC_GET_PHYTYPE
, &phytype
);
624 request
.count
= 0; /* let the ioctl decide */
625 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
627 sleep_ms(phytype
== PHY_TYPE_A
? 1000 : 750);
628 for (i
= 0; i
< 100; i
++) {
629 WL_GETINT(name
, WLC_GET_CHANNEL_SEL
, &chosen
);
635 WLCONF_DBG("interface %s: channel selected %d\n", name
, chosen
);
640 wlconf_auto_chanspec(char *name
)
642 chanspec_t chosen
= 0;
644 wl_uint32_list_t request
;
648 request
.count
= 0; /* let the ioctl decide */
649 WL_IOCTL(name
, WLC_START_CHANNEL_SEL
, &request
, sizeof(request
));
651 /* this time needs to be < 1000 to prevent mpc kicking in for 2nd radio */
653 for (i
= 0; i
< 100; i
++) {
654 WL_IOVAR_GETINT(name
, "apcschspec", &temp
);
661 chosen
= (chanspec_t
) temp
;
662 WLCONF_DBG("interface %s: chanspec selected %04x\n", name
, chosen
);
666 /* PHY type/BAND conversion */
667 #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
668 /* PHY type conversion */
669 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
670 (phy) == PHY_TYPE_B ? "b" : \
671 (phy) == PHY_TYPE_LP ? "l" : \
672 (phy) == PHY_TYPE_G ? "g" : \
673 (phy) == PHY_TYPE_SSN ? "s" : \
674 (phy) == PHY_TYPE_HT ? "h" : \
675 (phy) == PHY_TYPE_LCN ? "c" : "n")
676 #define WLCONF_STR2PHYTYPE(ch) ((ch) == 'a' ? PHY_TYPE_A : \
677 (ch) == 'b' ? PHY_TYPE_B : \
678 (ch) == 'l' ? PHY_TYPE_LP : \
679 (ch) == 'g' ? PHY_TYPE_G : \
680 (ch) == 's' ? PHY_TYPE_SSN : \
681 (ch) == 'h' ? PHY_TYPE_HT : \
682 (ch) == 'c' ? PHY_TYPE_LCN : PHY_TYPE_N)
684 #define WLCONF_PHYTYPE_11N(phy) ((phy) == PHY_TYPE_N || (phy) == PHY_TYPE_SSN || \
685 (phy) == PHY_TYPE_LCN || (phy) == PHY_TYPE_HT)
688 #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */
691 int idx
; /* bsscfg index */
692 char ifname
[PREFIX_LEN
]; /* OS name of interface (debug only) */
693 char prefix
[PREFIX_LEN
]; /* prefix for nvram params (eg. "wl0.1_") */
698 struct bsscfg_info bsscfgs
[WL_MAXBSSCFG
];
702 wlconf_get_bsscfgs(char* ifname
, char* prefix
)
708 struct bsscfg_list
*bclist
;
709 struct bsscfg_info
*bsscfg
;
711 bclist
= (struct bsscfg_list
*)malloc(sizeof(struct bsscfg_list
));
714 memset(bclist
, 0, sizeof(struct bsscfg_list
));
716 /* Set up Primary BSS Config information */
717 bsscfg
= &bclist
->bsscfgs
[0];
719 strncpy(bsscfg
->ifname
, ifname
, PREFIX_LEN
-1);
720 strcpy(bsscfg
->prefix
, prefix
);
723 /* additional virtual BSS Configs from wlX_vifs */
724 foreach(var
, nvram_safe_get(strcat_r(prefix
, "vifs", tmp
)), next
) {
725 if (bclist
->count
== WL_MAXBSSCFG
) {
726 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
728 "while configuring interface \"%s\"\n",
729 ifname
, WL_MAXBSSCFG
, strcat_r(prefix
, "vifs", tmp
), var
);
732 bsscfg
= &bclist
->bsscfgs
[bclist
->count
];
733 if (get_ifname_unit(var
, NULL
, &bsscfg
->idx
) != 0) {
734 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
739 strncpy(bsscfg
->ifname
, var
, PREFIX_LEN
-1);
740 snprintf(bsscfg
->prefix
, PREFIX_LEN
, "%s_", bsscfg
->ifname
);
748 wlconf_config_join_pref(char *name
, int auth_val
)
752 if ((auth_val
& (WPA_AUTH_UNSPECIFIED
| WPA2_AUTH_UNSPECIFIED
)) || CHECK_PSK(auth_val
)) {
754 /* WPA pref, 14 tuples */
755 0x02, 0xaa, 0x00, 0x0e,
756 /* WPA2 AES (unicast) AES (multicast) */
757 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x04,
758 /* WPA AES (unicast) AES (multicast) */
759 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x04,
760 /* WPA2 AES (unicast) TKIP (multicast) */
761 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x02,
762 /* WPA AES (unicast) TKIP (multicast) */
763 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x02,
764 /* WPA2 AES (unicast) WEP-40 (multicast) */
765 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x01,
766 /* WPA AES (unicast) WEP-40 (multicast) */
767 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x01,
768 /* WPA2 AES (unicast) WEP-128 (multicast) */
769 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x05,
770 /* WPA AES (unicast) WEP-128 (multicast) */
771 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x05,
772 /* WPA2 TKIP (unicast) TKIP (multicast) */
773 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x02,
774 /* WPA TKIP (unicast) TKIP (multicast) */
775 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x02,
776 /* WPA2 TKIP (unicast) WEP-40 (multicast) */
777 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x01,
778 /* WPA TKIP (unicast) WEP-40 (multicast) */
779 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x01,
780 /* WPA2 TKIP (unicast) WEP-128 (multicast) */
781 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x05,
782 /* WPA TKIP (unicast) WEP-128 (multicast) */
783 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x05,
785 0x01, 0x02, 0x00, 0x00,
788 if (CHECK_PSK(auth_val
)) {
789 for (i
= 0; i
< pref
[3]; i
++)
790 pref
[7 + i
* 12] = 0x02;
793 WL_IOVAR_SET(name
, "join_pref", pref
, sizeof(pref
));
799 wlconf_security_options(char *name
, char *prefix
, int bsscfg_idx
, bool id_supp
,
800 bool check_join_pref
)
806 bool need_id_supp
= FALSE
;
807 bool need_join_pref
= FALSE
;
809 #define AUTOWPA(cfg) ((cfg) == (WPA_AUTH_PSK | WPA2_AUTH_PSK))
813 * Need to check errors (card may have changed) and change to
814 * defaults since the new chip may not support the requested
815 * encryptions after the card has been changed.
817 if (wlconf_set_wsec(name
, prefix
, bsscfg_idx
)) {
818 /* change nvram only, code below will pass them on */
819 wlconf_restore_var(prefix
, "auth_mode");
820 wlconf_restore_var(prefix
, "auth");
821 /* reset wep to default */
822 wlconf_restore_var(prefix
, "crypto");
823 wlconf_restore_var(prefix
, "wep");
824 wlconf_set_wsec(name
, prefix
, bsscfg_idx
);
827 val
= wlconf_akm_options(prefix
);
828 if (bsscfg_idx
== 0) {
829 need_join_pref
= ((check_join_pref
|| id_supp
) && AUTOWPA(val
));
830 need_id_supp
= (id_supp
|| need_join_pref
);
834 wlconf_config_join_pref(name
, val
);
836 /* enable in-driver wpa supplicant? */
837 if (need_id_supp
&& (CHECK_PSK(val
))) {
841 if (((key
= nvram_get(strcat_r(prefix
, "wpa_psk", tmp
))) != NULL
) &&
842 (strlen(key
) < WSEC_MAX_PSK_LEN
)) {
843 psk
.key_len
= (ushort
) strlen(key
);
844 psk
.flags
= WSEC_PASSPHRASE
;
845 strcpy((char *)psk
.key
, key
);
846 WL_IOCTL(name
, WLC_SET_WSEC_PMK
, &psk
, sizeof(psk
));
848 wl_iovar_setint(name
, "sup_wpa", 1);
852 WL_BSSIOVAR_SETINT(name
, "wpa_auth", bsscfg_idx
, val
);
854 /* EAP Restrict if we have an AKM or radius authentication */
855 val
= ((val
!= 0) || (nvram_match(strcat_r(prefix
, "auth_mode", tmp
), "radius")));
856 WL_BSSIOVAR_SETINT(name
, "eap_restrict", bsscfg_idx
, val
);
859 if (nvram_match(strcat_r(prefix
, "wep", tmp
), "enabled")) {
860 for (i
= 1; i
<= DOT11_MAX_DEFAULT_KEYS
; i
++)
861 wlconf_set_wep_key(name
, prefix
, bsscfg_idx
, i
);
864 /* Set 802.11 authentication mode - open/shared */
865 val
= atoi(nvram_safe_get(strcat_r(prefix
, "auth", tmp
)));
866 WL_BSSIOVAR_SETINT(name
, "auth", bsscfg_idx
, val
);
871 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled
872 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
873 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off,
874 * afterburner is enabled/disabled based on the nvram settings.
876 * WME/WMM is also set in this procedure as it depends on N and afterburner.
877 * N ==> WMM is on by default
878 * N (or ampdu) ==> afterburner is off
879 * WMM ==> afterburner is off
881 * Returns whether afterburner is on in the system.
884 wlconf_aburn_ampdu_amsdu_set(char *name
, char prefix
[PREFIX_LEN
], int nmode
, int btc_mode
)
886 bool ampdu_valid_option
= FALSE
;
887 bool amsdu_valid_option
= FALSE
;
888 bool aburn_valid_option
= FALSE
;
889 int val
, aburn_option_val
= OFF
, ampdu_option_val
= OFF
, amsdu_option_val
= OFF
;
890 int wme_option_val
= ON
; /* On by default */
891 char tmp
[CAP_STR_LEN
], var
[80], *next
, *wme_val
;
892 char buf
[WLC_IOCTL_SMLEN
];
893 int len
= strlen("amsdu");
896 /* First, clear WMM and afterburner settings to avoid conflicts */
897 WL_IOVAR_SETINT(name
, "wme", OFF
);
898 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
900 /* Get WME setting from NVRAM if present */
901 wme_val
= nvram_get(strcat_r(prefix
, "wme", tmp
));
902 if (wme_val
&& !strcmp(wme_val
, "off")) {
903 wme_option_val
= OFF
;
906 /* Set options based on capability */
907 wl_iovar_get(name
, "cap", (void *)tmp
, CAP_STR_LEN
);
908 foreach(var
, tmp
, next
) {
912 /* Check for the capabilitiy 'amsdutx' */
913 if (strncmp(var
, "amsdutx", sizeof(var
)) == 0) {
917 nvram_str
= nvram_get(strcat_r(prefix
, var
, buf
));
921 if (!strcmp(nvram_str
, "on"))
923 else if (!strcmp(nvram_str
, "off"))
925 else if (!strcmp(nvram_str
, "auto"))
930 if (btc_mode
!= WL_BTC_PREMPT
&& strncmp(var
, "afterburner", sizeof(var
)) == 0) {
931 aburn_valid_option
= TRUE
;
932 aburn_option_val
= val
;
935 if (strncmp(var
, "ampdu", sizeof(var
)) == 0) {
936 ampdu_valid_option
= TRUE
;
937 ampdu_option_val
= val
;
941 amsdu_valid_option
= TRUE
;
942 amsdu_option_val
= val
;
946 if (nmode
!= OFF
) { /* N-mode is ON/AUTO */
947 if (ampdu_valid_option
) {
948 if (ampdu_option_val
!= OFF
) {
949 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
950 WL_IOVAR_SETINT(name
, "ampdu", ampdu_option_val
);
952 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
956 if (amsdu_valid_option
) {
957 if (amsdu_option_val
!= OFF
) { /* AMPDU (above) has priority over AMSDU */
958 if (ampdu_option_val
== OFF
) {
959 WL_IOVAR_SETINT(name
, "ampdu", OFF
);
960 WL_IOVAR_SETINT(name
, "amsdu", amsdu_option_val
);
963 WL_IOVAR_SETINT(name
, "amsdu", OFF
);
965 /* allow ab in N mode. Do this last: may defeat ampdu et al */
966 if (aburn_valid_option
) {
967 WL_IOVAR_SETINT(name
, "afterburner_override", aburn_option_val
);
969 /* Also turn off N reqd setting if ab is not OFF */
970 if (aburn_option_val
!= 0)
971 WL_IOVAR_SETINT(name
, "nreqd", 0);
975 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
976 * if WME is off, set the afterburner based on the configured nvram setting.
978 wl_iovar_setint(name
, "amsdu", OFF
);
979 wl_iovar_setint(name
, "ampdu", OFF
);
980 if (wme_option_val
!= OFF
) { /* Can't have afterburner with WMM */
981 if (aburn_valid_option
) {
982 WL_IOVAR_SETINT(name
, "afterburner_override", OFF
);
984 } else if (aburn_valid_option
) { /* Okay, use NVRam setting for afterburner */
985 WL_IOVAR_SETINT(name
, "afterburner_override", aburn_option_val
);
989 if (wme_option_val
&& aburn_option_val
== 0) {
990 WL_IOVAR_SETINT(name
, "wme", wme_option_val
);
991 wlconf_set_wme(name
, prefix
);
994 return wme_option_val
;
997 /* WLMEDIA_IPTV::WLMEDIA_IPTV_WET_TUNNEL */
999 wlconf_del_wet_tunnel_vndr_ie(char *name
, int bsscfg_idx
, uchar
*oui
)
1002 vndr_ie_setbuf_t
*ie_setbuf
;
1005 char getbuf
[2048] = {0};
1006 vndr_ie_buf_t
*iebuf
;
1007 vndr_ie_info_t
*ieinfo
;
1015 frametype
= VNDR_IE_BEACON_FLAG
;
1017 WL_BSSIOVAR_GET(name
, "vndr_ie", bsscfg_idx
, getbuf
, 2048);
1018 iebuf
= (vndr_ie_buf_t
*)getbuf
;
1020 bufaddr
= (char*)iebuf
->vndr_ie_list
;
1022 for (i
= 0; i
< iebuf
->iecount
; i
++) {
1023 ieinfo
= (vndr_ie_info_t
*)bufaddr
;
1024 bcopy((char*)&ieinfo
->pktflag
, (char*)&pktflag
, (int)sizeof(uint32
));
1025 if (pktflag
== frametype
) {
1026 if (!memcmp(ieinfo
->vndr_ie_data
.oui
, oui
, DOT11_OUI_LEN
)) {
1028 bufaddr
= (char*) &ieinfo
->vndr_ie_data
;
1029 buflen
= (int)ieinfo
->vndr_ie_data
.len
+ VNDR_IE_HDR_LEN
;
1033 bufaddr
= (char *)ieinfo
->vndr_ie_data
.oui
+ ieinfo
->vndr_ie_data
.len
;
1039 iebuf_len
= buflen
+ sizeof(vndr_ie_setbuf_t
) - sizeof(vndr_ie_t
);
1040 ie_setbuf
= (vndr_ie_setbuf_t
*)malloc(iebuf_len
);
1042 printf("memory alloc failure\n");
1046 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1047 strcpy(ie_setbuf
->cmd
, "del");
1049 /* Buffer contains only 1 IE */
1051 memcpy(&ie_setbuf
->vndr_ie_buffer
.iecount
, &iecount
, sizeof(int));
1053 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].pktflag
, &frametype
, sizeof(uint32
));
1055 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
, bufaddr
, buflen
);
1057 WL_BSSIOVAR_SET(name
, "vndr_ie", bsscfg_idx
, ie_setbuf
, iebuf_len
);
1064 /* WLMEDIA_IPTV::WLMEDIA_IPTV_WET_TUNNEL */
1066 wlconf_set_wet_tunnel_vndr_ie(char *name
, int bsscfg_idx
, uchar
*oui
, uchar
*data
, int datalen
)
1068 vndr_ie_setbuf_t
*ie_setbuf
;
1069 unsigned int pktflag
;
1070 int buflen
, iecount
;
1073 pktflag
= VNDR_IE_BEACON_FLAG
;
1075 buflen
= sizeof(vndr_ie_setbuf_t
) + datalen
- 1;
1076 ie_setbuf
= (vndr_ie_setbuf_t
*)malloc(buflen
);
1078 printf("memory alloc failure\n");
1082 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1083 strcpy(ie_setbuf
->cmd
, "add");
1085 /* Buffer contains only 1 IE */
1087 memcpy(&ie_setbuf
->vndr_ie_buffer
.iecount
, &iecount
, sizeof(int));
1090 * The packet flag bit field indicates the packets that will
1093 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].pktflag
, &pktflag
, sizeof(uint32
));
1095 /* Now, add the IE to the buffer, +1: one byte OUI_TYPE */
1096 ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.len
= DOT11_OUI_LEN
+ datalen
;
1098 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.oui
[0], oui
, DOT11_OUI_LEN
);
1100 memcpy(&ie_setbuf
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.data
[0], data
,
1103 wlconf_del_wet_tunnel_vndr_ie(name
, bsscfg_idx
, oui
);
1104 WL_BSSIOVAR_SET(name
, "vndr_ie", (int)bsscfg_idx
, ie_setbuf
, buflen
);
1110 #define VIFNAME_LEN 16
1112 /* configure the specified wireless interface */
1116 int restore_defaults
, val
, unit
, phytype
, bandtype
, gmode
= 0, ret
= 0;
1118 int error_bg
, error_a
;
1119 struct bsscfg_list
*bclist
= NULL
;
1120 struct bsscfg_info
*bsscfg
= NULL
;
1121 char tmp
[100], prefix
[PREFIX_LEN
];
1122 char var
[80], *next
, *str
, *addr
= NULL
;
1123 /* Pay attention to buffer length requirements when using this */
1124 char buf
[WLC_IOCTL_SMLEN
*2] __attribute__ ((aligned(4)));
1128 struct maclist
*maclist
;
1129 struct ether_addr
*ea
;
1134 int ap
, apsta
, wds
, sta
= 0, wet
= 0, mac_spoof
= 0, wmf
= 0;
1135 int radio_pwrsave
= 0, rxchain_pwrsave
= 0;
1136 char country_code
[4];
1144 int wl_ap_build
= 0; /* wl compiled with AP capabilities */
1145 char cap
[WLC_IOCTL_SMLEN
];
1146 char caps
[WLC_IOCTL_SMLEN
];
1149 uint nbw
= WL_CHANSPEC_BW_20
;
1150 int nmode
= OFF
; /* 802.11n support */
1151 char vif_addr
[WLC_IOCTL_SMLEN
];
1152 int max_no_vifs
= 0;
1155 bool ure_enab
= FALSE
;
1156 bool radar_enab
= FALSE
;
1157 bool obss_coex
= FALSE
;
1159 /* wlconf doesn't work for virtual i/f, so if we are given a
1160 * virtual i/f return 0 if that interface is in it's parent's "vifs"
1161 * list otherwise return -1
1163 if (get_ifname_unit(name
, &wlunit
, &wlsubunit
) == 0) {
1164 if (wlsubunit
>= 0) {
1165 /* we have been given a virtual i/f,
1166 * is it in it's parent i/f's virtual i/f list?
1168 sprintf(tmp
, "wl%d_vifs", wlunit
);
1170 if (strstr(nvram_safe_get(tmp
), name
) == NULL
)
1171 return -1; /* config error */
1173 return 0; /* okay */
1180 memset(tmp
, 0, sizeof(tmp
));
1182 /* because of ifdefs in wl driver, when we don't have AP capabilities we
1183 * can't use the same iovars to configure the wl.
1184 * so we use "wl_ap_build" to help us know how to configure the driver
1186 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
1189 foreach(cap
, caps
, next
) {
1190 if (!strcmp(cap
, "ap")) {
1192 } else if (!strcmp(cap
, "mbss16"))
1194 else if (!strcmp(cap
, "mbss8"))
1196 else if (!strcmp(cap
, "mbss4"))
1198 else if (!strcmp(cap
, "wmf"))
1200 else if (!strcmp(cap
, "rxchain_pwrsave"))
1201 rxchain_pwrsave
= 1;
1202 else if (!strcmp(cap
, "radio_pwrsave"))
1206 /* Check interface (fail silently for non-wl interfaces) */
1207 if ((ret
= wl_probe(name
)))
1210 /* Get MAC address */
1211 (void) wl_hwaddr(name
, (uchar
*)buf
);
1212 memcpy(vif_addr
, buf
, ETHER_ADDR_LEN
);
1215 WL_IOCTL(name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
));
1216 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
1218 /* Restore defaults if per-interface parameters do not exist */
1219 restore_defaults
= !nvram_get(strcat_r(prefix
, "ifname", tmp
));
1220 wlconf_validate_all(prefix
, restore_defaults
);
1221 nvram_set(strcat_r(prefix
, "ifname", tmp
), name
);
1222 nvram_set(strcat_r(prefix
, "hwaddr", tmp
), ether_etoa((uchar
*)buf
, eaddr
));
1223 snprintf(buf
, sizeof(buf
), "%d", unit
);
1224 nvram_set(strcat_r(prefix
, "unit", tmp
), buf
);
1227 /* Apply message level */
1228 if (nvram_invmatch("wl_msglevel", "")) {
1229 val
= (int)strtoul(nvram_get("wl_msglevel"), NULL
, 0);
1230 WL_IOCTL(name
, WLC_SET_MSGLEVEL
, &val
, sizeof(val
));
1234 /* Bring the interface down */
1235 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
1237 /* Disable all BSS Configs */
1238 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
1239 struct {int bsscfg_idx
; int enable
;} setbuf
;
1240 setbuf
.bsscfg_idx
= i
;
1243 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
1245 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
1246 /* fail quietly on a range error since the driver may
1247 * support fewer bsscfgs than we are prepared to configure
1249 if (bcmerr
== BCME_RANGE
)
1253 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
1254 " (down) failed, ret = %d, bcmerr = %d\n",
1255 __LINE__
, name
, i
, ret
, bcmerr
);
1259 /* Get the list of BSS Configs */
1260 bclist
= wlconf_get_bsscfgs(name
, prefix
);
1261 if (bclist
== NULL
) {
1267 strcat_r(prefix
, "vifs", tmp
);
1268 printf("BSS Config summary: primary -> \"%s\", %s -> \"%s\"\n", name
, tmp
,
1269 nvram_safe_get(tmp
));
1270 for (i
= 0; i
< bclist
->count
; i
++) {
1271 printf("BSS Config \"%s\": index %d\n",
1272 bclist
->bsscfgs
[i
].ifname
, bclist
->bsscfgs
[i
].idx
);
1276 /* create a wlX.Y_ifname nvram setting */
1277 for (i
= 1; i
< bclist
->count
; i
++) {
1278 bsscfg
= &bclist
->bsscfgs
[i
];
1279 #if defined(linux) || defined(__ECOS) || defined(__NetBSD__)
1280 strcpy(var
, bsscfg
->ifname
);
1282 nvram_set(strcat_r(bsscfg
->prefix
, "ifname", tmp
), var
);
1285 /* If ure_disable is not present or is 1, ure is not enabled;
1286 * that is, if it is present and 0, ure is enabled.
1288 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
1292 /* Enable MBSS mode if appropriate */
1294 WL_IOVAR_SETINT(name
, "mbss", (bclist
->count
> 1));
1298 * Set SSID for each BSS Config
1300 for (i
= 0; i
< bclist
->count
; i
++) {
1301 bsscfg
= &bclist
->bsscfgs
[i
];
1302 strcat_r(bsscfg
->prefix
, "ssid", tmp
);
1303 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
1304 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
1305 ssid
.SSID_len
= sizeof(ssid
.SSID
);
1306 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
), ssid
.SSID_len
);
1307 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1308 "with SSID \"%s\"\n", name
, bsscfg
->idx
,
1309 bsscfg
->ifname
, nvram_safe_get(tmp
));
1310 WL_BSSIOVAR_SET(name
, "ssid", bsscfg
->idx
, &ssid
,
1315 /* Create addresses for VIFs */
1317 /* set local bit for our MBSS vif base */
1318 ETHER_SET_LOCALADDR(vif_addr
);
1320 /* construct and set other wlX.Y_hwaddr */
1321 for (i
= 1; i
< max_no_vifs
; i
++) {
1322 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr", unit
, i
);
1323 addr
= nvram_safe_get(tmp
);
1324 if (!strcmp(addr
, "")) {
1325 vif_addr
[5] = (vif_addr
[5] & ~(max_no_vifs
-1))
1326 | ((max_no_vifs
-1) & (vif_addr
[5]+1));
1328 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
, eaddr
));
1331 /* The addresses are available in NVRAM, so set them */
1332 for (i
= 1; i
< max_no_vifs
; i
++) {
1333 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_bss_enabled", unit
, i
);
1334 if (!strcmp(nvram_safe_get(tmp
), "1")) {
1335 snprintf(tmp
, sizeof(tmp
), "wl%d.%d_hwaddr", unit
, i
);
1336 ether_atoe(nvram_safe_get(tmp
), (unsigned char *)eaddr
);
1337 WL_BSSIOVAR_SET(name
, "cur_etheraddr", i
, eaddr
, ETHER_ADDR_LEN
);
1340 } else { /* URE is enabled */
1341 /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
1342 snprintf(tmp
, sizeof(tmp
), "wl%d.1_hwaddr", unit
);
1343 WL_BSSIOVAR_SET(name
, "cur_etheraddr", 1, vif_addr
,
1345 nvram_set(tmp
, ether_etoa((uchar
*)vif_addr
, eaddr
));
1348 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1349 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
1350 ap
= (!strcmp(str
, "") || !strcmp(str
, "ap"));
1351 apsta
= (!strcmp(str
, "apsta") ||
1352 ((!strcmp(str
, "sta") || !strcmp(str
, "wet")) &&
1353 bclist
->count
> 1));
1354 sta
= (!strcmp(str
, "sta") && bclist
->count
== 1);
1355 wds
= !strcmp(str
, "wds");
1356 wet
= !strcmp(str
, "wet");
1357 mac_spoof
= !strcmp(str
, "mac_spoof");
1359 /* set apsta var first, because APSTA mode takes precedence */
1360 WL_IOVAR_SETINT(name
, "apsta", apsta
);
1363 val
= (ap
|| apsta
|| wds
) ? 1 : 0;
1364 WL_IOCTL(name
, WLC_SET_AP
, &val
, sizeof(val
));
1368 WL_IOCTL(name
, WLC_SET_WET
, &wet
, sizeof(wet
));
1372 WL_IOVAR_SETINT(name
, "mac_spoof", 1);
1375 /* For STA configurations, configure association retry time.
1376 * Use specified time (capped), or mode-specific defaults.
1378 if (sta
|| wet
|| apsta
) {
1379 char *retry_time
= nvram_safe_get(strcat_r(prefix
, "sta_retry_time", tmp
));
1380 val
= atoi(retry_time
);
1381 WL_IOVAR_SETINT(name
, "sta_retry_time", val
);
1384 /* Retain remaining WET effects only if not APSTA */
1387 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1390 val
= atoi(nvram_safe_get(strcat_r(prefix
, "infra", tmp
)));
1391 WL_IOCTL(name
, WLC_SET_INFRA
, &val
, sizeof(val
));
1393 /* Set The AP MAX Associations Limit */
1395 max_assoc
= val
= atoi(nvram_safe_get(strcat_r(prefix
, "maxassoc", tmp
)));
1397 WL_IOVAR_SETINT(name
, "maxassoc", val
);
1398 } else { /* Get value from driver if not in nvram */
1399 WL_IOVAR_GETINT(name
, "maxassoc", &max_assoc
);
1403 WL_IOVAR_SETINT(name
, "mpc", OFF
);
1405 for (i
= 0; i
< bclist
->count
; i
++) {
1407 bsscfg
= &bclist
->bsscfgs
[i
];
1410 /* XXXMSSID: The note about setting preauth now does not seem right.
1411 * NAS brings the BSS up if it runs, so setting the preauth value
1412 * will make it in the bcn/prb. If that is right, we can move this
1413 * chunk out of wlconf.
1416 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1417 * if we do it in the NAS we need to bring down the interface and up to make
1418 * it affect in the beacons
1420 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1422 preauth
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "preauth", tmp
));
1423 if (strlen (preauth
) != 0) {
1424 set_preauth
= atoi(preauth
);
1426 wlconf_set_preauth(name
, bsscfg
->idx
, set_preauth
);
1428 #endif /* BCMWPA2 */
1430 /* WLMEDIA_IPTV::WLMEDIA_IPTV_WET_TUNNEL */
1431 /* Add BRCM proprietary IE for wet tunnel capability */
1433 if (atoi(nvram_safe_get("wet_tunnel")) == 1) {
1434 brcm_prop_ie_t wet_tunnel_ie
;
1435 wet_tunnel_ie
.type
= WET_TUNNEL_IE_TYPE
;
1436 wet_tunnel_ie
.cap
= htons(1);
1437 wlconf_set_wet_tunnel_vndr_ie(name
,
1438 bsscfg
->idx
, (uchar
*)BRCM_PROP_OUI
,
1439 (uchar
*)&(wet_tunnel_ie
.type
),
1440 sizeof(wet_tunnel_ie
.type
)+sizeof(wet_tunnel_ie
.cap
));
1441 WL_IOVAR_SETINT(name
, "ap_tunneling", 1);
1445 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1447 if (ap
|| (apsta
&& bsscfg
->idx
!= 0)) {
1448 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "bss_maxassoc", tmp
)));
1450 WL_BSSIOVAR_SETINT(name
, "bss_maxassoc", bsscfg
->idx
, val
);
1451 } else if (max_assoc
> 0) { /* Set maxassoc same as global if not set */
1452 snprintf(var
, sizeof(var
), "%d", max_assoc
);
1453 nvram_set(tmp
, var
);
1457 /* Set network type */
1458 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "closed", tmp
)));
1459 WL_BSSIOVAR_SETINT(name
, "closednet", bsscfg
->idx
, val
);
1461 /* Set the ap isolate mode */
1462 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "ap_isolate", tmp
)));
1463 WL_BSSIOVAR_SETINT(name
, "ap_isolate", bsscfg
->idx
, val
);
1465 /* Set the WMF enable mode */
1467 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
, "wmf_bss_enable", tmp
)));
1468 WL_BSSIOVAR_SETINT(name
, "wmf_bss_enable", bsscfg
->idx
, val
);
1471 /* Set the Multicast Reverse Translation enable mode */
1473 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
1474 "mcast_regen_bss_enable", tmp
)));
1475 WL_BSSIOVAR_SETINT(name
, "mcast_regen_bss_enable", bsscfg
->idx
, val
);
1479 if (rxchain_pwrsave
) {
1480 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rxchain_pwrsave_enable", tmp
)));
1481 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_enable", bsscfg
->idx
, val
);
1483 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rxchain_pwrsave_quiet_time", tmp
)));
1484 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_quiet_time", bsscfg
->idx
, val
);
1486 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rxchain_pwrsave_pps", tmp
)));
1487 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_pps", bsscfg
->idx
, val
);
1489 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
1490 "rxchain_pwrsave_stas_assoc_check", tmp
)));
1491 WL_BSSIOVAR_SETINT(name
, "rxchain_pwrsave_stas_assoc_check", bsscfg
->idx
,
1495 if (radio_pwrsave
) {
1496 val
= atoi(nvram_safe_get(strcat_r(prefix
, "radio_pwrsave_enable", tmp
)));
1497 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_enable", bsscfg
->idx
, val
);
1499 val
= atoi(nvram_safe_get(strcat_r(prefix
, "radio_pwrsave_quiet_time", tmp
)));
1500 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_quiet_time", bsscfg
->idx
, val
);
1502 val
= atoi(nvram_safe_get(strcat_r(prefix
, "radio_pwrsave_pps", tmp
)));
1503 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_pps", bsscfg
->idx
, val
);
1505 val
= atoi(nvram_safe_get(strcat_r(prefix
, "radio_pwrsave_level", tmp
)));
1506 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_level", bsscfg
->idx
, val
);
1508 val
= atoi(nvram_safe_get(strcat_r(bsscfg
->prefix
,
1509 "radio_pwrsave_stas_assoc_check", tmp
)));
1510 WL_BSSIOVAR_SETINT(name
, "radio_pwrsave_stas_assoc_check", bsscfg
->idx
,
1514 /* Set up the country code */
1515 (void) strcat_r(prefix
, "country_code", tmp
);
1516 country
= nvram_get(tmp
);
1517 if (country
&& country
[0] != '\0') {
1518 strncpy(country_code
, country
, sizeof(country_code
));
1519 WL_IOCTL(name
, WLC_SET_COUNTRY
, country_code
, strlen(country_code
) + 1);
1521 /* Get the default country code if undefined */
1522 WL_IOCTL(name
, WLC_GET_COUNTRY
, country_code
, sizeof(country_code
));
1524 /* Add the new NVRAM variable */
1525 nvram_set("wl_country_code", country_code
);
1526 (void) strcat_r(prefix
, "country_code", tmp
);
1527 nvram_set(tmp
, country_code
);
1530 /* Change LED Duty Cycle */
1531 leddc
= (uint32
)strtoul(nvram_safe_get(strcat_r(prefix
, "leddc", tmp
)), NULL
, 16);
1533 WL_IOVAR_SETINT(name
, "leddc", leddc
);
1535 /* Enable or disable the radio */
1536 val
= nvram_match(strcat_r(prefix
, "radio", tmp
), "0");
1537 val
+= WL_RADIO_SW_DISABLE
<< 16;
1538 WL_IOCTL(name
, WLC_SET_RADIO
, &val
, sizeof(val
));
1540 /* Get supported phy types */
1541 WL_IOCTL(name
, WLC_GET_PHYLIST
, var
, sizeof(var
));
1542 nvram_set(strcat_r(prefix
, "phytypes", tmp
), var
);
1545 *(next
= buf
) = '\0';
1546 for (i
= 0; i
< strlen(var
); i
++) {
1547 /* Switch to band */
1548 val
= WLCONF_STR2PHYTYPE(var
[i
]);
1549 if (WLCONF_PHYTYPE_11N(val
)) {
1550 WL_GETINT(name
, WLC_GET_BAND
, &val
);
1552 val
= WLCONF_PHYTYPE2BAND(val
);
1553 WL_IOCTL(name
, WLC_SET_BAND
, &val
, sizeof(val
));
1554 /* Get radio ID on this band */
1555 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1556 next
+= sprintf(next
, "%sBCM%X", i
? " " : "",
1557 (rev
.radiorev
& IDCODE_ID_MASK
) >> IDCODE_ID_SHIFT
);
1559 nvram_set(strcat_r(prefix
, "radioids", tmp
), buf
);
1562 str
= nvram_get(strcat_r(prefix
, "phytype", tmp
));
1563 val
= str
? WLCONF_STR2PHYTYPE(str
[0]) : PHY_TYPE_G
;
1564 /* For NPHY use band value from NVRAM */
1565 if (WLCONF_PHYTYPE_11N(val
)) {
1566 str
= nvram_get(strcat_r(prefix
, "nband", tmp
));
1570 WL_GETINT(name
, WLC_GET_BAND
, &val
);
1573 val
= WLCONF_PHYTYPE2BAND(val
);
1575 WL_SETINT(name
, WLC_SET_BAND
, val
);
1577 /* Check errors (card may have changed) */
1579 /* default band to the first band in band list */
1580 val
= WLCONF_STR2PHYTYPE(var
[0]);
1581 val
= WLCONF_PHYTYPE2BAND(val
);
1582 WL_SETINT(name
, WLC_SET_BAND
, val
);
1585 /* Store the resolved bandtype */
1588 /* Get current core revision */
1589 WL_IOCTL(name
, WLC_GET_REVINFO
, &rev
, sizeof(rev
));
1590 snprintf(buf
, sizeof(buf
), "%d", rev
.corerev
);
1591 nvram_set(strcat_r(prefix
, "corerev", tmp
), buf
);
1593 if ((rev
.chipnum
== BCM4716_CHIP_ID
) || (rev
.chipnum
== BCM47162_CHIP_ID
) ||
1594 (rev
.chipnum
== BCM4748_CHIP_ID
) || (rev
.chipnum
== BCM4331_CHIP_ID
) ||
1595 (rev
.chipnum
== BCM43431_CHIP_ID
) || (rev
.chipnum
== BCM5357_CHIP_ID
) ||
1596 (rev
.chipnum
== BCM53572_CHIP_ID
) || (rev
.chipnum
== BCM43236_CHIP_ID
)) {
1597 int pam_mode
= WLC_N_PREAMBLE_GF_BRCM
; /* default GF-BRCM */
1599 strcat_r(prefix
, "mimo_preamble", tmp
);
1600 if (nvram_match(tmp
, "mm"))
1601 pam_mode
= WLC_N_PREAMBLE_MIXEDMODE
;
1602 else if (nvram_match(tmp
, "gf"))
1603 pam_mode
= WLC_N_PREAMBLE_GF
;
1604 else if (nvram_match(tmp
, "auto"))
1606 WL_IOVAR_SETINT(name
, "mimo_preamble", pam_mode
);
1609 if ((rev
.chipnum
== BCM5357_CHIP_ID
) || (rev
.chipnum
== BCM53572_CHIP_ID
)) {
1610 val
= atoi(nvram_safe_get("coma_sleep"));
1612 struct {int sleep
; int delay
;} setbuf
;
1613 nvram_unset("coma_sleep");
1617 WL_IOVAR_SET(name
, "coma", &setbuf
, sizeof(setbuf
));
1621 /* Get current phy type */
1622 WL_IOCTL(name
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
1623 printf("%s: PHYTYPE: %d\n", __FUNCTION__
, phytype
);
1624 snprintf(buf
, sizeof(buf
), "%s", WLCONF_PHYTYPE2STR(phytype
));
1625 nvram_set(strcat_r(prefix
, "phytype", tmp
), buf
);
1627 /* Setup regulatory mode */
1628 strcat_r(prefix
, "reg_mode", tmp
);
1629 if (nvram_match(tmp
, "off")) {
1631 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1632 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1633 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1634 } else if (nvram_match(tmp
, "h") || nvram_match(tmp
, "strict_h")) {
1636 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1638 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1640 if (nvram_match(tmp
, "h"))
1644 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1646 /* Set the CAC parameters */
1647 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dfs_preism", tmp
)));
1648 wl_iovar_setint(name
, "dfs_preism", val
);
1649 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dfs_postism", tmp
)));
1650 wl_iovar_setint(name
, "dfs_postism", val
);
1651 val
= atoi(nvram_safe_get(strcat_r(prefix
, "tpc_db", tmp
)));
1652 WL_IOCTL(name
, WLC_SEND_PWR_CONSTRAINT
, &val
, sizeof(val
));
1654 } else if (nvram_match(tmp
, "d")) {
1656 WL_IOCTL(name
, WLC_SET_RADAR
, &val
, sizeof(val
));
1657 WL_IOCTL(name
, WLC_SET_SPECT_MANAGMENT
, &val
, sizeof(val
));
1659 WL_IOCTL(name
, WLC_SET_REGULATORY
, &val
, sizeof(val
));
1662 /* set bandwidth capability for nphy and calculate nbw */
1663 if (WLCONF_PHYTYPE_11N(phytype
)) {
1664 /* Get the user nmode setting now */
1665 nmode
= AUTO
; /* enable by default for NPHY */
1667 strcat_r(prefix
, "nmode", tmp
);
1668 if (nvram_match(tmp
, "0"))
1671 val
= (nmode
!= OFF
) ? atoi(nvram_safe_get(strcat_r(prefix
, "nbw_cap", tmp
))) :
1674 WL_IOVAR_SETINT(name
, "nmode", (uint32
)nmode
);
1675 WL_IOVAR_SETINT(name
, "mimo_bw_cap", val
);
1677 if (((bandtype
== WLC_BAND_2G
) && (val
== WLC_N_BW_40ALL
)) ||
1678 ((bandtype
== WLC_BAND_5G
) &&
1679 (val
== WLC_N_BW_40ALL
|| val
== WLC_N_BW_20IN2G_40IN5G
)))
1680 nbw
= WL_CHANSPEC_BW_40
;
1682 nbw
= WL_CHANSPEC_BW_20
;
1684 /* Save n mode to OFF */
1685 nvram_set(strcat_r(prefix
, "nmode", tmp
), "0");
1688 /* Set channel before setting gmode or rateset */
1689 /* Manual Channel Selection - when channel # is not 0 */
1690 val
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
)));
1691 if (val
&& !WLCONF_PHYTYPE_11N(phytype
)) {
1692 WL_SETINT(name
, WLC_SET_CHANNEL
, val
);
1694 /* Use current channel (card may have changed) */
1695 WL_IOCTL(name
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
1696 snprintf(buf
, sizeof(buf
), "%d", ci
.target_channel
);
1697 nvram_set(strcat_r(prefix
, "channel", tmp
), buf
);
1699 } else if (val
&& WLCONF_PHYTYPE_11N(phytype
)) {
1700 chanspec_t chanspec
= 0;
1702 uint nctrlsb
= WL_CHANSPEC_CTL_SB_NONE
;
1706 /* Get Ctrl SB for 40MHz channel */
1707 if (nbw
== WL_CHANSPEC_BW_40
) {
1708 str
= nvram_safe_get(strcat_r(prefix
, "nctrlsb", tmp
));
1710 /* Adjust the channel to be center channel */
1711 if (!strcmp(str
, "lower")) {
1712 nctrlsb
= WL_CHANSPEC_CTL_SB_LOWER
;
1713 channel
= channel
+ 2;
1714 } else if (!strcmp(str
, "upper")) {
1715 nctrlsb
= WL_CHANSPEC_CTL_SB_UPPER
;
1716 channel
= channel
- 2;
1720 /* band | BW | CTRL SB | Channel */
1721 chanspec
|= ((bandtype
<< WL_CHANSPEC_BAND_SHIFT
) |
1722 (nbw
| nctrlsb
| channel
));
1724 WL_IOVAR_SETINT(name
, "chanspec", (uint32
)chanspec
);
1727 /* Set up number of Tx and Rx streams */
1728 if (WLCONF_PHYTYPE_11N(phytype
)) {
1733 /* Get the number of tx chains supported by the hardware */
1734 wl_iovar_getint(name
, "hw_txchain", &count
);
1735 /* update NVRAM with capabilities */
1736 snprintf(var
, sizeof(var
), "%d", count
);
1737 nvram_set(strcat_r(prefix
, "hw_txchain", tmp
), var
);
1739 /* Verify that there is an NVRAM param for txstreams, if not create it and
1740 * set it to hw_txchain
1742 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "txchain", tmp
)));
1744 /* invalid - NVRAM needs to be fixed/initialized */
1745 nvram_set(strcat_r(prefix
, "txchain", tmp
), var
);
1748 /* Apply user configured txstreams, use 1 if user disabled nmode */
1749 WL_IOVAR_SETINT(name
, "txchain", streams
);
1751 wl_iovar_getint(name
, "hw_rxchain", &count
);
1752 /* update NVRAM with capabilities */
1753 snprintf(var
, sizeof(var
), "%d", count
);
1754 nvram_set(strcat_r(prefix
, "hw_rxchain", tmp
), var
);
1756 /* Verify that there is an NVRAM param for rxstreams, if not create it and
1757 * set it to hw_txchain
1759 streams
= atoi(nvram_safe_get(strcat_r(prefix
, "rxchain", tmp
)));
1761 /* invalid - NVRAM needs to be fixed/initialized */
1762 nvram_set(strcat_r(prefix
, "rxchain", tmp
), var
);
1766 /* Apply user configured rxstreams, use 1 if user disabled nmode */
1767 WL_IOVAR_SETINT(name
, "rxchain", streams
);
1769 /* update the spatial policy to make chain changes effect */
1770 if (phytype
== PHY_TYPE_HT
) {
1771 wl_iovar_getint(name
, "spatial_policy", &policy
);
1772 WL_IOVAR_SETINT(name
, "spatial_policy", policy
);
1776 /* Reset to hardware rateset (band may have changed) */
1777 WL_IOCTL(name
, WLC_GET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1778 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1781 if (bandtype
== WLC_BAND_2G
) {
1782 int override
= WLC_PROTECTION_OFF
;
1783 int control
= WLC_PROTECTION_CTL_OFF
;
1786 gmode
= atoi(nvram_safe_get(strcat_r(prefix
, "gmode", tmp
)));
1787 WL_IOCTL(name
, WLC_SET_GMODE
, &gmode
, sizeof(gmode
));
1789 /* Set gmode protection override and control algorithm */
1790 strcat_r(prefix
, "gmode_protection", tmp
);
1791 if (nvram_match(tmp
, "auto")) {
1792 override
= WLC_PROTECTION_AUTO
;
1793 control
= WLC_PROTECTION_CTL_OVERLAP
;
1795 WL_IOCTL(name
, WLC_SET_GMODE_PROTECTION_OVERRIDE
, &override
, sizeof(override
));
1796 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
1799 /* Set nmode_protection */
1800 if (WLCONF_PHYTYPE_11N(phytype
)) {
1801 int override
= WLC_PROTECTION_OFF
;
1802 int control
= WLC_PROTECTION_CTL_OFF
;
1804 /* Set n protection override and control algorithm */
1805 str
= nvram_get(strcat_r(prefix
, "nmode_protection", tmp
));
1806 if (!str
|| !strcmp(str
, "auto")) {
1807 override
= WLC_PROTECTION_AUTO
;
1808 control
= WLC_PROTECTION_CTL_OVERLAP
;
1811 WL_IOVAR_SETINT(name
, "nmode_protection_override",
1813 WL_IOCTL(name
, WLC_SET_PROTECTION_CONTROL
, &control
, sizeof(control
));
1816 /* Set 802.11n required */
1818 uint32 nreqd
= OFF
; /* default */
1820 strcat_r(prefix
, "nreqd", tmp
);
1822 if (nvram_match(tmp
, "1"))
1825 WL_IOVAR_SETINT(name
, "nreqd", nreqd
);
1828 /* Set vlan_prio_mode */
1830 uint32 mode
= OFF
; /* default */
1832 strcat_r(prefix
, "vlan_prio_mode", tmp
);
1834 if (nvram_match(tmp
, "on"))
1837 WL_IOVAR_SETINT(name
, "vlan_mode", mode
);
1840 /* Get bluetooth coexistance(BTC) mode */
1841 btc_mode
= atoi(nvram_safe_get(strcat_r(prefix
, "btc_mode", tmp
)));
1843 /* Set the afterburner, AMPDU and AMSDU options based on the N-mode */
1844 wme_global
= wlconf_aburn_ampdu_amsdu_set(name
, prefix
, nmode
, btc_mode
);
1846 /* Now that wme_global is known, check per-BSS disable settings */
1847 for (i
= 0; i
< bclist
->count
; i
++) {
1849 bsscfg
= &bclist
->bsscfgs
[i
];
1851 subprefix
= apsta
? prefix
: bsscfg
->prefix
;
1853 /* For each BSS, check WME; make sure wme is set properly for this interface */
1854 strcat_r(subprefix
, "wme", tmp
);
1855 nvram_set(tmp
, wme_global
? "on" : "off");
1857 str
= nvram_safe_get(strcat_r(bsscfg
->prefix
, "wme_bss_disable", tmp
));
1858 val
= (str
[0] == '1') ? 1 : 0;
1859 WL_BSSIOVAR_SETINT(name
, "wme_bss_disable", bsscfg
->idx
, val
);
1862 /* Get current rateset (gmode may have changed) */
1863 WL_IOCTL(name
, WLC_GET_CURR_RATESET
, &rs
, sizeof(wl_rateset_t
));
1865 strcat_r(prefix
, "rateset", tmp
);
1866 if (nvram_match(tmp
, "all")) {
1867 /* Make all rates basic */
1868 for (i
= 0; i
< rs
.count
; i
++)
1869 rs
.rates
[i
] |= 0x80;
1870 } else if (nvram_match(tmp
, "12")) {
1871 /* Make 1 and 2 basic */
1872 for (i
= 0; i
< rs
.count
; i
++) {
1873 if ((rs
.rates
[i
] & 0x7f) == 2 || (rs
.rates
[i
] & 0x7f) == 4)
1874 rs
.rates
[i
] |= 0x80;
1876 rs
.rates
[i
] &= ~0x80;
1880 if (phytype
!= PHY_TYPE_SSN
&& phytype
!= PHY_TYPE_LCN
) {
1882 if (!wl_iovar_setint(name
, "btc_mode", btc_mode
)) {
1883 if (btc_mode
== WL_BTC_PREMPT
) {
1884 wl_rateset_t rs_tmp
= rs
;
1885 /* remove 1Mbps and 2 Mbps from rateset */
1886 for (i
= 0, rs
.count
= 0; i
< rs_tmp
.count
; i
++) {
1887 if ((rs_tmp
.rates
[i
] & 0x7f) == 2 ||
1888 (rs_tmp
.rates
[i
] & 0x7f) == 4)
1890 rs
.rates
[rs
.count
++] = rs_tmp
.rates
[i
];
1897 WL_IOCTL(name
, WLC_SET_RATESET
, &rs
, sizeof(wl_rateset_t
));
1899 /* Allow short preamble settings for the following:
1901 * 11g - short /long in GMODE_LEGACY_B and GMODE_AUTO gmodes
1902 * GMODE_PERFORMANCE and GMODE_LRS will use short and long
1903 * preambles respectively, by default
1904 * 11n - short/long applicable in 2.4G band only
1906 if (phytype
== PHY_TYPE_B
||
1907 (WLCONF_PHYTYPE_11N(phytype
) && (bandtype
== WLC_BAND_2G
)) ||
1908 ((phytype
== PHY_TYPE_G
|| phytype
== PHY_TYPE_LP
) &&
1909 (gmode
== GMODE_LEGACY_B
|| gmode
== GMODE_AUTO
))) {
1910 strcat_r(prefix
, "plcphdr", tmp
);
1911 if (nvram_match(tmp
, "long"))
1912 val
= WLC_PLCP_AUTO
;
1914 val
= WLC_PLCP_SHORT
;
1915 WL_IOCTL(name
, WLC_SET_PLCPHDR
, &val
, sizeof(val
));
1918 /* Set rate in 500 Kbps units */
1919 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rate", tmp
))) / 500000;
1921 /* Convert Auto mcsidx to Auto rate */
1922 if (WLCONF_PHYTYPE_11N(phytype
)) {
1923 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
1925 /* -1 mcsidx used to designate AUTO rate */
1930 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1931 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
1932 /* Must b/g band. Set to 5.5Mbps */
1935 /* it is band-blind. try both band */
1936 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
1937 error_a
= wl_iovar_setint(name
, "a_rate", val
);
1939 if (error_bg
&& error_a
) {
1940 /* both failed. Try default rate (card may have changed) */
1943 error_bg
= wl_iovar_setint(name
, "bg_rate", val
);
1944 error_a
= wl_iovar_setint(name
, "a_rate", val
);
1946 snprintf(buf
, sizeof(buf
), "%d", val
);
1947 nvram_set(strcat_r(prefix
, "rate", tmp
), buf
);
1950 /* check if nrate needs to be applied */
1953 int mcsidx
= atoi(nvram_safe_get(strcat_r(prefix
, "nmcsidx", tmp
)));
1954 bool ismcs
= (mcsidx
>= 0);
1956 /* mcsidx of 32 is valid only for 40 Mhz */
1957 if (mcsidx
== 32 && nbw
== WL_CHANSPEC_BW_20
) {
1960 nvram_set(strcat_r(prefix
, "nmcsidx", tmp
), "-1");
1963 /* Use nrate iovar only for MCS rate. */
1965 nrate
|= NRATE_MCS_INUSE
;
1966 nrate
|= mcsidx
& NRATE_RATE_MASK
;
1968 WL_IOVAR_SETINT(name
, "nrate", nrate
);
1972 /* Set multicast rate in 500 Kbps units */
1973 val
= atoi(nvram_safe_get(strcat_r(prefix
, "mrate", tmp
))) / 500000;
1974 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1975 if (btc_mode
== WL_BTC_PREMPT
&& (val
== 2 || val
== 4))
1976 /* Must b/g band. Set to 5.5Mbps */
1979 /* it is band-blind. try both band */
1980 error_bg
= wl_iovar_setint(name
, "bg_mrate", val
);
1981 error_a
= wl_iovar_setint(name
, "a_mrate", val
);
1983 if (error_bg
&& error_a
) {
1984 /* Try default rate (card may have changed) */
1987 wl_iovar_setint(name
, "bg_mrate", val
);
1988 wl_iovar_setint(name
, "a_mrate", val
);
1990 snprintf(buf
, sizeof(buf
), "%d", val
);
1991 nvram_set(strcat_r(prefix
, "mrate", tmp
), buf
);
1994 /* Set fragmentation threshold */
1995 val
= atoi(nvram_safe_get(strcat_r(prefix
, "frag", tmp
)));
1996 wl_iovar_setint(name
, "fragthresh", val
);
1998 /* Set RTS threshold */
1999 val
= atoi(nvram_safe_get(strcat_r(prefix
, "rts", tmp
)));
2000 wl_iovar_setint(name
, "rtsthresh", val
);
2002 /* Set DTIM period */
2003 val
= atoi(nvram_safe_get(strcat_r(prefix
, "dtim", tmp
)));
2004 WL_IOCTL(name
, WLC_SET_DTIMPRD
, &val
, sizeof(val
));
2006 /* Set beacon period */
2007 val
= atoi(nvram_safe_get(strcat_r(prefix
, "bcn", tmp
)));
2008 WL_IOCTL(name
, WLC_SET_BCNPRD
, &val
, sizeof(val
));
2010 /* Set beacon rotation */
2011 str
= nvram_get(strcat_r(prefix
, "bcn_rotate", tmp
));
2013 /* No nvram variable found, use the default */
2014 str
= "1"; //nvram_default_get(strcat_r(prefix, "bcn_rotate", tmp));
2017 wl_iovar_setint(name
, "bcn_rotate", val
);
2019 /* Set framebursting mode */
2020 if (btc_mode
== WL_BTC_PREMPT
)
2023 val
= nvram_match(strcat_r(prefix
, "frameburst", tmp
), "on");
2024 WL_IOCTL(name
, WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
2026 /* Enable or disable PLC failover */
2027 val
= atoi(nvram_safe_get(strcat_r(prefix
, "plc", tmp
)));
2028 WL_IOVAR_SETINT(name
, "plc", val
);
2030 /* Set STBC tx and rx mode */
2031 if (phytype
== PHY_TYPE_N
|| phytype
== PHY_TYPE_HT
) {
2032 char *nvram_str
= nvram_safe_get(strcat_r(prefix
, "stbc_tx", tmp
));
2034 if (!strcmp(nvram_str
, "auto")) {
2035 WL_IOVAR_SETINT(name
, "stbc_tx", AUTO
);
2036 } else if (!strcmp(nvram_str
, "on")) {
2037 WL_IOVAR_SETINT(name
, "stbc_tx", ON
);
2038 } else if (!strcmp(nvram_str
, "off")) {
2039 WL_IOVAR_SETINT(name
, "stbc_tx", OFF
);
2041 val
= atoi(nvram_safe_get(strcat_r(prefix
, "stbc_rx", tmp
)));
2042 WL_IOVAR_SETINT(name
, "stbc_rx", val
);
2045 /* Set RIFS mode based on framebursting */
2046 if (WLCONF_PHYTYPE_11N(phytype
)) {
2047 char *nvram_str
= nvram_safe_get(strcat_r(prefix
, "rifs", tmp
));
2048 if (!strcmp(nvram_str
, "on"))
2049 wl_iovar_setint(name
, "rifs", ON
);
2050 else if (!strcmp(nvram_str
, "off"))
2051 wl_iovar_setint(name
, "rifs", OFF
);
2053 /* RIFS mode advertisement */
2054 nvram_str
= nvram_safe_get(strcat_r(prefix
, "rifs_advert", tmp
));
2055 if (!strcmp(nvram_str
, "auto"))
2056 wl_iovar_setint(name
, "rifs_advert", AUTO
);
2057 else if (!strcmp(nvram_str
, "off"))
2058 wl_iovar_setint(name
, "rifs_advert", OFF
);
2061 /* Override BA mode only if set to on/off */
2062 ba
= nvram_safe_get(strcat_r(prefix
, "ba", tmp
));
2063 if (!strcmp(ba
, "on"))
2064 wl_iovar_setint(name
, "ba", ON
);
2065 else if (!strcmp(ba
, "off"))
2066 wl_iovar_setint(name
, "ba", OFF
);
2068 if (WLCONF_PHYTYPE_11N(phytype
)) {
2069 val
= AVG_DMA_XFER_RATE
;
2070 wl_iovar_set(name
, "avg_dma_xfer_rate", &val
, sizeof(val
));
2073 /* Bring the interface back up */
2074 WL_IOCTL(name
, WLC_UP
, NULL
, 0);
2077 val
= atoi(nvram_safe_get(strcat_r(prefix
, "antdiv", tmp
)));
2078 WL_IOCTL(name
, WLC_SET_ANTDIV
, &val
, sizeof(val
));
2080 /* Set radar parameters if it is enabled */
2082 wlconf_set_radarthrs(name
, prefix
);
2085 /* Set channel interference threshold value if it is enabled */
2086 str
= nvram_get(strcat_r(prefix
, "glitchthres", tmp
));
2089 int glitch_thres
= atoi(str
);
2090 if (glitch_thres
> 0)
2091 WL_IOVAR_SETINT(name
, "chanim_glitchthres", glitch_thres
);
2094 str
= nvram_get(strcat_r(prefix
, "ccathres", tmp
));
2097 int cca_thres
= atoi(str
);
2099 WL_IOVAR_SETINT(name
, "chanim_ccathres", cca_thres
);
2102 str
= nvram_get(strcat_r(prefix
, "chanimmode", tmp
));
2105 int chanim_mode
= atoi(str
);
2106 if (chanim_mode
>= 0)
2107 WL_IOVAR_SETINT(name
, "chanim_mode", chanim_mode
);
2110 /* Overlapping BSS Coexistence aka 20/40 Coex. aka OBSS Coex.
2111 * For an AP - Only use if 2G band AND user wants a 40Mhz chanspec.
2112 * For a STA - Always
2114 if (WLCONF_PHYTYPE_11N(phytype
)) {
2116 ((ap
|| apsta
) && (nbw
== WL_CHANSPEC_BW_40
) && (bandtype
== WLC_BAND_2G
))) {
2117 str
= nvram_safe_get(strcat_r(prefix
, "obss_coex", tmp
));
2119 /* No nvram variable found, use the default */
2120 str
= "0"; //nvram_default_get(strcat_r(prefix, "obss_coex", tmp));
2122 obss_coex
= atoi(str
);
2124 /* Need to disable obss coex in case of 20MHz and/or
2130 /* force coex off for msgtest build */
2133 WL_IOVAR_SETINT(name
, "obss_coex", obss_coex
);
2136 /* Auto Channel Selection:
2137 * 1. When channel # is 0 in AP mode, this determines our channel and 20Mhz vs. 40Mhz
2138 * 2. If we're running OBSS Coex and the user specified a channel, Autochannel runs to
2139 * do an initial scan to help us make decisions about whether we can create a 40Mhz AP
2141 /* The following condition(s) must be met in order for Auto Channel Selection to work.
2142 * - the I/F must be up for the channel scan
2143 * - the AP must not be supporting a BSS (all BSS Configs must be disabled)
2146 int channel
= atoi(nvram_safe_get(strcat_r(prefix
, "channel", tmp
)));
2152 val
= nvram_safe_get("acs_mode");
2154 if (!strcmp(val
, "legacy") || (rev
.chipnum
== BCM4331_CHIP_ID
) ||
2155 (rev
.chipnum
== BCM43431_CHIP_ID
))
2158 snprintf(tmp
, sizeof(tmp
), "acs_ifnames");
2159 ptr
= nvram_get(tmp
);
2161 snprintf(buf
, sizeof(buf
), "%s %s", ptr
, name
);
2163 strncpy(buf
, name
, sizeof(buf
));
2164 nvram_set(tmp
, buf
);
2168 #endif /* EXT_ACS */
2169 if (obss_coex
|| channel
== 0) {
2170 if (WLCONF_PHYTYPE_11N(phytype
)) {
2171 chanspec_t chanspec
;
2175 /* assumes that initial chanspec has been set earlier */
2176 /* Maybe we expand scope of chanspec from above so
2177 * that we don't have to do the iovar_get here?
2180 /* We're not doing auto-channel, give the driver
2181 * the preferred chanspec.
2183 WL_IOVAR_GETINT(name
, "chanspec", &pref_chspec
);
2184 WL_IOVAR_SETINT(name
, "pref_chanspec", pref_chspec
);
2186 WL_IOVAR_SETINT(name
, "pref_chanspec", 0);
2188 chanspec
= wlconf_auto_chanspec(name
);
2190 WL_IOVAR_SETINT(name
, "chanspec", chanspec
);
2192 /* select a channel */
2193 val
= wlconf_auto_channel(name
);
2194 /* switch to the selected channel */
2196 WL_IOCTL(name
, WLC_SET_CHANNEL
, &val
, sizeof(val
));
2198 /* set the auto channel scan timer in the driver when in auto mode */
2200 val
= 15; /* 15 minutes for now */
2205 /* reset the channel scan timer in the driver when not in auto mode */
2209 WL_IOCTL(name
, WLC_SET_CS_SCAN_TIMER
, &val
, sizeof(val
));
2210 WL_IOVAR_SETINT(name
, "chanim_mode", CHANIM_ACT
);
2217 /* Security settings for each BSS Configuration */
2218 for (i
= 0; i
< bclist
->count
; i
++) {
2219 bsscfg
= &bclist
->bsscfgs
[i
];
2220 wlconf_security_options(name
, bsscfg
->prefix
, bsscfg
->idx
, mac_spoof
,
2221 (wet
|| sta
|| apsta
));
2225 * Finally enable BSS Configs or Join BSS
2227 * AP: Enable BSS Config to bring AP up only when nas will not run
2228 * STA: Join the BSS regardless.
2230 for (i
= 0; i
< bclist
->count
; i
++) {
2231 struct {int bsscfg_idx
; int enable
;} setbuf
;
2232 char vifname
[VIFNAME_LEN
];
2233 char *name_ptr
= name
;
2235 setbuf
.bsscfg_idx
= bclist
->bsscfgs
[i
].idx
;
2238 bsscfg
= &bclist
->bsscfgs
[i
];
2239 if (nvram_match(strcat_r(bsscfg
->prefix
, "bss_enabled", tmp
), "1")) {
2243 /* Set the MAC list */
2244 maclist
= (struct maclist
*)buf
;
2246 if (!nvram_match(strcat_r(bsscfg
->prefix
, "macmode", tmp
), "disabled")) {
2248 foreach(var
, nvram_safe_get(strcat_r(bsscfg
->prefix
, "maclist", tmp
)),
2250 if (((char *)((&ea
[1])->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
2252 if (ether_atoe(var
, ea
->octet
)) {
2259 if (setbuf
.bsscfg_idx
== 0) {
2261 } else { /* Non-primary BSS; changes name syntax */
2262 char tmp
[VIFNAME_LEN
];
2265 /* Remove trailing _ if present */
2266 memset(tmp
, 0, sizeof(tmp
));
2267 strncpy(tmp
, bsscfg
->prefix
, VIFNAME_LEN
- 1);
2268 if (((len
= strlen(tmp
)) > 0) && (tmp
[len
- 1] == '_')) {
2271 nvifname_to_osifname(tmp
, vifname
, VIFNAME_LEN
);
2275 WL_IOCTL(name_ptr
, WLC_SET_MACLIST
, buf
, sizeof(buf
));
2277 /* Set macmode for each VIF */
2278 (void) strcat_r(bsscfg
->prefix
, "macmode", tmp
);
2280 if (nvram_match(tmp
, "deny"))
2281 val
= WLC_MACMODE_DENY
;
2282 else if (nvram_match(tmp
, "allow"))
2283 val
= WLC_MACMODE_ALLOW
;
2285 val
= WLC_MACMODE_DISABLED
;
2287 WL_IOCTL(name_ptr
, WLC_SET_MACMODE
, &val
, sizeof(val
));
2299 wlconf_down(char *name
)
2305 struct {int bsscfg_idx
; int enable
;} setbuf
;
2306 int wl_ap_build
= 0; /* 1 = wl compiled with AP capabilities */
2307 char cap
[WLC_IOCTL_SMLEN
];
2308 char caps
[WLC_IOCTL_SMLEN
];
2312 /* wlconf doesn't work for virtual i/f */
2313 if (get_ifname_unit(name
, NULL
, &wlsubunit
) == 0 && wlsubunit
>= 0) {
2314 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name
);
2318 /* Check interface (fail silently for non-wl interfaces) */
2319 if ((ret
= wl_probe(name
)))
2322 /* because of ifdefs in wl driver, when we don't have AP capabilities we
2323 * can't use the same iovars to configure the wl.
2324 * so we use "wl_ap_build" to help us know how to configure the driver
2326 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
2329 foreach(cap
, caps
, next
) {
2330 if (!strcmp(cap
, "ap")) {
2336 /* Bring down the interface */
2337 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
2339 /* Disable all BSS Configs */
2340 for (i
= 0; i
< WL_MAXBSSCFG
; i
++) {
2341 setbuf
.bsscfg_idx
= i
;
2344 ret
= wl_iovar_set(name
, "bss", &setbuf
, sizeof(setbuf
));
2346 wl_iovar_getint(name
, "bcmerror", &bcmerr
);
2347 /* fail quietly on a range error since the driver may
2348 * support fewer bsscfgs than we are prepared to configure
2350 if (bcmerr
== BCME_RANGE
)
2355 WL_IOCTL(name
, WLC_GET_UP
, &val
, sizeof(val
));
2359 ssid
.SSID
[0] = '\0';
2360 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
2362 /* Bring down the interface */
2363 WL_IOCTL(name
, WLC_DOWN
, NULL
, sizeof(val
));
2367 /* Nuke the WDS list */
2368 wlconf_wds_clear(name
);
2374 wlconf_start(char *name
)
2376 int i
, ii
, unit
, val
, ret
= 0;
2379 int ap
, apsta
, wds
, sta
= 0, wet
= 0;
2380 int wl_ap_build
= 0; /* wl compiled with AP capabilities */
2381 char buf
[WLC_IOCTL_SMLEN
];
2382 struct maclist
*maclist
;
2383 struct ether_addr
*ea
;
2384 struct bsscfg_list
*bclist
= NULL
;
2385 struct bsscfg_info
*bsscfg
;
2387 char cap
[WLC_IOCTL_SMLEN
], caps
[WLC_IOCTL_SMLEN
];
2388 char var
[80], tmp
[100], prefix
[PREFIX_LEN
], *str
, *next
;
2390 /* Check interface (fail silently for non-wl interfaces) */
2391 if ((ret
= wl_probe(name
)))
2394 /* wlconf doesn't work for virtual i/f, so if we are given a
2395 * virtual i/f return 0 if that interface is in it's parent's "vifs"
2396 * list otherwise return -1
2398 memset(tmp
, 0, sizeof(tmp
));
2399 if (get_ifname_unit(name
, &wlunit
, &wlsubunit
) == 0) {
2400 if (wlsubunit
>= 0) {
2401 /* we have been given a virtual i/f,
2402 * is it in it's parent i/f's virtual i/f list?
2404 sprintf(tmp
, "wl%d_vifs", wlunit
);
2406 if (strstr(nvram_safe_get(tmp
), name
) == NULL
)
2407 return -1; /* config error */
2409 return 0; /* okay */
2416 /* because of ifdefs in wl driver, when we don't have AP capabilities we
2417 * can't use the same iovars to configure the wl.
2418 * so we use "wl_ap_build" to help us know how to configure the driver
2420 if (wl_iovar_get(name
, "cap", (void *)caps
, WLC_IOCTL_SMLEN
))
2423 foreach(cap
, caps
, next
) {
2424 if (!strcmp(cap
, "ap"))
2429 WL_IOCTL(name
, WLC_GET_INSTANCE
, &unit
, sizeof(unit
));
2430 snprintf(prefix
, sizeof(prefix
), "wl%d_", unit
);
2433 /* Get the list of BSS Configs */
2434 if (!(bclist
= wlconf_get_bsscfgs(name
, prefix
)))
2437 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
2438 str
= nvram_safe_get(strcat_r(prefix
, "mode", tmp
));
2439 ap
= (!strcmp(str
, "") || !strcmp(str
, "ap"));
2440 apsta
= (!strcmp(str
, "apsta") ||
2441 ((!strcmp(str
, "sta") || !strcmp(str
, "wet")) &&
2442 bclist
->count
> 1));
2443 sta
= (!strcmp(str
, "sta") && bclist
->count
== 1);
2444 wds
= !strcmp(str
, "wds");
2445 wet
= !strcmp(str
, "wet");
2446 if (!strcmp(str
, "mac_spoof"))
2449 /* Retain remaining WET effects only if not APSTA */
2452 /* AP only config, code copied as-is from wlconf function */
2453 if (ap
|| apsta
|| wds
) {
2454 /* Set lazy WDS mode */
2455 val
= atoi(nvram_safe_get(strcat_r(prefix
, "lazywds", tmp
)));
2456 WL_IOCTL(name
, WLC_SET_LAZYWDS
, &val
, sizeof(val
));
2458 /* Set the WDS list */
2459 maclist
= (struct maclist
*) buf
;
2462 foreach(var
, nvram_safe_get(strcat_r(prefix
, "wds", tmp
)), next
) {
2463 if (((char *)(ea
->octet
)) > ((char *)(&buf
[sizeof(buf
)])))
2465 ether_atoe(var
, ea
->octet
);
2469 WL_IOCTL(name
, WLC_SET_WDSLIST
, buf
, sizeof(buf
));
2471 /* Set WDS link detection timeout */
2472 val
= atoi(nvram_safe_get(strcat_r(prefix
, "wds_timeout", tmp
)));
2473 wl_iovar_setint(name
, "wdstimeout", val
);
2477 * Finally enable BSS Configs or Join BSS
2478 * code copied as-is from wlconf function
2480 for (i
= 0; i
< bclist
->count
; i
++) {
2481 struct {int bsscfg_idx
; int enable
;} setbuf
;
2483 setbuf
.bsscfg_idx
= bclist
->bsscfgs
[i
].idx
;
2486 bsscfg
= &bclist
->bsscfgs
[i
];
2487 if (nvram_match(strcat_r(bsscfg
->prefix
, "bss_enabled", tmp
), "1")) {
2492 if (ap
|| apsta
|| sta
|| wet
) {
2493 for (ii
= 0; ii
< MAX_BSS_UP_RETRIES
; ii
++) {
2495 WL_IOVAR_SET(name
, "bss", &setbuf
, sizeof(setbuf
));
2498 strcat_r(prefix
, "ssid", tmp
);
2499 ssid
.SSID_len
= strlen(nvram_safe_get(tmp
));
2500 if (ssid
.SSID_len
> sizeof(ssid
.SSID
))
2501 ssid
.SSID_len
= sizeof(ssid
.SSID
);
2502 strncpy((char *)ssid
.SSID
, nvram_safe_get(tmp
),
2504 WL_IOCTL(name
, WLC_SET_SSID
, &ssid
, sizeof(ssid
));
2506 if (apsta
&& (ret
!= 0))
2522 main(int argc
, char *argv
[])
2524 /* Check parameters and branch based on action */
2525 if (argc
== 3 && !strcmp(argv
[2], "up"))
2526 return wlconf(argv
[1]);
2527 else if (argc
== 3 && !strcmp(argv
[2], "down"))
2528 return wlconf_down(argv
[1]);
2529 else if (argc
== 3 && !strcmp(argv
[2], "start"))
2530 return wlconf_start(argv
[1]);
2532 fprintf(stderr
, "Usage: wlconf <ifname> up|down\n");
2536 #endif /* defined(linux) */