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