RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src / wlconf / wlconf.c
blob740f9c8f1f566de0b49401eab107b8e01514d678
1 /*
2 * Wireless Network Adapter Configuration Utility
4 * Copyright 2008, 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$
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 <shutils.h>
24 #include <wlutils.h>
26 /* phy types */
27 #define PHY_TYPE_A 0
28 #define PHY_TYPE_B 1
29 #define PHY_TYPE_G 2
30 #define PHY_TYPE_N 4
31 #define PHY_TYPE_LP 5
32 #define PHY_TYPE_NULL 0xf
34 /* how many times to attempt to bring up a virtual i/f when
35 * we are in APSTA mode and IOVAR set of "bss" "up" returns busy
37 #define MAX_BSS_UP_RETRIES 5
39 /* notify the average dma xfer rate (in kbps) to the driver */
40 #define AVG_DMA_XFER_RATE 120000
42 /* parts of an idcode: */
43 #define IDCODE_MFG_MASK 0x00000fff
44 #define IDCODE_MFG_SHIFT 0
45 #define IDCODE_ID_MASK 0x0ffff000
46 #define IDCODE_ID_SHIFT 12
47 #define IDCODE_REV_MASK 0xf0000000
48 #define IDCODE_REV_SHIFT 28
51 * Debugging Macros
53 #define WLCONF_DBG(fmt, arg...)
54 #define WL_IOCTL(name, cmd, buf, len) (ret = wl_ioctl(name, cmd, buf, len))
55 #define WL_SETINT(name, cmd, val) (ret = wlconf_setint(name, cmd, val))
56 #define WL_GETINT(name, cmd, pval) (ret = wlconf_getint(name, cmd, pval))
57 #define WL_IOVAR_SET(ifname, iovar, param, paramlen) (ret = wl_iovar_set(ifname, iovar, \
58 param, paramlen))
59 #define WL_IOVAR_SETINT(ifname, iovar, val) (ret = wl_iovar_setint(ifname, iovar, val))
60 #define WL_IOVAR_GETINT(ifname, iovar, val) (ret = wl_iovar_getint(ifname, iovar, val))
61 #define WL_BSSIOVAR_SETBUF(ifname, iovar, bssidx, param, paramlen, buf, buflen) \
62 (ret = wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, buf, buflen))
63 #define WL_BSSIOVAR_SET(ifname, iovar, bssidx, param, paramlen) \
64 (ret = wl_bssiovar_set(ifname, iovar, bssidx, param, paramlen))
65 #define WL_BSSIOVAR_GET(ifname, iovar, bssidx, param, paramlen) \
66 (ret = wl_bssiovar_get(ifname, iovar, bssidx, param, paramlen))
67 #define WL_BSSIOVAR_SETINT(ifname, iovar, bssidx, val) (ret = wl_bssiovar_setint(ifname, iovar, \
68 bssidx, val))
70 #ifdef BCMWPA2
71 #define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
72 #else
73 #define CHECK_PSK(mode) ((mode) & WPA_AUTH_PSK)
74 #endif
76 /* prototypes */
77 struct bsscfg_list *wlconf_get_bsscfgs(char* ifname, char* prefix);
78 int wlconf(char *name);
79 int wlconf_down(char *name);
81 static int
82 wlconf_getint(char* ifname, int cmd, int *pval)
84 return wl_ioctl(ifname, cmd, pval, sizeof(int));
87 static int
88 wlconf_setint(char* ifname, int cmd, int val)
90 return wl_ioctl(ifname, cmd, &val, sizeof(int));
93 static int
94 wlconf_wds_clear(char *name)
96 struct maclist maclist;
97 int ret;
99 maclist.count = 0;
100 WL_IOCTL(name, WLC_SET_WDSLIST, &maclist, sizeof(maclist));
102 return ret;
105 /* set WEP key */
106 static int
107 wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i)
109 wl_wsec_key_t key;
110 char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
111 char *keystr, hex[] = "XX";
112 unsigned char *data = key.data;
113 int ret = 0;
115 memset(&key, 0, sizeof(key));
116 key.index = i - 1;
117 sprintf(wl_key, "%skey%d", prefix, i);
118 keystr = nvram_safe_get(wl_key);
120 switch (strlen(keystr)) {
121 case WEP1_KEY_SIZE:
122 case WEP128_KEY_SIZE:
123 key.len = strlen(keystr);
124 strcpy((char *)key.data, keystr);
125 break;
126 case WEP1_KEY_HEX_SIZE:
127 case WEP128_KEY_HEX_SIZE:
128 key.len = strlen(keystr) / 2;
129 while (*keystr) {
130 strncpy(hex, keystr, 2);
131 *data++ = (unsigned char) strtoul(hex, NULL, 16);
132 keystr += 2;
134 break;
135 default:
136 key.len = 0;
137 break;
140 /* Set current WEP key */
141 if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key))))
142 key.flags = WL_PRIMARY_KEY;
144 WL_BSSIOVAR_SET(name, "wsec_key", bsscfg_idx, &key, sizeof(key));
146 return ret;
149 extern struct nvram_tuple router_defaults[];
151 /* validate/restore all per-interface related variables */
152 static void
153 wlconf_validate_all(char *prefix, bool restore)
155 struct nvram_tuple *t;
156 char tmp[100];
157 char *v;
158 for (t = router_defaults; t->name; t++) {
159 if (!strncmp(t->name, "wl_", 3)) {
160 strcat_r(prefix, &t->name[3], tmp);
161 if (!restore && nvram_get(tmp))
162 continue;
163 v = nvram_get(t->name);
164 nvram_set(tmp, v ? v : t->value);
169 /* restore specific per-interface variable */
170 static void
171 wlconf_restore_var(char *prefix, char *name)
173 struct nvram_tuple *t;
174 char tmp[100];
175 for (t = router_defaults; t->name; t++) {
176 if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) {
177 nvram_set(strcat_r(prefix, name, tmp), t->value);
178 break;
182 static int
183 wlconf_akm_options(char *prefix)
185 char comb[32];
186 char *wl_akm;
187 int akm_ret_val = 0;
188 char akm[32];
189 char *next;
191 wl_akm = nvram_safe_get(strcat_r(prefix, "akm", comb));
192 foreach(akm, wl_akm, next) {
193 if (!strcmp(akm, "wpa"))
194 akm_ret_val |= WPA_AUTH_UNSPECIFIED;
195 if (!strcmp(akm, "psk"))
196 akm_ret_val |= WPA_AUTH_PSK;
197 #ifdef BCMWPA2
198 if (!strcmp(akm, "wpa2"))
199 akm_ret_val |= WPA2_AUTH_UNSPECIFIED;
200 if (!strcmp(akm, "psk2"))
201 akm_ret_val |= WPA2_AUTH_PSK;
202 if (!strcmp(akm, "brcm_psk"))
203 akm_ret_val |= BRCM_AUTH_PSK;
204 #endif
206 return akm_ret_val;
209 /* Set up wsec */
210 static int
211 wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx)
213 char tmp[100];
214 int val = 0;
215 int akm_val;
216 int ret;
218 /* Set wsec bitvec */
219 akm_val = wlconf_akm_options(prefix);
220 if (akm_val != 0) {
221 if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip"))
222 val = TKIP_ENABLED;
223 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes"))
224 val = AES_ENABLED;
225 else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes"))
226 val = TKIP_ENABLED | AES_ENABLED;
228 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled"))
229 val |= WEP_ENABLED;
230 WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val);
231 /* Set wsec restrict if WSEC_ENABLED */
232 WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0);
234 return 0;
237 #ifdef BCMWPA2
238 static int
239 wlconf_set_preauth(char *name, int bsscfg_idx, int preauth)
241 uint cap;
242 int ret;
244 WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint));
245 if (ret != 0) return -1;
247 if (preauth)
248 cap |= WPA_CAP_WPA2_PREAUTH;
249 else
250 cap &= ~WPA_CAP_WPA2_PREAUTH;
252 WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap);
254 return ret;
256 #endif /* BCMWPA2 */
258 static void
259 wlconf_set_radarthrs(char *name, char *prefix)
261 wl_radar_thr_t radar_thr;
262 int i, ret, len;
263 char nv_buf[NVRAM_MAX_VALUE_LEN], *rargs, *v, *endptr;
264 char buf[WLC_IOCTL_SMLEN];
265 char *version = NULL, *thr0_20_lo = NULL, *thr1_20_lo = NULL, *thr0_40_lo = NULL;
266 char *thr1_40_lo = NULL, *thr0_20_hi = NULL, *thr1_20_hi = NULL, *thr0_40_hi = NULL;
267 char *thr1_40_hi = NULL;
268 char **locals[] = { &version, &thr0_20_lo, &thr1_20_lo, &thr0_40_lo, &thr1_40_lo,
269 &thr0_20_hi, &thr1_20_hi, &thr0_40_hi, &thr1_40_hi };
271 rargs = nvram_safe_get(strcat_r(prefix, "radarthrs", nv_buf));
272 if (!rargs)
273 goto err;
275 len = strlen(rargs);
276 if ((len > NVRAM_MAX_VALUE_LEN) || (len == 0))
277 goto err;
279 memset(nv_buf, 0, sizeof(nv_buf));
280 strncpy(nv_buf, rargs, len);
281 v = nv_buf;
282 for (i = 0; i < (sizeof(locals) / sizeof(locals[0])); i++) {
283 *locals[i] = v;
284 while (*v && *v != ' ') {
285 v++;
287 if (*v) {
288 *v = 0;
289 v++;
291 if (v >= (nv_buf + len)) /* Check for complete list, if not caught later */
292 break;
295 /* Start building request */
296 memset(buf, 0, sizeof(buf));
297 strcpy(buf, "radarthrs");
298 /* Retrieve radar thrs parameters */
299 if (!version)
300 goto err;
301 radar_thr.version = atoi(version);
302 if (radar_thr.version > WL_RADAR_THR_VERSION)
303 goto err;
305 /* Retrieve ver 0 params */
306 if (!thr0_20_lo)
307 goto err;
308 radar_thr.thresh0_20_lo = (uint16)strtol(thr0_20_lo, &endptr, 0);
309 if (*endptr != '\0')
310 goto err;
312 if (!thr1_20_lo)
313 goto err;
314 radar_thr.thresh1_20_lo = (uint16)strtol(thr1_20_lo, &endptr, 0);
315 if (*endptr != '\0')
316 goto err;
318 if (!thr0_40_lo)
319 goto err;
320 radar_thr.thresh0_40_lo = (uint16)strtol(thr0_40_lo, &endptr, 0);
321 if (*endptr != '\0')
322 goto err;
324 if (!thr1_40_lo)
325 goto err;
326 radar_thr.thresh1_40_lo = (uint16)strtol(thr1_40_lo, &endptr, 0);
327 if (*endptr != '\0')
328 goto err;
330 if (radar_thr.version == 0) {
332 * Attempt a best effort update of ver 0 to ver 1 by updating
333 * the appropriate values with the specified defaults. The defaults
334 * are from the reference design.
336 radar_thr.version = WL_RADAR_THR_VERSION; /* avoid driver rejecting it */
337 radar_thr.thresh0_20_hi = 0x6ac;
338 radar_thr.thresh1_20_hi = 0x6cc;
339 radar_thr.thresh0_40_hi = 0x6bc;
340 radar_thr.thresh1_40_hi = 0x6e0;
341 } else {
342 /* Retrieve ver 1 params */
343 if (!thr0_20_hi)
344 goto err;
345 radar_thr.thresh0_20_hi = (uint16)strtol(thr0_20_hi, &endptr, 0);
346 if (*endptr != '\0')
347 goto err;
349 if (!thr1_20_hi)
350 goto err;
351 radar_thr.thresh1_20_hi = (uint16)strtol(thr1_20_hi, &endptr, 0);
352 if (*endptr != '\0')
353 goto err;
355 if (!thr0_40_hi)
356 goto err;
357 radar_thr.thresh0_40_hi = (uint16)strtol(thr0_40_hi, &endptr, 0);
358 if (*endptr != '\0')
359 goto err;
361 if (!thr1_40_hi)
362 goto err;
363 radar_thr.thresh1_40_hi = (uint16)strtol(thr1_40_hi, &endptr, 0);
364 if (*endptr != '\0')
365 goto err;
368 /* Copy radar parameters into buffer and plug them to the driver */
369 memcpy((char*)(buf + strlen(buf) + 1), (char*)&radar_thr, sizeof(wl_radar_thr_t));
370 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
372 return;
374 err:
375 WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n");
376 return;
380 /* Set up WME */
381 static void
382 wlconf_set_wme(char *name, char *prefix)
384 int i, j, k;
385 int val, ret;
386 int phytype, gmode, no_ack, apsd, dp[2];
387 edcf_acparam_t *acparams;
388 /* Pay attention to buffer length requirements when using this */
389 char buf[WLC_IOCTL_SMLEN];
390 char *v, *nv_value, nv[100];
391 char nv_name[] = "%swme_%s_%s";
392 char *ac[] = {"be", "bk", "vi", "vo"};
393 char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first;
394 char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced,
395 &oldest_first };
396 struct {char *req; char *str;} mode[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"},
397 {"wme_tx_params", "txp"}};
399 /* query the phy type */
400 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
401 /* get gmode */
402 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", nv)));
404 /* WME sta setting first */
405 for (i = 0; i < 2; i++) {
406 /* build request block */
407 memset(buf, 0, sizeof(buf));
408 strcpy(buf, mode[i].req);
409 /* put push wmeac params after "wme-ac" in buf */
410 acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1);
411 dp[i] = 0;
412 for (j = 0; j < AC_COUNT; j++) {
413 /* get packed nvram parameter */
414 snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]);
415 nv_value = nvram_safe_get(nv);
416 strcpy(nv, nv_value);
417 /* unpack it */
418 v = nv;
419 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
420 *locals[k] = v;
421 while (*v && *v != ' ')
422 v++;
423 if (*v) {
424 *v = 0;
425 v++;
429 /* update CWmin */
430 acparams->ECW &= ~EDCF_ECWMIN_MASK;
431 val = atoi(cwmin);
432 for (val++, k = 0; val; val >>= 1, k++);
433 acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK;
434 /* update CWmax */
435 acparams->ECW &= ~EDCF_ECWMAX_MASK;
436 val = atoi(cwmax);
437 for (val++, k = 0; val; val >>= 1, k++);
438 acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK;
439 /* update AIFSN */
440 acparams->ACI &= ~EDCF_AIFSN_MASK;
441 acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK;
442 /* update ac */
443 acparams->ACI &= ~EDCF_ACI_MASK;
444 acparams->ACI |= j << EDCF_ACI_SHIFT;
445 /* update TXOP */
446 if (phytype == PHY_TYPE_B || gmode == 0)
447 val = atoi(txop_b);
448 else
449 val = atoi(txop_ag);
450 acparams->TXOP = val / 32;
451 /* update acm */
452 acparams->ACI &= ~EDCF_ACM_MASK;
453 val = strcmp(admin_forced, "on") ? 0 : 1;
454 acparams->ACI |= val << 4;
456 /* configure driver */
457 WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
461 /* set no-ack */
462 v = nvram_safe_get(strcat_r(prefix, "wme_no_ack", nv));
463 no_ack = strcmp(v, "on") ? 0 : 1;
464 WL_IOVAR_SETINT(name, "wme_noack", no_ack);
466 /* set APSD */
467 v = nvram_safe_get(strcat_r(prefix, "wme_apsd", nv));
468 apsd = strcmp(v, "on") ? 0 : 1;
469 WL_IOVAR_SETINT(name, "wme_apsd", apsd);
471 /* set per-AC discard policy */
472 strcpy(buf, "wme_dp");
473 WL_IOVAR_SETINT(name, "wme_dp", dp[1]);
475 /* WME Tx parameters setting */
477 wme_tx_params_t txparams[AC_COUNT];
478 char *srl, *sfbl, *lrl, *lfbl, *maxrate;
479 char **locals[] = { &srl, &sfbl, &lrl, &lfbl, &maxrate };
481 /* build request block */
482 memset(txparams, 0, sizeof(txparams));
484 for (j = 0; j < AC_COUNT; j++) {
485 /* get packed nvram parameter */
486 snprintf(nv, sizeof(nv), nv_name, prefix, mode[2].str, ac[j]);
487 nv_value = nvram_safe_get(nv);
488 strcpy(nv, nv_value);
489 /* unpack it */
490 v = nv;
491 for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
492 *locals[k] = v;
493 while (*v && *v != ' ')
494 v++;
495 if (*v) {
496 *v = 0;
497 v++;
501 /* update short retry limit */
502 txparams[j].short_retry = atoi(srl);
504 /* update short fallback limit */
505 txparams[j].short_fallback = atoi(sfbl);
507 /* update long retry limit */
508 txparams[j].long_retry = atoi(lrl);
510 /* update long fallback limit */
511 txparams[j].long_fallback = atoi(lfbl);
513 /* update max rate */
514 txparams[j].max_rate = atoi(maxrate);
517 /* set the WME tx parameters */
518 WL_IOVAR_SET(name, mode[2].req, txparams, sizeof(txparams));
521 return;
524 #if defined(linux)
525 #include <unistd.h>
526 static void
527 sleep_ms(const unsigned int ms)
529 usleep(1000*ms);
531 #elif defined(__ECOS)
532 static void
533 sleep_ms(const unsigned int ms)
535 cyg_tick_count_t ostick;
537 ostick = ms / 10;
538 cyg_thread_delay(ostick);
540 #else
541 #error "sleep_ms() not defined for this OS!!!"
542 #endif /* defined(linux) */
545 * The following condition(s) must be met when Auto Channel Selection
546 * is enabled.
547 * - the I/F is up (change radio channel requires it is up?)
548 * - the AP must not be associated (setting SSID to empty should
549 * make sure it for us)
551 static uint8
552 wlconf_auto_channel(char *name)
554 int chosen = 0;
555 wl_uint32_list_t request;
556 int phytype;
557 int ret;
558 int i;
560 /* query the phy type */
561 WL_GETINT(name, WLC_GET_PHYTYPE, &phytype);
563 request.count = 0; /* let the ioctl decide */
564 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
565 if (!ret) {
566 sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
567 for (i = 0; i < 100; i++) {
568 WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen);
569 if (!ret)
570 break;
571 sleep_ms(100);
574 WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
575 return chosen;
578 static chanspec_t
579 wlconf_auto_chanspec(char *name)
581 chanspec_t chosen = 0;
582 int temp = 0;
583 wl_uint32_list_t request;
584 int ret;
585 int i;
587 request.count = 0; /* let the ioctl decide */
588 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
589 if (!ret) {
590 sleep_ms(1000);
591 for (i = 0; i < 100; i++) {
592 WL_IOVAR_GETINT(name, "apcschspec", &temp);
593 if (!ret)
594 break;
595 sleep_ms(100);
599 chosen = (chanspec_t) temp;
600 WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen);
601 return chosen;
604 /* PHY type/BAND conversion */
605 #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
606 /* PHY type conversion */
607 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
608 (phy) == PHY_TYPE_B ? "b" : \
609 (phy) == PHY_TYPE_LP ? "l" : \
610 (phy) == PHY_TYPE_G ? "g" : "n")
611 #define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
612 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \
613 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \
614 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N)
616 #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */
618 struct bsscfg_info {
619 int idx; /* bsscfg index */
620 char ifname[PREFIX_LEN]; /* OS name of interface (debug only) */
621 char prefix[PREFIX_LEN]; /* prefix for nvram params (eg. "wl0.1_") */
624 struct bsscfg_list {
625 int count;
626 struct bsscfg_info bsscfgs[WL_MAXBSSCFG];
629 struct bsscfg_list *
630 wlconf_get_bsscfgs(char* ifname, char* prefix)
632 char var[80];
633 char tmp[100];
634 char *next;
636 struct bsscfg_list *bclist;
637 struct bsscfg_info *bsscfg;
639 bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list));
640 if (bclist == NULL)
641 return NULL;
642 memset(bclist, 0, sizeof(struct bsscfg_list));
644 /* Set up Primary BSS Config information */
645 bsscfg = &bclist->bsscfgs[0];
646 bsscfg->idx = 0;
647 strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1);
648 strcpy(bsscfg->prefix, prefix);
649 bclist->count = 1;
651 /* additional virtual BSS Configs from wlX_vifs */
652 foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) {
653 if (bclist->count == WL_MAXBSSCFG) {
654 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
655 "in nvram %s\n"
656 "while configuring interface \"%s\"\n",
657 ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var);
658 continue;
660 bsscfg = &bclist->bsscfgs[bclist->count];
661 if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) {
662 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
663 "name \"%s\"\n",
664 ifname, var);
665 continue;
667 strncpy(bsscfg->ifname, var, PREFIX_LEN-1);
668 snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname);
669 bclist->count++;
672 return bclist;
675 static void
676 wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool id_supp)
678 int i;
679 int val;
680 int ret;
681 char tmp[100];
683 /* Set WSEC */
685 * Need to check errors (card may have changed) and change to
686 * defaults since the new chip may not support the requested
687 * encryptions after the card has been changed.
689 if (wlconf_set_wsec(name, prefix, bsscfg_idx)) {
690 /* change nvram only, code below will pass them on */
691 wlconf_restore_var(prefix, "auth_mode");
692 wlconf_restore_var(prefix, "auth");
693 /* reset wep to default */
694 wlconf_restore_var(prefix, "crypto");
695 wlconf_restore_var(prefix, "wep");
696 wlconf_set_wsec(name, prefix, bsscfg_idx);
699 val = wlconf_akm_options(prefix);
700 /* enable in-driver wpa supplicant? */
701 if (id_supp && !nvram_get_int(strcat_r(prefix, "disable_wpa_supp", tmp)) && (CHECK_PSK(val))) {
702 wsec_pmk_t psk;
703 char *key;
705 if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) &&
706 (strlen(key) < WSEC_MAX_PSK_LEN)) {
707 psk.key_len = (ushort) strlen(key);
708 psk.flags = WSEC_PASSPHRASE;
709 strcpy((char *)psk.key, key);
710 WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
712 wl_iovar_setint(name, "sup_wpa", 1);
714 WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val);
716 /* EAP Restrict if we have an AKM or radius authentication */
717 val = ((val != 0) || (nvram_match(strcat_r(prefix, "auth_mode", tmp), "radius")));
718 WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val);
720 /* Set WEP keys */
721 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) {
722 for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++)
723 wlconf_set_wep_key(name, prefix, bsscfg_idx, i);
726 /* Set 802.11 authentication mode - open/shared */
727 val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp)));
728 WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val);
732 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled
733 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
734 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off,
735 * afterburner is enabled/disabled based on the nvram settings.
737 * WME/WMM is also set in this procedure as it depends on N and afterburner.
738 * N ==> WMM is on by default
739 * N (or ampdu) ==> afterburner is off
740 * WMM ==> afterburner is off
742 * Returns whether afterburner is on in the system.
744 static int
745 wlconf_aburn_ampdu_amsdu_set(char *name, char prefix[PREFIX_LEN], int nmode, int btc_mode)
747 bool ampdu_valid_option = FALSE;
748 bool amsdu_valid_option = FALSE;
749 bool aburn_valid_option = FALSE;
750 int val, aburn_option_val = OFF, ampdu_option_val = OFF, amsdu_option_val = OFF;
751 int wme_option_val = ON; /* On by default */
752 char tmp[100], var[80], *next, *wme_val;
753 char buf[WLC_IOCTL_SMLEN];
754 int ret;
756 /* First, clear WMM and afterburner settings to avoid conflicts */
757 WL_IOVAR_SETINT(name, "wme", OFF);
758 WL_IOVAR_SETINT(name, "afterburner_override", OFF);
760 /* Get WME setting from NVRAM if present */
761 wme_val = nvram_get(strcat_r(prefix, "wme", tmp));
762 if (wme_val && !strcmp(wme_val, "off")) {
763 wme_option_val = OFF;
766 /* Set options based on capability */
767 wl_iovar_get(name, "cap", (void *)tmp, 100);
768 foreach(var, tmp, next) {
769 char *nvram_str = nvram_get(strcat_r(prefix, var, buf));
771 if (!nvram_str)
772 continue;
774 if (!strcmp(nvram_str, "on"))
775 val = ON;
776 else if (!strcmp(nvram_str, "off"))
777 val = OFF;
778 else if (!strcmp(nvram_str, "auto"))
779 val = AUTO;
780 else
781 continue;
783 if (btc_mode != WL_BTC_PREMPT && strncmp(var, "afterburner", sizeof(var)) == 0) {
784 aburn_valid_option = TRUE;
785 aburn_option_val = val;
788 if (strncmp(var, "ampdu", sizeof(var)) == 0) {
789 ampdu_valid_option = TRUE;
790 ampdu_option_val = val;
793 if (strncmp(var, "amsdu", sizeof(var)) == 0) {
794 amsdu_valid_option = TRUE;
795 amsdu_option_val = val;
799 if (nmode != OFF) { /* N-mode is ON/AUTO */
802 if (ampdu_valid_option) {
803 if (ampdu_option_val != OFF) {
804 WL_IOVAR_SETINT(name, "amsdu", OFF);
805 WL_IOVAR_SETINT(name, "ampdu", ampdu_option_val);
806 } else {
807 WL_IOVAR_SETINT(name, "ampdu", OFF);
811 if (amsdu_valid_option) {
812 if (amsdu_option_val != OFF) { /* AMPDU (above) has priority over AMSDU */
813 if (ampdu_option_val == OFF) {
814 WL_IOVAR_SETINT(name, "ampdu", OFF);
815 WL_IOVAR_SETINT(name, "amsdu", amsdu_option_val);
817 } else
818 WL_IOVAR_SETINT(name, "amsdu", OFF);
820 /* allow ab in N mode. Do this last: may defeat ampdu et al */
821 if (aburn_valid_option) {
822 WL_IOVAR_SETINT(name, "afterburner_override", aburn_option_val);
824 /* Also turn off N reqd setting if ab is not OFF */
825 if (aburn_option_val != 0)
826 WL_IOVAR_SETINT(name, "nreqd", 0);
829 } else {
830 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
831 * if WME is off, set the afterburner based on the configured nvram setting.
833 wl_iovar_setint(name, "amsdu", OFF);
834 wl_iovar_setint(name, "ampdu", OFF);
835 if (wme_option_val != OFF) { /* Can't have afterburner with WMM */
836 if (aburn_valid_option) {
837 WL_IOVAR_SETINT(name, "afterburner_override", OFF);
839 } else if (aburn_valid_option) { /* Okay, use NVRam setting for afterburner */
840 WL_IOVAR_SETINT(name, "afterburner_override", aburn_option_val);
844 if (wme_option_val && aburn_option_val == 0) {
845 WL_IOVAR_SETINT(name, "wme", wme_option_val);
846 wlconf_set_wme(name, prefix);
849 return wme_option_val;
852 #define VIFNAME_LEN 16
854 /* configure the specified wireless interface */
856 wlconf(char *name)
858 int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0;
859 int bcmerr;
860 int error_bg, error_a;
861 struct bsscfg_list *bclist = NULL;
862 struct bsscfg_info *bsscfg;
863 char tmp[100], prefix[PREFIX_LEN];
864 char var[80], *next, phy[] = "a", *str, *addr = NULL;
865 /* Pay attention to buffer length requirements when using this */
866 char buf[WLC_IOCTL_SMLEN];
867 char *country;
868 wlc_rev_info_t rev;
869 channel_info_t ci;
870 struct maclist *maclist;
871 struct ether_addr *ea;
872 wlc_ssid_t ssid;
873 wl_rateset_t rs;
874 unsigned int i;
875 char eaddr[32];
876 int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0;
877 char country_code[4];
878 int nas_will_run = 0;
879 char *ba;
880 #ifdef BCMWPA2
881 char *preauth;
882 int set_preauth;
883 #endif
884 int ii;
885 int wlunit = -1;
886 int wlsubunit = -1;
887 int wl_ap_build = 0; /* wl compiled with AP capabilities */
888 char cap[WLC_IOCTL_SMLEN];
889 char caps[WLC_IOCTL_SMLEN];
890 int btc_mode;
891 uint32 leddc;
892 uint nbw = WL_CHANSPEC_BW_20;
893 int nmode = OFF; /* 802.11n support */
894 char vif_addr[WLC_IOCTL_SMLEN];
895 int max_no_vifs = 0;
896 int wme_global;
897 int max_assoc = -1;
898 bool ure_enab = FALSE;
899 bool radar_enab = FALSE;
901 /* wlconf doesn't work for virtual i/f, so if we are given a
902 * virtual i/f return 0 if that interface is in it's parent's "vifs"
903 * list otherwise return -1
905 if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0)
907 if (wlsubunit >= 0)
909 /* we have been given a virtual i/f,
910 * is it in it's parent i/f's virtual i/f list?
912 sprintf(tmp, "wl%d_vifs", wlunit);
914 if (strstr(nvram_safe_get(tmp), name) == NULL)
915 return -1; /* config error */
916 else
917 return 0; /* okay */
920 else
922 return -1;
925 /* clean up tmp */
926 memset(tmp, 0, sizeof(tmp));
928 /* because of ifdefs in wl driver, when we don't have AP capabilities we
929 * can't use the same iovars to configure the wl.
930 * so we use "wl_ap_build" to help us know how to configure the driver
932 if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
933 return -1;
935 foreach(cap, caps, next) {
936 if (!strcmp(cap, "ap")) {
937 wl_ap_build = 1;
939 else if (!strcmp(cap, "mbss16"))
940 max_no_vifs = 16;
941 else if (!strcmp(cap, "mbss4"))
942 max_no_vifs = 4;
945 /* Check interface (fail silently for non-wl interfaces) */
946 if ((ret = wl_probe(name)))
947 return ret;
949 /* Get MAC address */
950 (void) wl_hwaddr(name, (uchar *)buf);
951 memcpy(vif_addr, buf, ETHER_ADDR_LEN);
953 /* Get instance */
954 WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit));
955 snprintf(prefix, sizeof(prefix), "wl%d_", unit);
957 /* Restore defaults if per-interface parameters do not exist */
958 restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
959 wlconf_validate_all(prefix, restore_defaults);
960 nvram_set(strcat_r(prefix, "ifname", tmp), name);
961 nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr));
962 snprintf(buf, sizeof(buf), "%d", unit);
963 nvram_set(strcat_r(prefix, "unit", tmp), buf);
966 /* Bring the interface down */
967 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
969 /* Disable all BSS Configs */
970 for (i = 0; i < WL_MAXBSSCFG; i++) {
971 struct {int bsscfg_idx; int enable;} setbuf;
972 setbuf.bsscfg_idx = i;
973 setbuf.enable = 0;
975 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
976 if (ret) {
977 wl_iovar_getint(name, "bcmerror", &bcmerr);
978 /* fail quietly on a range error since the driver may
979 * support fewer bsscfgs than we are prepared to configure
981 if (bcmerr == BCME_RANGE)
982 break;
984 if (ret)
985 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
986 " (down) failed, ret = %d, bcmerr = %d\n",
987 __LINE__, name, i, ret, bcmerr);
990 /* Get the list of BSS Configs */
991 bclist = wlconf_get_bsscfgs(name, prefix);
992 if (bclist == NULL) {
993 ret = -1;
994 goto exit;
998 /* create a wlX.Y_ifname nvram setting */
999 for (i = 1; i < bclist->count; i++) {
1000 bsscfg = &bclist->bsscfgs[i];
1001 #if defined(linux) || defined(__ECOS)
1002 strcpy(var, bsscfg->ifname);
1003 #endif
1004 nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var);
1007 /* If ure_disable is not present or is 1, ure is not enabled;
1008 * that is, if it is present and 0, ure is enabled.
1010 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
1011 ure_enab = TRUE;
1013 if (wl_ap_build) {
1014 /* Enable MBSS mode if appropriate */
1015 if (!ure_enab) {
1016 WL_IOVAR_SETINT(name, "mbss", (bclist->count > 1));
1020 * Set SSID for each BSS Config
1022 for (i = 0; i < bclist->count; i++) {
1023 bsscfg = &bclist->bsscfgs[i];
1024 strcat_r(bsscfg->prefix, "ssid", tmp);
1025 ssid.SSID_len = strlen(nvram_safe_get(tmp));
1026 if (ssid.SSID_len > sizeof(ssid.SSID))
1027 ssid.SSID_len = sizeof(ssid.SSID);
1028 strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len);
1029 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1030 "with SSID \"%s\"\n", name, bsscfg->idx,
1031 bsscfg->ifname, nvram_safe_get(tmp));
1032 WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid,
1033 sizeof(ssid));
1037 /* Create addresses for VIFs */
1038 if (!ure_enab) {
1039 /* set local bit for our MBSS vif base */
1040 ETHER_SET_LOCALADDR(vif_addr);
1042 /* construct and set other wlX.Y_hwaddr */
1043 for (i = 1; i < max_no_vifs; i++) {
1044 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i);
1045 addr = nvram_safe_get(tmp);
1046 if (!strcmp(addr, "")) {
1047 vif_addr[5] = (vif_addr[5] & ~(max_no_vifs-1))
1048 | ((max_no_vifs-1) & (vif_addr[5]+1));
1050 nvram_set(tmp, ether_etoa((uchar *)vif_addr,
1051 eaddr));
1054 /* The addresses are available in NVRAM, so set them */
1055 for (i = 1; i < max_no_vifs; i++) {
1056 snprintf(tmp, sizeof(tmp), "wl%d.%d_bss_enabled",
1057 unit, i);
1058 if (!strcmp(nvram_safe_get(tmp), "1")) {
1059 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr",
1060 unit, i);
1061 ether_atoe(nvram_safe_get(tmp), (unsigned char *)eaddr);
1062 WL_BSSIOVAR_SET(name, "cur_etheraddr", i,
1063 eaddr, ETHER_ADDR_LEN);
1066 } else { /* URE is enabled */
1067 /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
1068 snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit);
1069 WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr,
1070 ETHER_ADDR_LEN);
1071 nvram_set(tmp, ether_etoa((uchar *)vif_addr, eaddr));
1074 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1075 str = nvram_safe_get(strcat_r(prefix, "mode", tmp));
1076 ap = (!strcmp(str, "") || !strcmp(str, "ap"));
1077 apsta = (!strcmp(str, "apsta") ||
1078 ((!strcmp(str, "sta") || !strcmp(str, "wet")) &&
1079 bclist->count > 1));
1080 sta = (!strcmp(str, "sta") && bclist->count == 1);
1081 wds = !strcmp(str, "wds");
1082 wet = !strcmp(str, "wet");
1083 mac_spoof = !strcmp(str, "mac_spoof");
1085 /* set apsta var first, because APSTA mode takes precedence */
1086 WL_IOVAR_SETINT(name, "apsta", apsta);
1088 /* Set AP mode */
1089 val = (ap || apsta || wds) ? 1 : 0;
1090 WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val));
1092 /* Set mode: WET */
1093 if (wet)
1094 WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet));
1096 if (mac_spoof) {
1097 sta = 1;
1098 WL_IOVAR_SETINT(name, "mac_spoof", 1);
1101 /* For STA configurations, configure association retry time.
1102 * Use specified time (capped), or mode-specific defaults.
1104 if (sta || wet || apsta) {
1105 char *retry_time = nvram_safe_get(strcat_r(prefix, "sta_retry_time", tmp));
1106 val = atoi(retry_time);
1107 WL_IOVAR_SETINT(name, "sta_retry_time", val);
1110 /* Retain remaining WET effects only if not APSTA */
1111 wet &= !apsta;
1113 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1114 val = 1;
1115 if (wet || sta)
1116 val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp)));
1117 WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val));
1119 /* Set The AP MAX Associations Limit */
1120 if (ap | apsta) {
1121 max_assoc = val = atoi(nvram_safe_get(strcat_r(prefix, "maxassoc", tmp)));
1122 if (val > 0) {
1123 WL_IOVAR_SETINT(name, "maxassoc", val);
1124 } else { /* Get value from driver if not in nvram */
1125 WL_IOVAR_GETINT(name, "maxassoc", &max_assoc);
1129 for (i = 0; i < bclist->count; i++) {
1130 char *subprefix;
1131 bsscfg = &bclist->bsscfgs[i];
1133 #ifdef BCMWPA2
1134 /* XXXMSSID: The note about setting preauth now does not seem right.
1135 * NAS brings the BSS up if it runs, so setting the preauth value
1136 * will make it in the bcn/prb. If that is right, we can move this
1137 * chunk out of wlconf.
1140 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1141 * if we do it in the NAS we need to bring down the interface and up to make
1142 * it affect in the beacons
1144 if (ap || (apsta && bsscfg->idx != 0)) {
1145 set_preauth = 1;
1146 preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp));
1147 if (strlen (preauth) != 0) {
1148 set_preauth = atoi(preauth);
1150 wlconf_set_preauth(name, bsscfg->idx, set_preauth);
1152 #endif /* BCMWPA2 */
1154 subprefix = apsta ? prefix : bsscfg->prefix;
1156 if (ap || (apsta && bsscfg->idx != 0)) {
1157 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "bss_maxassoc", tmp)));
1158 if (val > 0) {
1159 WL_BSSIOVAR_SETINT(name, "bss_maxassoc", bsscfg->idx, val);
1160 } else if (max_assoc > 0) { /* Set maxassoc same as global if not set */
1161 snprintf(var, sizeof(var), "%d", max_assoc);
1162 nvram_set(tmp, var);
1166 /* Set network type */
1167 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "closed", tmp)));
1168 WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val);
1170 /* Set the ap isolate mode */
1171 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "ap_isolate", tmp)));
1172 WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val);
1175 /* Set up the country code */
1176 (void) strcat_r(prefix, "country_code", tmp);
1177 country = nvram_get(tmp);
1178 if (country && country[0] != '\0') {
1179 strncpy(country_code, country, sizeof(country_code));
1180 WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
1181 } else {
1182 /* Get the default country code if undefined */
1183 WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code));
1185 /* Add the new NVRAM variable */
1186 nvram_set("wl_country_code", country_code);
1187 (void) strcat_r(prefix, "country_code", tmp);
1188 nvram_set(tmp, country_code);
1191 /* Change LED Duty Cycle */
1192 leddc = (uint32)strtoul(nvram_safe_get(strcat_r(prefix, "leddc", tmp)), NULL, 16);
1193 if (leddc)
1194 WL_IOVAR_SETINT(name, "leddc", leddc);
1196 /* Enable or disable the radio */
1197 val = nvram_match(strcat_r(prefix, "radio", tmp), "0");
1198 val += WL_RADIO_SW_DISABLE << 16;
1199 WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
1201 /* Get supported phy types */
1202 WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var));
1203 nvram_set(strcat_r(prefix, "phytypes", tmp), var);
1205 /* Get radio IDs */
1206 *(next = buf) = '\0';
1207 for (i = 0; i < strlen(var); i++) {
1208 /* Switch to band */
1209 phy[0] = var[i];
1210 val = WLCONF_STR2PHYTYPE(phy);
1211 if (val == PHY_TYPE_N) {
1212 WL_GETINT(name, WLC_GET_BAND, &val);
1213 } else
1214 val = WLCONF_PHYTYPE2BAND(val);
1215 WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
1216 /* Get radio ID on this band */
1217 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1218 next += sprintf(next, "%sBCM%X", i ? " " : "",
1219 (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT);
1221 nvram_set(strcat_r(prefix, "radioids", tmp), buf);
1223 /* Set band */
1224 str = nvram_get(strcat_r(prefix, "phytype", tmp));
1225 val = WLCONF_STR2PHYTYPE(str);
1226 /* For NPHY use band value from NVRAM */
1227 if (val == PHY_TYPE_N) {
1228 str = nvram_get(strcat_r(prefix, "nband", tmp));
1229 if (str)
1230 val = atoi(str);
1231 else {
1232 WL_GETINT(name, WLC_GET_BAND, &val);
1234 } else
1235 val = WLCONF_PHYTYPE2BAND(val);
1237 WL_SETINT(name, WLC_SET_BAND, val);
1239 /* Check errors (card may have changed) */
1240 if (ret) {
1241 /* default band to the first band in band list */
1242 phy[0] = var[0];
1243 val = WLCONF_STR2PHYTYPE(phy);
1244 val = WLCONF_PHYTYPE2BAND(val);
1245 WL_SETINT(name, WLC_SET_BAND, val);
1248 /* Store the resolved bandtype */
1249 bandtype = val;
1251 /* Get current core revision */
1252 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1253 snprintf(buf, sizeof(buf), "%d", rev.corerev);
1254 nvram_set(strcat_r(prefix, "corerev", tmp), buf);
1256 /* Get current phy type */
1257 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
1258 snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype));
1259 nvram_set(strcat_r(prefix, "phytype", tmp), buf);
1261 /* Setup regulatory mode */
1262 strcat_r(prefix, "reg_mode", tmp);
1263 if (nvram_match(tmp, "off")) {
1264 val = 0;
1265 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1266 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1267 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1268 } else if (nvram_match(tmp, "h")) {
1269 val = 0;
1270 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1271 val = 1;
1272 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1273 radar_enab = TRUE;
1274 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1276 /* Set the CAC parameters */
1277 val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_preism", tmp)));
1278 wl_iovar_setint(name, "dfs_preism", val);
1279 val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_postism", tmp)));
1280 wl_iovar_setint(name, "dfs_postism", val);
1281 val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp)));
1282 WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val));
1284 } else if (nvram_match(tmp, "d")) {
1285 val = 0;
1286 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1287 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1288 val = 1;
1289 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1292 /* Reset to hardware rateset (band may have changed) */
1293 WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t));
1294 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1296 /* set bandwidth capability for nphy and calculate nbw */
1297 if (phytype == PHY_TYPE_N) {
1298 /* Get the user nmode setting now */
1299 nmode = AUTO; /* enable by default for NPHY */
1300 /* Set n mode */
1301 strcat_r(prefix, "nmode", tmp);
1302 if (nvram_match(tmp, "0"))
1303 nmode = OFF;
1305 val = (nmode != OFF) ? atoi(nvram_safe_get(strcat_r(prefix, "nbw_cap", tmp))) :
1306 WLC_N_BW_20ALL;
1308 WL_IOVAR_SETINT(name, "nmode", (uint32)nmode);
1309 WL_IOVAR_SETINT(name, "mimo_bw_cap", val);
1311 if (((bandtype == WLC_BAND_2G) && (val == WLC_N_BW_40ALL)) ||
1312 ((bandtype == WLC_BAND_5G) &&
1313 (val == WLC_N_BW_40ALL || val == WLC_N_BW_20IN2G_40IN5G)))
1314 nbw = WL_CHANSPEC_BW_40;
1315 else
1316 nbw = WL_CHANSPEC_BW_20;
1319 /* Set channel before setting gmode or rateset */
1320 /* Manual Channel Selection - when channel # is not 0 */
1321 val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp)));
1322 if (val && phytype != PHY_TYPE_N) {
1323 WL_SETINT(name, WLC_SET_CHANNEL, val);
1324 if (ret) {
1325 /* Use current channel (card may have changed) */
1326 WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
1327 snprintf(buf, sizeof(buf), "%d", ci.target_channel);
1328 nvram_set(strcat_r(prefix, "channel", tmp), buf);
1330 } else if (val && phytype == PHY_TYPE_N) {
1331 chanspec_t chanspec = 0;
1332 uint channel;
1333 uint nctrlsb = WL_CHANSPEC_CTL_SB_NONE;
1335 channel = val;
1337 /* Get Ctrl SB for 40MHz channel */
1338 if (nbw == WL_CHANSPEC_BW_40) {
1339 str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp));
1341 /* Adjust the channel to be center channel */
1342 if (!strcmp(str, "lower")) {
1343 nctrlsb = WL_CHANSPEC_CTL_SB_LOWER;
1344 channel = channel + 2;
1345 } else if (!strcmp(str, "upper")) {
1346 nctrlsb = WL_CHANSPEC_CTL_SB_UPPER;
1347 channel = channel - 2;
1351 /* band | BW | CTRL SB | Channel */
1352 chanspec |= ((bandtype << WL_CHANSPEC_BAND_SHIFT) |
1353 (nbw | nctrlsb | channel));
1355 WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec);
1358 /* Set up number of Tx and Rx streams */
1359 if (phytype == PHY_TYPE_N) {
1360 int count;
1361 int streams;
1363 wl_iovar_getint(name, "txchain_cnt", &count);
1364 /* update NVRAM with capabilities */
1365 snprintf(var, sizeof(var), "%d", count);
1366 nvram_set(strcat_r(prefix, "txchain_cnt", tmp), var);
1368 /* Verify that there is an NVRAM param for txstreams, if not create it and
1369 * set it to txchain_cnt
1371 streams = atoi(nvram_safe_get(strcat_r(prefix, "txstreams", tmp)));
1372 if (streams == 0) {
1373 /* invalid - NVRAM needs to be fixed/initialized */
1374 nvram_set(strcat_r(prefix, "txstreams", tmp), var);
1375 streams = count;
1377 /* Apply user configured txstreams, use 1 if user disabled nmode */
1378 if (nmode == OFF)
1379 streams = 1;
1380 WL_IOVAR_SETINT(name, "txstreams", streams);
1382 wl_iovar_getint(name, "rxchain_cnt", &count);
1383 /* update NVRAM with capabilities */
1384 snprintf(var, sizeof(var), "%d", count);
1385 nvram_set(strcat_r(prefix, "rxchain_cnt", tmp), var);
1387 /* Verify that there is an NVRAM param for rxstreams, if not create it and
1388 * set it to txchain_cnt
1390 streams = atoi(nvram_safe_get(strcat_r(prefix, "rxstreams", tmp)));
1391 if (streams == 0) {
1392 /* invalid - NVRAM needs to be fixed/initialized */
1393 nvram_set(strcat_r(prefix, "rxstreams", tmp), var);
1394 streams = count;
1397 /* Apply user configured rxstreams, use 1 if user disabled nmode */
1398 if (nmode == OFF)
1399 streams = 1;
1400 WL_IOVAR_SETINT(name, "rxstreams", streams);
1403 /* Set gmode */
1404 if (bandtype == WLC_BAND_2G) {
1405 int override = WLC_PROTECTION_OFF;
1406 int control = WLC_PROTECTION_CTL_OFF;
1408 /* Set gmode */
1409 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp)));
1410 WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode));
1412 /* Set gmode protection override and control algorithm */
1413 strcat_r(prefix, "gmode_protection", tmp);
1414 if (nvram_match(tmp, "auto")) {
1415 override = WLC_PROTECTION_AUTO;
1416 control = WLC_PROTECTION_CTL_OVERLAP;
1418 WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override));
1419 WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control));
1422 /* Set nmode_protection */
1423 if (phytype == PHY_TYPE_N) {
1424 int override = WLC_PROTECTION_OFF;
1425 int control = WLC_PROTECTION_CTL_OFF;
1427 /* Set n protection override and control algorithm */
1428 strcat_r(prefix, "nmode_protection", tmp);
1430 if (nvram_match(tmp, "auto")) {
1431 override = WLC_PROTECTION_AUTO;
1432 control = WLC_PROTECTION_CTL_OVERLAP;
1435 WL_IOVAR_SETINT(name, "nmode_protection_override",
1436 (uint32)override);
1437 WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control));
1440 /* Set 802.11n required */
1441 if (nmode != OFF) {
1442 uint32 nreqd = OFF; /* default */
1444 strcat_r(prefix, "nreqd", tmp);
1446 if (nvram_match(tmp, "1"))
1447 nreqd = ON;
1449 WL_IOVAR_SETINT(name, "nreqd", nreqd);
1452 /* Set vlan_prio_mode */
1454 uint32 mode = OFF; /* default */
1456 strcat_r(prefix, "vlan_prio_mode", tmp);
1458 if (nvram_match(tmp, "on"))
1459 mode = ON;
1461 WL_IOVAR_SETINT(name, "vlan_mode", mode);
1464 /* Get bluetooth coexistance(BTC) mode */
1465 btc_mode = atoi(nvram_safe_get(strcat_r(prefix, "btc_mode", tmp)));
1467 /* Set the afterburner, AMPDU and AMSDU options based on the N-mode */
1468 wme_global = wlconf_aburn_ampdu_amsdu_set(name, prefix, nmode, btc_mode);
1470 /* Now that wme_global is known, check per-BSS disable settings */
1471 for (i = 0; i < bclist->count; i++) {
1472 char *subprefix;
1473 bsscfg = &bclist->bsscfgs[i];
1475 subprefix = apsta ? prefix : bsscfg->prefix;
1477 /* For each BSS, check WME; make sure wme is set properly for this interface */
1478 strcat_r(subprefix, "wme", tmp);
1479 nvram_set(tmp, wme_global ? "on" : "off");
1481 str = nvram_safe_get(strcat_r(bsscfg->prefix, "wme_bss_disable", tmp));
1482 val = (str[0] == '1') ? 1 : 0;
1483 WL_BSSIOVAR_SETINT(name, "wme_bss_disable", bsscfg->idx, val);
1486 /* Set BTC mode */
1487 if (!wl_iovar_setint(name, "btc_mode", btc_mode)) {
1488 if (btc_mode == WL_BTC_PREMPT) {
1489 wl_rateset_t rs_tmp = rs;
1490 /* remove 1Mbps and 2 Mbps from rateset */
1491 for (i = 0, rs.count = 0; i < rs_tmp.count; i++) {
1492 if ((rs_tmp.rates[i] & 0x7f) == 2 || (rs_tmp.rates[i] & 0x7f) == 4)
1493 continue;
1494 rs.rates[rs.count++] = rs_tmp.rates[i];
1499 /* Allow short preamble override for b cards */
1500 if (phytype == PHY_TYPE_B ||
1501 (phytype == PHY_TYPE_G && (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) {
1502 strcat_r(prefix, "plcphdr", tmp);
1503 if (nvram_match(tmp, "long"))
1504 val = WLC_PLCP_AUTO;
1505 else
1506 val = WLC_PLCP_SHORT;
1507 WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val));
1510 /* Set rate in 500 Kbps units */
1511 val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000;
1513 /* Convert Auto mcsidx to Auto rate */
1514 if (phytype == PHY_TYPE_N) {
1515 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1517 /* -1 mcsidx used to designate AUTO rate */
1518 if (mcsidx == -1)
1519 val = 0;
1522 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1523 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1524 /* Must b/g band. Set to 5.5Mbps */
1525 val = 11;
1527 /* it is band-blind. try both band */
1528 error_bg = wl_iovar_setint(name, "bg_rate", val);
1529 error_a = wl_iovar_setint(name, "a_rate", val);
1531 if (error_bg && error_a) {
1532 /* both failed. Try default rate (card may have changed) */
1533 val = 0;
1535 error_bg = wl_iovar_setint(name, "bg_rate", val);
1536 error_a = wl_iovar_setint(name, "a_rate", val);
1538 snprintf(buf, sizeof(buf), "%d", val);
1539 nvram_set(strcat_r(prefix, "rate", tmp), buf);
1542 /* check if nrate needs to be applied */
1543 if (nmode != OFF) {
1544 uint32 nrate = 0;
1545 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1546 bool ismcs = (mcsidx >= 0);
1548 /* mcsidx of 32 is valid only for 40 Mhz */
1549 if (mcsidx == 32 && nbw == WL_CHANSPEC_BW_20) {
1550 mcsidx = -1;
1551 ismcs = FALSE;
1552 nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1");
1555 /* Use nrate iovar only for MCS rate. */
1556 if (ismcs) {
1557 nrate |= NRATE_MCS_INUSE;
1558 nrate |= mcsidx & NRATE_RATE_MASK;
1560 WL_IOVAR_SETINT(name, "nrate", nrate);
1564 /* Set multicast rate in 500 Kbps units */
1565 val = atoi(nvram_safe_get(strcat_r(prefix, "mrate", tmp))) / 500000;
1566 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1567 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1568 /* Must b/g band. Set to 5.5Mbps */
1569 val = 11;
1571 /* it is band-blind. try both band */
1572 error_bg = wl_iovar_setint(name, "bg_mrate", val);
1573 error_a = wl_iovar_setint(name, "a_mrate", val);
1575 if (error_bg && error_a) {
1576 /* Try default rate (card may have changed) */
1577 val = 0;
1579 wl_iovar_setint(name, "bg_mrate", val);
1580 wl_iovar_setint(name, "a_mrate", val);
1582 snprintf(buf, sizeof(buf), "%d", val);
1583 nvram_set(strcat_r(prefix, "mrate", tmp), buf);
1586 /* Set fragmentation threshold */
1587 val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp)));
1588 wl_iovar_setint(name, "fragthresh", val);
1590 /* Set RTS threshold */
1591 val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp)));
1592 wl_iovar_setint(name, "rtsthresh", val);
1594 /* Set DTIM period */
1595 val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp)));
1596 WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val));
1598 /* Set beacon period */
1599 val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp)));
1600 WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val));
1602 /* Set framebursting mode */
1603 if (btc_mode == WL_BTC_PREMPT)
1604 val = FALSE;
1605 else
1606 val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on");
1607 WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val));
1609 /* Set RIFS mode based on framebursting */
1610 if (phytype == PHY_TYPE_N) {
1611 char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp));
1612 if (!strcmp(nvram_str, "on"))
1613 wl_iovar_setint(name, "rifs", ON);
1614 else if (!strcmp(nvram_str, "off"))
1615 wl_iovar_setint(name, "rifs", OFF);
1618 /* Override BA mode only if set to on/off */
1619 ba = nvram_safe_get(strcat_r(prefix, "ba", tmp));
1620 if (!strcmp(ba, "on"))
1621 wl_iovar_setint(name, "ba", ON);
1622 else if (!strcmp(ba, "off"))
1623 wl_iovar_setint(name, "ba", OFF);
1625 if (phytype == PHY_TYPE_N) {
1626 val = AVG_DMA_XFER_RATE;
1627 wl_iovar_set(name, "avg_dma_xfer_rate", &val, sizeof(val));
1630 /* Bring the interface back up */
1631 WL_IOCTL(name, WLC_UP, NULL, 0);
1633 /* Set antenna */
1634 val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp)));
1635 WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val));
1638 /* Get current rateset (gmode may have changed) */
1639 WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t));
1641 strcat_r(prefix, "rateset", tmp);
1642 if (nvram_match(tmp, "all")) {
1643 /* Make all rates basic */
1644 for (i = 0; i < rs.count; i++)
1645 rs.rates[i] |= 0x80;
1646 } else if (nvram_match(tmp, "12") && bandtype == WLC_BAND_2G) {
1647 /* Make 1 and 2 basic */
1648 for (i = 0; i < rs.count; i++) {
1649 if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4)
1650 rs.rates[i] |= 0x80;
1651 else
1652 rs.rates[i] &= ~0x80;
1656 /* Set rateset. */
1657 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1659 /* Set radar parameters if it is enabled */
1660 if (radar_enab) {
1661 wlconf_set_radarthrs(name, prefix);
1664 /* The following condition(s) must be met in order for Auto Channel Selection to work.
1665 * - the I/F must be up for the channel scan
1666 * - the AP must not be supporting a BSS (all BSS Configs must be disabled)
1668 if (ap || apsta) {
1669 int channel = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp)));
1671 if (channel == 0) {
1672 if (phytype == PHY_TYPE_N) {
1673 chanspec_t chanspec;
1674 chanspec = wlconf_auto_chanspec(name);
1675 if (chanspec != 0)
1676 WL_IOVAR_SETINT(name, "chanspec", chanspec);
1677 } else {
1678 /* select a channel */
1679 val = wlconf_auto_channel(name);
1680 /* switch to the selected channel */
1681 if (val != 0)
1682 WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
1684 /* set the auto channel scan timer in the driver when in auto mode */
1685 if (channel == 0) {
1686 val = 15; /* 15 minutes for now */
1687 } else {
1688 val = 0;
1691 else {
1692 /* reset the channel scan timer in the driver when not in auto mode */
1693 val = 0;
1696 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1699 /* Security settings for each BSS Configuration */
1700 for (i = 0; i < bclist->count; i++) {
1701 bsscfg = &bclist->bsscfgs[i];
1702 wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, wet | sta);
1705 /* AP only config */
1706 if (ap || apsta || wds) {
1707 /* Set lazy WDS mode */
1708 val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp)));
1709 WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val));
1711 /* Set the WDS list */
1712 maclist = (struct maclist *) buf;
1713 maclist->count = 0;
1714 ea = maclist->ea;
1715 foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
1716 if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)])))
1717 break;
1718 ether_atoe(var, ea->octet);
1719 maclist->count++;
1720 ea++;
1722 WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
1724 /* Set WDS link detection timeout */
1725 val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp)));
1726 wl_iovar_setint(name, "wdstimeout", val);
1730 * Finally enable BSS Configs or Join BSS
1732 * AP: Enable BSS Config to bring AP up only when nas will not run
1733 * STA: Join the BSS regardless.
1735 for (i = 0; i < bclist->count; i++) {
1736 struct {int bsscfg_idx; int enable;} setbuf;
1737 char vifname[VIFNAME_LEN];
1738 char *name_ptr = name;
1740 setbuf.bsscfg_idx = bclist->bsscfgs[i].idx;
1741 setbuf.enable = 0;
1743 bsscfg = &bclist->bsscfgs[i];
1744 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) {
1745 setbuf.enable = 1;
1748 /* Set the MAC list */
1749 maclist = (struct maclist *)buf;
1750 maclist->count = 0;
1751 if (!nvram_match(strcat_r(bsscfg->prefix, "macmode", tmp), "disabled")) {
1752 ea = maclist->ea;
1753 foreach(var, nvram_safe_get(strcat_r(bsscfg->prefix, "maclist", tmp)),
1754 next) {
1755 if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)])))
1756 break;
1757 if (ether_atoe(var, ea->octet)) {
1758 maclist->count++;
1759 ea++;
1764 if (setbuf.bsscfg_idx == 0) {
1765 name_ptr = name;
1766 } else { /* Non-primary BSS; changes name syntax */
1767 char tmp[VIFNAME_LEN];
1768 int len;
1770 /* Remove trailing _ if present */
1771 memset(tmp, 0, sizeof(tmp));
1772 strncpy(tmp, bsscfg->prefix, VIFNAME_LEN - 1);
1773 if (((len = strlen(tmp)) > 0) && (tmp[len - 1] == '_')) {
1774 tmp[len - 1] = 0;
1776 nvifname_to_osifname(tmp, vifname, VIFNAME_LEN);
1777 name_ptr = vifname;
1780 WL_IOCTL(name_ptr, WLC_SET_MACLIST, buf, sizeof(buf));
1782 /* Set macmode for each VIF */
1783 (void) strcat_r(bsscfg->prefix, "macmode", tmp);
1785 if (nvram_match(tmp, "deny"))
1786 val = WLC_MACMODE_DENY;
1787 else if (nvram_match(tmp, "allow"))
1788 val = WLC_MACMODE_ALLOW;
1789 else
1790 val = WLC_MACMODE_DISABLED;
1792 WL_IOCTL(name_ptr, WLC_SET_MACMODE, &val, sizeof(val));
1794 /* NAS runs if we have an AKM or radius authentication */
1795 nas_will_run = wlconf_akm_options(bclist->bsscfgs[i].prefix) ||
1796 nvram_match(strcat_r(bclist->bsscfgs[i].prefix, "auth_mode", tmp),
1797 "radius");
1799 if (((ap || apsta) && !nas_will_run) || sta || wet) {
1800 for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) {
1801 if (wl_ap_build) {
1802 WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf));
1804 else {
1805 strcat_r(prefix, "ssid", tmp);
1806 ssid.SSID_len = strlen(nvram_safe_get(tmp));
1807 if (ssid.SSID_len > sizeof(ssid.SSID))
1808 ssid.SSID_len = sizeof(ssid.SSID);
1809 strncpy((char *)ssid.SSID, nvram_safe_get(tmp),
1810 ssid.SSID_len);
1811 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1813 if (apsta && (ret != 0))
1814 sleep_ms(1000);
1815 else
1816 break;
1821 ret = 0;
1822 exit:
1823 if (bclist != NULL)
1824 free(bclist);
1826 return ret;
1830 wlconf_down(char *name)
1832 int val, ret = 0;
1833 int i;
1834 int wlsubunit;
1835 int bcmerr;
1836 struct {int bsscfg_idx; int enable;} setbuf;
1837 int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */
1838 char cap[WLC_IOCTL_SMLEN];
1839 char caps[WLC_IOCTL_SMLEN];
1840 char *next;
1841 wlc_ssid_t ssid;
1843 /* wlconf doesn't work for virtual i/f */
1844 if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) {
1845 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name);
1846 return 0;
1849 /* Check interface (fail silently for non-wl interfaces) */
1850 if ((ret = wl_probe(name)))
1851 return ret;
1853 /* because of ifdefs in wl driver, when we don't have AP capabilities we
1854 * can't use the same iovars to configure the wl.
1855 * so we use "wl_ap_build" to help us know how to configure the driver
1857 if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
1858 return -1;
1860 foreach(cap, caps, next) {
1861 if (!strcmp(cap, "ap")) {
1862 wl_ap_build = 1;
1866 if (wl_ap_build) {
1867 /* Bring down the interface */
1868 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1870 /* Disable all BSS Configs */
1871 for (i = 0; i < WL_MAXBSSCFG; i++) {
1872 setbuf.bsscfg_idx = i;
1873 setbuf.enable = 0;
1875 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
1876 if (ret) {
1877 wl_iovar_getint(name, "bcmerror", &bcmerr);
1878 /* fail quietly on a range error since the driver may
1879 * support fewer bsscfgs than we are prepared to configure
1881 if (bcmerr == BCME_RANGE)
1882 break;
1886 else {
1887 WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
1888 if (val) {
1889 /* Nuke SSID */
1890 ssid.SSID_len = 0;
1891 ssid.SSID[0] = '\0';
1892 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1894 /* Bring down the interface */
1895 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1899 /* Nuke the WDS list */
1900 wlconf_wds_clear(name);
1902 return 0;
1905 #if defined(linux)
1907 main(int argc, char *argv[])
1909 /* Check parameters and branch based on action */
1910 if (argc == 3 && !strcmp(argv[2], "up"))
1911 return wlconf(argv[1]);
1912 else if (argc == 3 && !strcmp(argv[2], "down"))
1913 return wlconf_down(argv[1]);
1914 else {
1915 fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
1916 return -1;
1919 #endif