cosmetics
[tomato.git] / release / src-rt-6.x.4708 / router / wlconf_arm / wlconf.c
blob977581310f68d9aca091dc0a5e85ea8514c83a73
1 /*
2 * Wireless Network Adapter Configuration Utility
4 * Copyright (C) 2014, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: wlconf.c 454872 2014-02-12 02:49:54Z $
15 #include <typedefs.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <assert.h>
20 #include <bcmnvram.h>
21 #include <bcmutils.h>
22 #include <bcmparams.h>
23 #include <bcmdevs.h>
24 #include <shutils.h>
25 #include <wlutils.h>
26 #include <wlioctl.h>
27 #include <proto/802.1d.h>
28 #include <bcmconfig.h>
29 #include <bcmwifi_channels.h>
30 #include <netconf.h>
31 #include <nvparse.h>
32 #include <arpa/inet.h>
34 #if defined(linux)
35 #include <sys/utsname.h>
36 #endif
38 /* phy types */
39 #define PHY_TYPE_A 0
40 #define PHY_TYPE_B 1
41 #define PHY_TYPE_G 2
42 #define PHY_TYPE_N 4
43 #define PHY_TYPE_LP 5
44 #define PHY_TYPE_SSN 6
45 #define PHY_TYPE_HT 7
46 #define PHY_TYPE_LCN 8
47 #define PHY_TYPE_AC 11
48 #define PHY_TYPE_NULL 0xf
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
67 * Debugging Macros
69 #ifdef BCMDBG
70 #define WLCONF_DBG(fmt, arg...) printf("%s: "fmt, __FUNCTION__ , ## arg)
71 #define WL_IOCTL(ifname, cmd, buf, len) \
72 if ((ret = wl_ioctl(ifname, cmd, buf, len))) \
73 fprintf(stderr, "%s:%d:(%s): %s failed, err = %d\n", \
74 __FUNCTION__, __LINE__, ifname, #cmd, ret);
75 #define WL_SETINT(ifname, cmd, val) \
76 if ((ret = wlconf_setint(ifname, cmd, val))) \
77 fprintf(stderr, "%s:%d:(%s): setting %s to %d (0x%x) failed, err = %d\n", \
78 __FUNCTION__, __LINE__, ifname, #cmd, (int)val, (unsigned int)val, ret);
79 #define WL_GETINT(ifname, cmd, pval) \
80 if ((ret = wlconf_getint(ifname, cmd, pval))) \
81 fprintf(stderr, "%s:%d:(%s): getting %s failed, err = %d\n", \
82 __FUNCTION__, __LINE__, ifname, #cmd, ret);
83 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) \
84 if ((ret = wl_iovar_set(ifname, iovar, param, paramlen))) \
85 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" failed, err = %d\n", \
86 __FUNCTION__, __LINE__, ifname, iovar, ret);
87 #define WL_IOVAR_GET(ifname, iovar, param, paramlen) \
88 if ((ret = wl_iovar_get(ifname, iovar, param, paramlen))) \
89 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \
90 __FUNCTION__, __LINE__, ifname, iovar, ret);
91 #define WL_IOVAR_SETINT(ifname, iovar, val) \
92 if ((ret = wl_iovar_setint(ifname, iovar, val))) \
93 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" to 0x%x failed, err = %d\n", \
94 __FUNCTION__, __LINE__, ifname, iovar, (unsigned int)val, ret);
95 #define WL_IOVAR_GETINT(ifname, iovar, val) \
96 if ((ret = wl_iovar_getint(ifname, iovar, val))) \
97 fprintf(stderr, "%s:%d:(%s): getting iovar \"%s\" failed, err = %d\n", \
98 __FUNCTION__, __LINE__, ifname, iovar, ret);
99 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
100 if ((ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))) \
101 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
102 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
103 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
104 if ((ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))) \
105 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
106 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
107 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
108 if ((ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))) \
109 fprintf(stderr, "%s:%d:(%s): getting bsscfg #%d iovar \"%s\" failed, err = %d\n", \
110 __FUNCTION__, __LINE__, ifname, bssidx, iovar, ret);
111 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) \
112 if ((ret = wl_bssiovar_setint(ifname, iovar, bssidx, val))) \
113 fprintf(stderr, "%s:%d:(%s): setting bsscfg #%d iovar \"%s\" " \
114 "to val 0x%x failed, err = %d\n", \
115 __FUNCTION__, __LINE__, ifname, bssidx, iovar, (unsigned int)val, ret);
116 #else
117 #define WLCONF_DBG(fmt, arg...)
118 #define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len))
119 #define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val))
120 #define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval))
121 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \
122 param, paramlen))
123 #define WL_IOVAR_GET(ifname, iovar, param, paramlen) (ret = wl_iovar_get(ifname, iovar, \
124 param, paramlen))
125 #define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val))
126 #define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val))
127 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
128 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))
129 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
130 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))
131 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
132 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))
133 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \
134 bssidx, val))
135 #endif /* BCMDBG */
137 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
139 /* prototypes */
140 struct bsscfg_list *wlconf_get_bsscfgs(char* ifname, char* prefix);
141 int wlconf(char *name);
142 int wlconf_down(char *name);
144 static int
145 wlconf_getint(char* ifname, int cmd, int *pval)
147 return wl_ioctl(ifname, cmd, pval, sizeof(int));
150 static int
151 wlconf_setint(char* ifname, int cmd, int val)
153 return wl_ioctl(ifname, cmd, &val, sizeof(int));
156 static int
157 wlconf_wds_clear(char *name)
159 struct maclist maclist;
160 int ret;
162 maclist.count = 0;
163 WL_IOCTL(name, WLC_SET_WDSLIST, &maclist, sizeof(maclist));
165 return ret;
168 /* set WEP key */
169 static int
170 wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i)
172 wl_wsec_key_t key;
173 char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
174 char *keystr, hex[] = "XX";
175 unsigned char *data = key.data;
176 int ret = 0;
178 memset(&key, 0, sizeof(key));
179 key.index = i - 1;
180 sprintf(wl_key, "%skey%d", prefix, i);
181 keystr = nvram_safe_get(wl_key);
183 switch (strlen(keystr)) {
184 case WEP1_KEY_SIZE:
185 case WEP128_KEY_SIZE:
186 key.len = strlen(keystr);
187 strcpy((char *)key.data, keystr);
188 break;
189 case WEP1_KEY_HEX_SIZE:
190 case WEP128_KEY_HEX_SIZE:
191 key.len = strlen(keystr) / 2;
192 while (*keystr) {
193 strncpy(hex, keystr, 2);
194 *data++ = (unsigned char) strtoul(hex, NULL, 16);
195 keystr += 2;
197 break;
198 default:
199 key.len = 0;
200 break;
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));
209 return ret;
212 static int
213 wlconf_akm_options(char *prefix)
215 char comb[32];
216 char *wl_akm;
217 int akm_ret_val = 0;
218 char akm[32];
219 char *next;
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;
234 return akm_ret_val;
237 /* Set up wsec */
238 static int
239 wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx)
241 char tmp[100];
242 int val = 0;
243 int akm_val;
244 int ret;
246 /* Set wsec bitvec */
247 akm_val = wlconf_akm_options(prefix);
248 if (akm_val != 0) {
249 if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip"))
250 val = TKIP_ENABLED;
251 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes"))
252 val = AES_ENABLED;
253 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes"))
254 val = TKIP_ENABLED | AES_ENABLED;
256 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled"))
257 val |= WEP_ENABLED;
258 WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val);
259 /* Set wsec restrict if WSEC_ENABLED */
260 WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0);
262 return 0;
265 static int
266 wlconf_set_preauth(char *name, int bsscfg_idx, int preauth)
268 uint cap;
269 int ret;
271 WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint));
272 if (ret != 0) return -1;
274 if (preauth)
275 cap |= WPA_CAP_WPA2_PREAUTH;
276 else
277 cap &= ~WPA_CAP_WPA2_PREAUTH;
279 WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap);
281 return ret;
284 static void
285 wlconf_set_radarthrs(char *name, char *prefix)
287 wl_radar_thr_t radar_thr;
288 int i, ret, len;
289 char nv_buf[NVRAM_MAX_VALUE_LEN], *rargs, *v, *endptr;
290 char buf[WLC_IOCTL_SMLEN];
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));
305 if (!rargs)
306 goto err;
308 len = strlen(rargs);
309 if ((len > NVRAM_MAX_VALUE_LEN) || (len == 0))
310 goto err;
312 memset(nv_buf, 0, sizeof(nv_buf));
313 strncpy(nv_buf, rargs, len);
314 v = nv_buf;
315 for (i = 0; i < (sizeof(locals) / sizeof(locals[0])); i++) {
316 *locals[i] = v;
317 while (*v && *v != ' ') {
318 v++;
320 if (*v) {
321 *v = 0;
322 v++;
324 if (v >= (nv_buf + len)) /* Check for complete list, if not caught later */
325 break;
328 /* Start building request */
329 memset(buf, 0, sizeof(buf));
330 strcpy(buf, "radarthrs");
331 /* Retrieve radar thrs parameters */
332 if (!version)
333 goto err;
334 radar_thr.version = atoi(version);
335 if (radar_thr.version > WL_RADAR_THR_VERSION)
336 goto err;
338 /* Retrieve ver 0 params */
339 if (!thr0_20_lo)
340 goto err;
341 radar_thr.thresh0_20_lo = (uint16)strtol(thr0_20_lo, &endptr, 0);
342 if (*endptr != '\0')
343 goto err;
345 if (!thr1_20_lo)
346 goto err;
347 radar_thr.thresh1_20_lo = (uint16)strtol(thr1_20_lo, &endptr, 0);
348 if (*endptr != '\0')
349 goto err;
351 if (!thr0_40_lo)
352 goto err;
353 radar_thr.thresh0_40_lo = (uint16)strtol(thr0_40_lo, &endptr, 0);
354 if (*endptr != '\0')
355 goto err;
357 if (!thr1_40_lo)
358 goto err;
359 radar_thr.thresh1_40_lo = (uint16)strtol(thr1_40_lo, &endptr, 0);
360 if (*endptr != '\0')
361 goto err;
363 if (!thr0_80_lo)
364 goto err;
365 radar_thr.thresh0_80_lo = (uint16)strtol(thr0_80_lo, &endptr, 0);
366 if (*endptr != '\0')
367 goto err;
369 if (!thr1_80_lo)
370 goto err;
371 radar_thr.thresh1_80_lo = (uint16)strtol(thr1_80_lo, &endptr, 0);
372 if (*endptr != '\0')
373 goto err;
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;
389 } else {
390 /* Retrieve ver 1 params */
391 if (!thr0_20_hi)
392 goto err;
393 radar_thr.thresh0_20_hi = (uint16)strtol(thr0_20_hi, &endptr, 0);
394 if (*endptr != '\0')
395 goto err;
397 if (!thr1_20_hi)
398 goto err;
399 radar_thr.thresh1_20_hi = (uint16)strtol(thr1_20_hi, &endptr, 0);
400 if (*endptr != '\0')
401 goto err;
403 if (!thr0_40_hi)
404 goto err;
405 radar_thr.thresh0_40_hi = (uint16)strtol(thr0_40_hi, &endptr, 0);
406 if (*endptr != '\0')
407 goto err;
409 if (!thr1_40_hi)
410 goto err;
411 radar_thr.thresh1_40_hi = (uint16)strtol(thr1_40_hi, &endptr, 0);
412 if (*endptr != '\0')
413 goto err;
415 if (!thr0_80_hi)
416 goto err;
417 radar_thr.thresh0_80_hi = (uint16)strtol(thr0_80_hi, &endptr, 0);
418 if (*endptr != '\0')
419 goto err;
421 if (!thr1_80_hi)
422 goto err;
423 radar_thr.thresh1_80_hi = (uint16)strtol(thr1_80_hi, &endptr, 0);
424 if (*endptr != '\0')
425 goto err;
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));
433 return;
435 err:
436 WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n");
437 return;
441 * This allows phy antenna selection to be retrieved from NVRAM
443 static void
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));
453 if (!argstr) {
454 return;
456 len = strlen(argstr);
457 if ((len == 0) || (len > NVRAM_MAX_VALUE_LEN)) {
458 return;
461 memset(nv_buf, 0, sizeof(nv_buf));
462 strncpy(nv_buf, argstr, len);
463 v = nv_buf;
464 for (argc = 0; argc < ANT_SELCFG_MAX; ) {
465 argv[argc++] = v;
466 while (*v && *v != ' ') {
467 v++;
469 if (*v) {
470 *v = 0;
471 v++;
473 if (v >= (nv_buf + len)) {
474 break;
477 if ((argc != 1) && (argc != ANT_SELCFG_MAX)) {
478 WLCONF_DBG("phy_antsel requires 1 or %d arguments\n", ANT_SELCFG_MAX);
479 return;
482 memset(buf, 0, sizeof(buf));
483 strcpy(buf, "phy_antsel");
484 for (i = 0, j = 0; i < ANT_SELCFG_MAX; i++) {
485 val.ant_config[i] = (uint8)strtol(argv[j], &endptr, 0);
486 if (*endptr != '\0') {
487 WLCONF_DBG("Invalid antsel argument\n");
488 return;
490 if (argc > 1) {
491 /* ANT_SELCFG_MAX argument format */
492 j++;
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));
500 return;
505 static void
506 wlconf_set_current_txparam_into_nvram(char *name, char *prefix)
508 int ret, aci;
509 wme_tx_params_t txparams[AC_COUNT];
510 char *nv[] = {"wme_txp_be", "wme_txp_bk", "wme_txp_vi", "wme_txp_vo"};
511 char data[50], tmp[50];
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);
528 /* Set up WME */
529 static void
530 wlconf_set_wme(char *name, char *prefix)
532 int i, j, k;
533 int val, ret;
534 int phytype, gmode, no_ack, apsd, dp[2];
535 edcf_acparam_t *acparams;
536 /* Pay attention to buffer length requirements when using this */
537 char buf[WLC_IOCTL_SMLEN*2];
538 char *v, *nv_value, nv[100];
539 char nv_name[] = "%swme_%s_%s";
540 char *ac[] = {"be", "bk", "vi", "vo"};
541 char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first;
542 char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced,
543 &oldest_first };
544 struct {char *req; char *str;} mode[] = {{"wme_ac_ap", "ap"}, {"wme_ac_sta", "sta"},
545 {"wme_tx_params", "txp"}};
547 /* query the phy type */
548 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
549 /* get gmode */
550 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", nv)));
552 /* WME sta setting first */
553 for (i = 0; i < 2; i++) {
554 /* build request block */
555 memset(buf, 0, sizeof(buf));
556 strcpy(buf, mode[i].req);
557 /* put push wmeac params after "wme-ac" in buf */
558 acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1);
559 dp[i] = 0;
560 for (j = 0; j < AC_COUNT; j++) {
561 /* get packed nvram parameter */
562 snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]);
563 nv_value = nvram_safe_get(nv);
564 strcpy(nv, nv_value);
565 /* unpack it */
566 v = nv;
567 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
568 *locals[k] = v;
569 while (*v && *v != ' ')
570 v++;
571 if (*v) {
572 *v = 0;
573 v++;
577 /* update CWmin */
578 acparams->ECW &= ~EDCF_ECWMIN_MASK;
579 val = atoi(cwmin);
580 for (val++, k = 0; val; val >>= 1, k++);
581 acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK;
582 /* update CWmax */
583 acparams->ECW &= ~EDCF_ECWMAX_MASK;
584 val = atoi(cwmax);
585 for (val++, k = 0; val; val >>= 1, k++);
586 acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK;
587 /* update AIFSN */
588 acparams->ACI &= ~EDCF_AIFSN_MASK;
589 acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK;
590 /* update ac */
591 acparams->ACI &= ~EDCF_ACI_MASK;
592 acparams->ACI |= j << EDCF_ACI_SHIFT;
593 /* update TXOP */
594 if (phytype == PHY_TYPE_B || gmode == 0)
595 val = atoi(txop_b);
596 else
597 val = atoi(txop_ag);
598 acparams->TXOP = val / 32;
599 /* update acm */
600 acparams->ACI &= ~EDCF_ACM_MASK;
601 val = strcmp(admin_forced, "on") ? 0 : 1;
602 acparams->ACI |= val << 4;
604 /* configure driver */
605 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
609 /* set no-ack */
610 v = nvram_safe_get(strcat_r(prefix, "wme_no_ack", nv));
611 no_ack = strcmp(v, "on") ? 0 : 1;
612 WL_IOVAR_SETINT(name, "wme_noack", no_ack);
614 /* set APSD */
615 v = nvram_safe_get(strcat_r(prefix, "wme_apsd", nv));
616 apsd = strcmp(v, "on") ? 0 : 1;
617 WL_IOVAR_SETINT(name, "wme_apsd", apsd);
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);
637 /* unpack it */
638 v = nv;
639 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
640 *locals[k] = v;
641 while (*v && *v != ' ')
642 v++;
643 if (*v) {
644 *v = 0;
645 v++;
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));
669 return;
672 #if defined(linux) || defined(__NetBSD__)
673 #include <unistd.h>
674 static void
675 sleep_ms(const unsigned int ms)
677 usleep(1000*ms);
679 #elif defined(__ECOS)
680 static void
681 sleep_ms(const unsigned int ms)
683 cyg_tick_count_t ostick;
685 ostick = ms / 10;
686 cyg_thread_delay(ostick);
688 #else
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
694 * is enabled.
695 * - the I/F is up (change radio channel requires it is up?)
696 * - the AP must not be associated (setting SSID to empty should
697 * make sure it for us)
699 static uint8
700 wlconf_auto_channel(char *name)
702 int chosen = 0;
703 wl_uint32_list_t request;
704 int phytype;
705 int ret;
706 int i;
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));
713 if (!ret) {
714 sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
715 for (i = 0; i < 100; i++) {
716 WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen);
717 if (!ret)
718 break;
719 sleep_ms(100);
722 WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
723 return chosen;
726 static chanspec_t
727 wlconf_auto_chanspec(char *name)
729 chanspec_t chosen = 0;
730 int temp = 0;
731 wl_uint32_list_t request;
732 int ret;
733 int i;
735 request.count = 0; /* let the ioctl decide */
736 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
737 if (!ret) {
738 /* this time needs to be < 1000 to prevent mpc kicking in for 2nd radio */
739 sleep_ms(500);
740 for (i = 0; i < 100; i++) {
741 WL_IOVAR_GETINT(name, "apcschspec", &temp);
742 if (!ret)
743 break;
744 sleep_ms(100);
748 chosen = (chanspec_t) temp;
749 WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen);
750 return 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)
779 struct bsscfg_info {
780 int idx; /* bsscfg index */
781 char ifname[PREFIX_LEN]; /* OS name of interface (debug only) */
782 char prefix[PREFIX_LEN]; /* prefix for nvram params (eg. "wl0.1_") */
785 struct bsscfg_list {
786 int count;
787 struct bsscfg_info bsscfgs[WL_MAXBSSCFG];
790 struct bsscfg_list *
791 wlconf_get_bsscfgs(char* ifname, char* prefix)
793 char var[80];
794 char tmp[100];
795 char *next;
797 struct bsscfg_list *bclist;
798 struct bsscfg_info *bsscfg;
800 bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list));
801 if (bclist == NULL)
802 return NULL;
803 memset(bclist, 0, sizeof(struct bsscfg_list));
805 /* Set up Primary BSS Config information */
806 bsscfg = &bclist->bsscfgs[0];
807 bsscfg->idx = 0;
808 strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1);
809 strcpy(bsscfg->prefix, prefix);
810 bclist->count = 1;
812 /* additional virtual BSS Configs from wlX_vifs */
813 foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) {
814 if (bclist->count == WL_MAXBSSCFG) {
815 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
816 "in nvram %s\n"
817 "while configuring interface \"%s\"\n",
818 ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var);
819 continue;
821 bsscfg = &bclist->bsscfgs[bclist->count];
822 if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) {
823 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
824 "name \"%s\"\n",
825 ifname, var);
826 continue;
828 strncpy(bsscfg->ifname, var, PREFIX_LEN-1);
829 snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname);
830 bclist->count++;
833 return bclist;
836 static void
837 wlconf_config_join_pref(char *name, int bsscfg_idx, int auth_val)
839 int ret = 0, i = 0;
841 if ((auth_val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) ||
842 CHECK_PSK(auth_val)) {
843 uchar pref[] = {
844 /* WPA pref, 14 tuples */
845 0x02, 0xaa, 0x00, 0x0e,
846 /* WPA2 AES (unicast) AES (multicast) */
847 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x04,
848 /* WPA AES (unicast) AES (multicast) */
849 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x04,
850 /* WPA2 AES (unicast) TKIP (multicast) */
851 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x02,
852 /* WPA AES (unicast) TKIP (multicast) */
853 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x02,
854 /* WPA2 AES (unicast) WEP-40 (multicast) */
855 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x01,
856 /* WPA AES (unicast) WEP-40 (multicast) */
857 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x01,
858 /* WPA2 AES (unicast) WEP-128 (multicast) */
859 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x04, 0x00, 0x0f, 0xac, 0x05,
860 /* WPA AES (unicast) WEP-128 (multicast) */
861 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x50, 0xf2, 0x05,
862 /* WPA2 TKIP (unicast) TKIP (multicast) */
863 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x02,
864 /* WPA TKIP (unicast) TKIP (multicast) */
865 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x02,
866 /* WPA2 TKIP (unicast) WEP-40 (multicast) */
867 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x01,
868 /* WPA TKIP (unicast) WEP-40 (multicast) */
869 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x01,
870 /* WPA2 TKIP (unicast) WEP-128 (multicast) */
871 0x00, 0x0f, 0xac, 0x01, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x0f, 0xac, 0x05,
872 /* WPA TKIP (unicast) WEP-128 (multicast) */
873 0x00, 0x50, 0xf2, 0x01, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x50, 0xf2, 0x05,
874 /* RSSI pref */
875 0x01, 0x02, 0x00, 0x00,
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));
888 static void
889 wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool id_supp,
890 bool check_join_pref)
892 int i;
893 int val;
894 int ret;
895 char tmp[100];
896 bool need_join_pref = FALSE;
897 #define AUTOWPA(cfg) ((cfg) == (WPA_AUTH_PSK | WPA2_AUTH_PSK))
899 /* Set WSEC */
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);
919 if (need_join_pref)
920 wlconf_config_join_pref(name, bsscfg_idx, val);
922 /* enable in-driver wpa supplicant? */
923 if (id_supp && (CHECK_PSK(val))) {
924 wsec_pmk_t psk;
925 char *key;
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);
937 if (!need_join_pref)
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);
944 /* Set WEP keys */
945 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) {
946 for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++)
947 wlconf_set_wep_key(name, prefix, bsscfg_idx, i);
950 /* Set 802.11 authentication mode - open/shared */
951 val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp)));
952 WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val);
953 #ifdef MFP
954 /* Set MFP */
955 val = WPA_AUTH_DISABLED;
956 WL_BSSIOVAR_GET(name, "wpa_auth", bsscfg_idx, &val, sizeof(val));
957 if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
958 val = atoi(nvram_safe_get(strcat_r(prefix, "mfp", tmp)));
959 WL_BSSIOVAR_SETINT(name, "mfp", bsscfg_idx, val);
961 #endif
964 static void
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);
979 /* unpack it */
980 v = nv;
981 for (j = 0; nv_len >= 0 && j < NUMPRIO; j++) {
982 retry = v;
983 while (*v && *v != ' ') {
984 v++;
985 nv_len--;
987 if (*v) {
988 *v = 0;
989 v++;
990 nv_len--;
992 /* set the AMPDU retry limit per-tid */
993 retry_limit.tid = j;
994 retry_limit.retry = atoi(retry);
995 WL_IOVAR_SET(name, iov_name[i], &retry_limit, sizeof(retry_limit));
999 return;
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.
1012 static int
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);
1023 int ret, phytype;
1024 wlc_rev_info_t rev;
1025 #ifdef linux
1026 struct utsname unamebuf;
1028 uname(&unamebuf);
1029 #endif
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) {
1047 char *nvram_str;
1048 bool amsdu = 0;
1050 /* Check for the capabilitiy 'amsdutx' */
1051 if (strncmp(var, "amsdutx", sizeof(var)) == 0) {
1052 var[len] = '\0';
1053 amsdu = 1;
1055 nvram_str = nvram_get(strcat_r(prefix, var, buf));
1056 if (!nvram_str)
1057 continue;
1059 if (!strcmp(nvram_str, "on"))
1060 val = ON;
1061 else if (!strcmp(nvram_str, "off"))
1062 val = OFF;
1063 else if (!strcmp(nvram_str, "auto"))
1064 val = AUTO;
1065 else
1066 continue;
1068 if (strncmp(var, "ampdu", sizeof(var)) == 0) {
1069 ampdu_valid_option = TRUE;
1070 ampdu_option_val = val;
1073 if (amsdu) {
1074 amsdu_valid_option = TRUE;
1075 amsdu_option_val = val;
1077 nvram_str = nvram_get(strcat_r(prefix, "rx_amsdu_in_ampdu", buf));
1078 if (nvram_str) {
1079 if (!strcmp(nvram_str, "on"))
1080 rx_amsdu_in_ampdu_option_val = ON;
1081 else if (!strcmp(nvram_str, "auto"))
1082 rx_amsdu_in_ampdu_option_val = AUTO;
1086 * Some tests show problems when AMSDU is enabled on TX
1087 * side together with ps-pretend.
1088 * Ps-pretend is used on AP only.
1089 * Let's disable AMSDU downstream unconditionally
1090 * in devicemode=1.
1091 * When ps-pretend be OK with AMSDU, below statement
1092 * need to be removed.
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);
1105 } else {
1106 WL_IOVAR_SETINT(name, "ampdu", OFF);
1109 wlconf_set_ampdu_retry_limit(name, prefix);
1111 #ifdef linux
1112 /* For MIPS routers set the num mpdu per ampdu limit to 32. We observed
1113 * that having this value at 32 helps with bi-di thru'put as well.
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__ */
1121 #endif /* linux */
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);
1132 } else
1133 WL_IOVAR_SETINT(name, "amsdu", OFF);
1136 WL_IOVAR_SETINT(name, "rx_amsdu_in_ampdu", rx_amsdu_in_ampdu_option_val);
1137 } else {
1138 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
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. */
1153 static int
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)
1160 bw_cap = atoi(str);
1161 else {
1162 /* Backward compatibility. Map to bandwidth cap bitmap values. */
1163 int val = atoi(nvram_safe_get(strcat_r(prefix, "nbw_cap", tmp)));
1165 if (((bandtype == WLC_BAND_2G) && (val == WLC_N_BW_40ALL)) ||
1166 ((bandtype == WLC_BAND_5G) &&
1167 (val == WLC_N_BW_40ALL || val == WLC_N_BW_20IN2G_40IN5G)))
1168 bw_cap = WLC_BW_CAP_40MHZ;
1169 else
1170 bw_cap = WLC_BW_CAP_20MHZ;
1173 return bw_cap;
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];
1180 wlc_rev_info_t rev;
1181 uint32 txbf_bfe_cap = 0;
1182 uint32 txbf_bfr_cap = 0;
1183 int ret = 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);
1192 if (txbf_bfr_cap) {
1193 /* Turning TxBF on (order matters) */
1194 WL_IOVAR_SETINT(name, "txbf_bfr_cap", 1);
1195 WL_IOVAR_SETINT(name, "txbf", 1);
1196 } else {
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];
1214 wlc_rev_info_t rev;
1215 uint32 txbf_timer = 0;
1216 int ret = 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 */
1229 static void
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;
1239 char *wlifname;
1240 struct in_addr ipaddr, ipmask;
1241 char nvram_ifname[32];
1242 bool tm_filters_configured = FALSE;
1243 /* DWM variables */
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)];
1248 int dscp_filterlen;
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);
1255 if (!wlifname) {
1256 return;
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) {
1280 continue;
1282 if (nettrm.match.flags == NETCONF_DISABLED) {
1283 continue;
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;
1299 trfmgmt++;
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) {
1312 continue;
1314 if (nettrm_dwm.match.flags == NETCONF_DISABLED) {
1315 continue;
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
1361 static void
1362 trf_mgmt_rssi_policy(char *prefix)
1364 char *wlifname;
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) {
1372 return;
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, ""))
1378 return;
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 */
1386 static int
1387 wlconf_del_brcm_syscap_ie(char *name, int bsscfg_idx, char *oui)
1389 int iebuf_len = 0;
1390 vndr_ie_setbuf_t *ie_setbuf = NULL;
1391 int iecount, i;
1393 char getbuf[2048] = {0};
1394 vndr_ie_buf_t *iebuf;
1395 vndr_ie_info_t *ieinfo;
1396 char *bufaddr;
1397 int buflen = 0;
1398 int found = 0;
1399 uint32 pktflag;
1400 uint32 frametype;
1401 int ret = 0;
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)) {
1415 found = 1;
1416 bufaddr = (char*) &ieinfo->vndr_ie_data;
1417 buflen = (int)ieinfo->vndr_ie_data.len + VNDR_IE_HDR_LEN;
1418 break;
1421 bufaddr = (char *)(ieinfo->vndr_ie_data.oui + ieinfo->vndr_ie_data.len);
1424 if (!found)
1425 goto err;
1427 iebuf_len = buflen + sizeof(vndr_ie_setbuf_t) - sizeof(vndr_ie_t);
1428 ie_setbuf = (vndr_ie_setbuf_t *)malloc(iebuf_len);
1429 if (!ie_setbuf) {
1430 WLCONF_DBG("memory alloc failure\n");
1431 ret = -1;
1432 goto err;
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 */
1441 iecount = 1;
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);
1450 err:
1451 if (ie_setbuf)
1452 free(ie_setbuf);
1454 return ret;
1457 static int
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;
1463 int ret = 0;
1465 pktflag = VNDR_IE_BEACON_FLAG;
1467 buflen = sizeof(vndr_ie_setbuf_t) + datalen - 1;
1468 ie_setbuf = (vndr_ie_setbuf_t *)malloc(buflen);
1469 if (!ie_setbuf) {
1470 WLCONF_DBG("memory alloc failure\n");
1471 ret = -1;
1472 goto err;
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 */
1481 iecount = 1;
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);
1491 if (datalen > 0)
1492 memcpy(&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0], data,
1493 datalen);
1495 ret = wlconf_del_brcm_syscap_ie(name, bsscfg_idx, oui);
1496 if (ret)
1497 goto err;
1499 WL_BSSIOVAR_SET(name, "vndr_ie", (int)bsscfg_idx, ie_setbuf, buflen);
1501 err:
1502 if (ie_setbuf)
1503 free(ie_setbuf);
1505 return (ret);
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.
1514 * Inputs:
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.
1523 * Outputs:
1524 * Driver settings may be updated.
1526 * Returns:
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.
1532 static int
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,
1537 PARAM_PRIO = 1,
1538 PARAM_STEERFLAG = 2,
1539 PARAM_COUNT
1540 } param_idx = PARAM_MACADDRESS;
1541 char *param;
1542 struct ether_addr ea;
1543 char *end;
1544 uint32 value;
1546 while ((param = strsep(&param_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;
1553 break;
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;
1558 int ret;
1560 value = strtol(param, &end, 0);
1561 if (*end != '\0') {
1562 return BCME_BADARG;
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));
1569 break;
1571 case PARAM_STEERFLAG:
1572 if (*param) {
1573 value = strtol(param, &end, 0);
1574 if (*end != '\0') {
1575 return BCME_BADARG;
1578 break;
1580 default:
1581 /* Future use parameter already set in nvram config - ignore. */
1582 break;
1584 ++param_idx;
1587 if (param_idx <= PARAM_PRIO) { /* No mac address and/or no parameters at all, forget it. */
1588 return BCME_BADARG;
1591 return BCME_OK;
1594 #define VIFNAME_LEN 16
1596 /* configure the specified wireless interface */
1598 wlconf(char *name)
1600 int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0;
1601 int bcmerr;
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)));
1609 char *country;
1610 char *country_rev;
1611 wlc_rev_info_t rev;
1612 channel_info_t ci;
1613 struct maclist *maclist;
1614 struct ether_addr *ea;
1615 wlc_ssid_t ssid;
1616 wl_rateset_t rs;
1617 unsigned int i;
1618 char eaddr[32];
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}};
1622 char *ba;
1623 char *preauth;
1624 int set_preauth;
1625 int wlunit = -1;
1626 int wlsubunit = -1;
1627 int wl_ap_build = 0; /* wl compiled with AP capabilities */
1628 char cap[WLC_IOCTL_SMLEN];
1629 char caps[WLC_IOCTL_MEDLEN];
1630 int btc_mode;
1631 uint32 leddc;
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;
1636 int wme_global;
1637 int max_assoc = -1;
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 */
1658 else
1659 return 0; /* okay */
1661 } else {
1662 return -1;
1665 /* clean up tmp */
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)))
1673 return -1;
1675 foreach(cap, caps, next) {
1676 if (!strcmp(cap, "ap")) {
1677 wl_ap_build = 1;
1678 } else if (!strcmp(cap, "mbss16"))
1679 max_no_vifs = 16;
1680 else if (!strcmp(cap, "mbss8"))
1681 max_no_vifs = 8;
1682 else if (!strcmp(cap, "mbss4"))
1683 max_no_vifs = 4;
1684 else if (!strcmp(cap, "wmf"))
1685 wmf = 1;
1686 else if (!strcmp(cap, "rxchain_pwrsave"))
1687 rxchain_pwrsave = 1;
1688 else if (!strcmp(cap, "radio_pwrsave"))
1689 radio_pwrsave = 1;
1690 else if (!strcmp(cap, "wet_tunnel"))
1691 wet_tunnel_cap = 1;
1694 /* Check interface (fail silently for non-wl interfaces) */
1695 if ((ret = wl_probe(name)))
1696 return ret;
1698 /* Get MAC address */
1699 (void) wl_hwaddr(name, (uchar *)buf);
1700 memcpy(vif_addr, buf, ETHER_ADDR_LEN);
1702 /* Get instance */
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);
1718 #ifdef BCMDBG
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));
1730 else
1731 WL_IOCTL(name, WLC_SET_MSGLEVEL, &val, sizeof(val));
1733 #endif
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;
1742 setbuf.enable = 0;
1744 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
1745 if (ret) {
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)
1751 break;
1753 if (ret) {
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) {
1763 ret = -1;
1764 goto exit;
1767 #ifdef BCMDBG
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);
1775 #endif
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);
1782 #endif
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 */
1792 ure_enab = TRUE;
1794 if (wl_ap_build) {
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));
1799 #else
1800 WL_IOVAR_SETINT(name, "mbss", (bclist->count >= 2));
1801 #endif
1802 } else
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,
1819 sizeof(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)
1844 continue;
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,
1854 ETHER_ADDR_LEN);
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);
1874 /* Set AP mode */
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));
1881 if (mac_spoof) {
1882 sta = 1;
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";
1892 struct {
1893 int val;
1894 int band;
1895 } roam;
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 */
1911 wet &= !apsta;
1913 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1914 val = 1;
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++) {
1921 val = 0;
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 */
1932 if (ap || apsta) {
1933 max_assoc = val = atoi(nvram_safe_get(strcat_r(prefix, "maxassoc", tmp)));
1934 if (val > 0) {
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);
1940 if (!wet && !sta)
1941 WL_IOVAR_SETINT(name, "mpc", OFF);
1943 /* Set the Proxy STA or Repeater mode */
1944 if (psta) {
1945 WL_IOVAR_SETINT(name, "psta", PSTA_MODE_PROXY);
1946 } else if (psr) {
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);
1950 } else {
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;
1959 } else {
1960 WL_IOVAR_SETINT(name, "wet_tunnel", 0);
1964 for (i = 0; i < bclist->count; i++) {
1965 char *subprefix;
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)) {
1979 set_preauth = 1;
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)));
1999 if (val > 0) {
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 */
2016 if (wmf) {
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",
2034 tmp)));
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",
2042 tmp)));
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,
2048 val);
2051 if (radio_pwrsave) {
2052 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "radio_pwrsave_enable",
2053 tmp)));
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",
2061 tmp)));
2062 WL_BSSIOVAR_SETINT(name, "radio_pwrsave_pps", bsscfg->idx, val);
2063 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "radio_pwrsave_level",
2064 tmp)));
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,
2070 val);
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));
2098 } else {
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);
2114 if (leddc)
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);
2126 /* Get radio IDs */
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);
2133 } else
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);
2143 /* Set band */
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));
2149 if (str)
2150 val = atoi(str);
2151 else {
2152 WL_GETINT(name, WLC_GET_BAND, &val);
2154 } else
2155 val = WLCONF_PHYTYPE2BAND(val);
2157 WL_SETINT(name, WLC_SET_BAND, val);
2159 /* Check errors (card may have changed) */
2160 if (ret) {
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 */
2168 bandtype = val;
2170 /* Check errors again (will cover 5Ghz-only cards) */
2171 if (ret) {
2172 int list[3];
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"))
2199 pam_mode = -1;
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"));
2205 if (val > 0) {
2206 struct {int sleep; int delay;} setbuf;
2207 nvram_unset("coma_sleep");
2208 nvram_commit();
2209 setbuf.sleep = val;
2210 setbuf.delay = 1;
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")) {
2223 val = 0;
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")) {
2228 val = 0;
2229 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
2230 val = 1;
2231 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
2232 radar_enab = TRUE;
2233 if (nvram_match(tmp, "h"))
2234 val = 1;
2235 else
2236 val = 2;
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)))) {
2241 val = atoi(str);
2242 wl_iovar_setint(name, "dfs_preism", val);
2244 if ((str = nvram_get(strcat_r(prefix, "dfs_postism", tmp)))) {
2245 val = atoi(str);
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")) {
2252 val = 0;
2253 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
2254 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
2255 val = 1;
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)) {
2261 struct {
2262 int bandtype;
2263 uint8 bw_cap;
2264 } param;
2266 /* Get the user nmode setting now */
2267 nmode = AUTO; /* enable by default for NPHY */
2268 /* Set n mode */
2269 strcat_r(prefix, "nmode", tmp);
2270 if (nvram_match(tmp, "0"))
2271 nmode = OFF;
2273 WL_IOVAR_SETINT(name, "nmode", (uint32)nmode);
2275 if (nmode == OFF)
2276 val = WLC_BW_CAP_20MHZ;
2277 else
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", &param, sizeof(param));
2290 } else {
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);
2299 if (chanspec) {
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);
2310 if (ret) {
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)) {
2317 uint channel;
2318 uint nctrlsb = 0;
2319 uint cspecbw = (bandtype == WLC_BAND_2G) ?
2320 WL_CHANSPEC_BAND_2G:WL_CHANSPEC_BAND_5G;
2322 channel = val;
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)) {
2365 int count;
2366 int streams;
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)));
2378 if (streams == 0) {
2379 /* invalid - NVRAM needs to be fixed/initialized */
2380 nvram_set(strcat_r(prefix, "txchain", tmp), var);
2381 streams = count;
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)));
2395 if (streams == 0) {
2396 /* invalid - NVRAM needs to be fixed/initialized */
2397 nvram_set(strcat_r(prefix, "rxchain", tmp), var);
2398 streams = count;
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));
2409 /* Set gmode */
2410 if (bandtype == WLC_BAND_2G) {
2411 int override = WLC_PROTECTION_OFF;
2412 int control = WLC_PROTECTION_CTL_OFF;
2414 /* Set gmode */
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",
2441 (uint32)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"))
2452 mode = 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++) {
2465 char *subprefix;
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));
2486 val = atoi(str);
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;
2504 else
2505 rs.rates[i] &= ~0x80;
2509 if (phytype != PHY_TYPE_SSN && phytype != PHY_TYPE_LCN) {
2510 /* Set BTC mode */
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)
2518 continue;
2519 rs.rates[rs.count++] = rs_tmp.rates[i];
2525 /* Set rateset */
2526 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
2528 /* Allow short preamble settings for the following:
2529 * 11b - short/long
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;
2542 else
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 */
2555 if (mcsidx == -1)
2556 val = 0;
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 */
2562 val = 11;
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) */
2570 val = 0;
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 */
2580 if (nmode != OFF) {
2581 uint32 nrate = 0;
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) {
2587 mcsidx = -1;
2588 ismcs = FALSE;
2589 nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1");
2592 /* Use nrate iovar only for MCS rate. */
2593 if (ismcs) {
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 */
2606 val = 11;
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) */
2614 val = 0;
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));
2641 if (!str) {
2642 /* No nvram variable found, use the default */
2643 str = nvram_default_get(strcat_r(prefix, "bcn_rotate", tmp));
2645 val = atoi(str);
2646 wl_iovar_setint(name, "bcn_rotate", val);
2648 /* Set framebursting mode */
2649 if (btc_mode == WL_BTC_PREMPT)
2650 val = FALSE;
2651 else
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));
2712 if (str) {
2713 val = atoi(str);
2714 } else {
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);
2719 if (val) {
2720 /* nar is enabled on this interface, add tuneable parameters */
2721 str = nvram_get(strcat_r(prefix, "nar_handle_ampdu", tmp));
2722 if (str) {
2723 WL_IOVAR_SETINT(name, "nar_handle_ampdu", atoi(str));
2725 str = nvram_get(strcat_r(prefix, "nar_transit_limit", tmp));
2726 if (str) {
2727 WL_IOVAR_SETINT(name, "nar_transit_limit", atoi(str));
2731 /* Set up TxBF */
2732 wlconf_set_txbf(name, prefix);
2734 /* set airtime fairness */
2735 val = 0;
2736 str = nvram_get(strcat_r(prefix, "atf", tmp));
2737 if (str) {
2738 val = atoi(str);
2740 WL_IOVAR_SETINT(name, "atf", val);
2742 str = nvram_get(strcat_r(prefix, "ampdu_atf_us", tmp));
2743 if (str) {
2744 val = atoi(str);
2745 if (val) {
2746 WL_IOVAR_SETINT(name, "ampdu_atf_us", val);
2747 WL_IOVAR_SETINT(name, "nar_atf_us", val);
2751 /* set TAF */
2752 val = 0;
2753 str = nvram_get(strcat_r(prefix, "taf_enable", tmp));
2754 if (str && (bandtype == WLC_BAND_5G)) {
2755 val = atoi(str);
2757 WL_IOVAR_SETINT(name, "taf", val);
2759 val = 0;
2760 str = nvram_get(strcat_r(prefix, "taf_rule", tmp));
2761 if (str) {
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 */
2770 val = 0;
2771 str = nvram_get(strcat_r(prefix, "ebos_enable", tmp));
2772 if (str) {
2773 val = atoi(str);
2775 WL_IOVAR_SETINT(name, "ebos_enable", val);
2777 val = 0;
2778 str = nvram_get(strcat_r(prefix, "ebos_flags", tmp));
2779 if (str) {
2780 val = strtoul(str, NULL, 0);
2781 WL_IOVAR_SETINT(name, "ebos_flags", val);
2784 val = 0;
2785 str = nvram_get(strcat_r(prefix, "ebos_prr_threshold", tmp));
2786 if (str) {
2787 val = strtoul(str, NULL, 0);
2788 WL_IOVAR_SETINT(name, "ebos_prr_threshold", val);
2791 val = 0;
2792 str = nvram_get(strcat_r(prefix, "ebos_prr_flags", tmp));
2793 if (str) {
2794 val = strtoul(str, NULL, 0);
2795 WL_IOVAR_SETINT(name, "ebos_prr_flags", val);
2798 val = 0;
2799 str = nvram_get(strcat_r(prefix, "ebos_prr_transit", tmp));
2800 if (str) {
2801 val = strtol(str, NULL, 0);
2802 WL_IOVAR_SETINT(name, "ebos_prr_transit", val);
2804 val = 0;
2806 str = nvram_get(strcat_r(prefix, "ebos_transit", tmp));
2807 if (str) {
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)));
2814 if (val) {
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));
2820 if (str) {
2821 /* user specified phy cal period. */
2822 val = atoi(str);
2823 WL_IOVAR_SET(name, "cal_period", &val, sizeof(val));
2826 /* Set antenna */
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 */
2834 if (radar_enab) {
2835 wlconf_set_radarthrs(name, prefix);
2838 /* set pspretend */
2839 val = 0;
2840 if (ap) {
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));
2846 if (str) {
2847 val = atoi(str);
2848 WL_BSSIOVAR_SETINT(name, "pspretend_retry_limit", bsscfg->idx, val);
2852 /* now set it for primary bss */
2853 val = 0;
2854 str = nvram_get(strcat_r(prefix, "pspretend_retry_limit", tmp));
2855 if (str) {
2856 val = atoi(str);
2859 WL_IOVAR_SETINT(name, "pspretend_retry_limit", val);
2861 val = 0;
2862 if (ap) {
2863 str = nvram_get(strcat_r(prefix, "pspretend_threshold", tmp));
2864 if (str) {
2865 val = atoi(str);
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));
2874 if (str) {
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));
2882 if (str) {
2883 int cca_thres = atoi(str);
2884 if (cca_thres > 0)
2885 WL_IOVAR_SETINT(name, "chanim_ccathres", cca_thres);
2888 str = nvram_get(strcat_r(prefix, "chanimmode", tmp));
2890 if (str) {
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)) {
2908 if (sta ||
2909 ((ap || apsta) && (nbw == WL_CHANSPEC_BW_40) && (bandtype == WLC_BAND_2G))) {
2910 str = nvram_safe_get(strcat_r(prefix, "obss_coex", tmp));
2911 if (!str) {
2912 /* No nvram variable found, use the default */
2913 str = nvram_default_get(strcat_r(prefix, "obss_coex", tmp));
2915 obss_coex = atoi(str);
2916 } else {
2917 /* Need to disable obss coex in case of 20MHz and/or
2918 * in case of 5G.
2920 obss_coex = 0;
2922 #ifdef WLTEST
2923 /* force coex off for msgtest build */
2924 obss_coex = 0;
2925 #endif
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)
2941 if (ap || apsta) {
2942 int channel = chanspec ? wf_chspec_ctlchan(chanspec) : 0;
2943 #ifdef EXT_ACS
2944 char tmp[100];
2945 char *ptr;
2946 char * str_val;
2948 str_val = nvram_safe_get("acs_mode");
2949 if (!strcmp(str_val, "legacy"))
2950 goto legacy_mode;
2952 snprintf(tmp, sizeof(tmp), "acs_ifnames");
2953 ptr = nvram_get(tmp);
2954 if (ptr)
2955 snprintf(buf, sizeof(buf), "%s %s", ptr, name);
2956 else
2957 strncpy(buf, name, sizeof(buf));
2958 nvram_set(tmp, buf);
2959 WL_IOVAR_SETINT(name, "chanim_mode", CHANIM_EXT);
2960 goto legacy_end;
2962 legacy_mode:
2963 #endif /* EXT_ACS */
2964 if (obss_coex || channel == 0) {
2965 if (WLCONF_PHYTYPE_11N(phytype)) {
2966 chanspec_t chanspec;
2967 int pref_chspec;
2969 if (channel != 0) {
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);
2980 } else {
2981 WL_IOVAR_SETINT(name, "pref_chanspec", 0);
2984 chanspec = wlconf_auto_chanspec(name);
2985 if (chanspec != 0)
2986 WL_IOVAR_SETINT(name, "chanspec", chanspec);
2987 } else {
2988 /* select a channel */
2989 val = wlconf_auto_channel(name);
2990 /* switch to the selected channel */
2991 if (val != 0)
2992 WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
2994 /* set the auto channel scan timer in the driver when in auto mode */
2995 if (channel == 0) {
2996 val = 15; /* 15 minutes for now */
2997 } else {
2998 val = 0;
3000 } else {
3001 /* reset the channel scan timer in the driver when not in auto mode */
3002 val = 0;
3005 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
3006 WL_IOVAR_SETINT(name, "chanim_mode", CHANIM_ACT);
3007 #ifdef EXT_ACS
3008 legacy_end:
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);
3016 } /* AP or APSTA */
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;
3037 setbuf.enable = 0;
3039 bsscfg = &bclist->bsscfgs[i];
3040 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) {
3041 setbuf.enable = 1;
3044 /* Set the MAC list */
3045 maclist = (struct maclist *)buf;
3046 maclist->count = 0;
3047 if (!nvram_match(strcat_r(bsscfg->prefix, "macmode", tmp), "disabled")) {
3048 ea = maclist->ea;
3049 foreach(var, nvram_safe_get(strcat_r(bsscfg->prefix, "maclist", tmp)),
3050 next) {
3051 if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)])))
3052 break;
3053 if (ether_atoe(var, ea->octet)) {
3054 maclist->count++;
3055 ea++;
3060 if (setbuf.bsscfg_idx == 0) {
3061 name_ptr = name;
3062 } else { /* Non-primary BSS; changes name syntax */
3063 char tmp[VIFNAME_LEN];
3064 int 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] == '_')) {
3070 tmp[len - 1] = 0;
3072 nvifname_to_osifname(tmp, vifname, VIFNAME_LEN);
3073 name_ptr = vifname;
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;
3085 else
3086 val = WLC_MACMODE_DISABLED;
3088 WL_IOCTL(name_ptr, WLC_SET_MACMODE, &val, sizeof(val));
3091 ret = 0;
3092 exit:
3093 if (bclist != NULL)
3094 free(bclist);
3096 return ret;
3100 wlconf_down(char *name)
3102 int val, ret = 0;
3103 int i;
3104 int wlsubunit;
3105 int bcmerr;
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];
3110 char *next;
3111 wlc_ssid_t ssid;
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);
3116 return 0;
3119 /* Check interface (fail silently for non-wl interfaces) */
3120 if ((ret = wl_probe(name)))
3121 return ret;
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)))
3128 return -1;
3130 foreach(cap, caps, next) {
3131 if (!strcmp(cap, "ap")) {
3132 wl_ap_build = 1;
3136 if (wl_ap_build) {
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;
3143 setbuf.enable = 0;
3145 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
3146 if (ret) {
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)
3152 break;
3155 } else {
3156 WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
3157 if (val) {
3158 /* Nuke SSID */
3159 ssid.SSID_len = 0;
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);
3171 return 0;
3175 wlconf_start(char *name)
3177 int i, ii, unit, val, ret = 0;
3178 int wlunit = -1;
3179 int wlsubunit = -1;
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;
3187 wlc_ssid_t ssid;
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)))
3195 return ret;
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 */
3211 else
3212 return 0; /* okay */
3215 else {
3216 return -1;
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)))
3224 return -1;
3226 foreach(cap, caps, next) {
3227 if (!strcmp(cap, "ap"))
3228 wl_ap_build = 1;
3230 if (!strcmp(cap, "traffic-mgmt"))
3231 trf_mgmt_cap = 1;
3233 if (!strcmp(cap, "traffic-mgmt-dwm"))
3234 trf_mgmt_dwm_cap = 1;
3237 /* Get instance */
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)))
3244 return -1;
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"))
3256 sta = 1;
3258 /* Retain remaining WET effects only if not APSTA */
3259 wet &= !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;
3269 maclist->count = 0;
3270 ea = maclist->ea;
3271 foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
3272 if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)])))
3273 break;
3274 ether_atoe(var, ea->octet);
3275 maclist->count++;
3276 ea++;
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;
3293 setbuf.enable = 0;
3295 bsscfg = &bclist->bsscfgs[i];
3296 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) {
3297 setbuf.enable = 1;
3300 /* bring up BSS */
3301 if (ap || apsta || sta || wet) {
3302 for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) {
3303 if (wl_ap_build) {
3304 WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf));
3306 else {
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),
3312 ssid.SSID_len);
3313 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
3315 if (apsta && (ret != 0))
3316 sleep_ms(1000);
3317 else
3318 break;
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__ */
3348 if (bclist != NULL)
3349 free(bclist);
3351 return ret;
3354 #if defined(linux)
3355 static int
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);
3366 return -1;
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"));
3375 return 0;
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]);
3390 else {
3391 fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
3392 return -1;
3395 #endif /* defined(linux) */