minor wlconf update
[tomato.git] / release / src / router / wlconf / wlconf.c
blobb9e810aba558a3b2eb22e5cc1ed695fc2313e7d8
1 /*
2 * Wireless Network Adapter Configuration Utility
4 * Copyright 2007, 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 #else
532 #error "sleep_ms() not defined for this OS!!!"
533 #endif /* defined(linux) */
536 * The following condition(s) must be met when Auto Channel Selection
537 * is enabled.
538 * - the I/F is up (change radio channel requires it is up?)
539 * - the AP must not be associated (setting SSID to empty should
540 * make sure it for us)
542 static uint8
543 wlconf_auto_channel(char *name)
545 int chosen = 0;
546 wl_uint32_list_t request;
547 int phytype;
548 int ret;
549 int i;
551 /* query the phy type */
552 WL_GETINT(name, WLC_GET_PHYTYPE, &phytype);
554 request.count = 0; /* let the ioctl decide */
555 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
556 if (!ret) {
557 sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
558 for (i = 0; i < 100; i++) {
559 WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen);
560 if (!ret)
561 break;
562 sleep_ms(100);
565 WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
566 return chosen;
569 static chanspec_t
570 wlconf_auto_chanspec(char *name)
572 chanspec_t chosen = 0;
573 wl_uint32_list_t request;
574 int bandtype;
575 int ret;
576 int i;
578 /* query the band type */
579 WL_GETINT(name, WLC_GET_BAND, &bandtype);
581 request.count = 0; /* let the ioctl decide */
582 WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
583 if (!ret) {
584 sleep_ms(1000);
585 for (i = 0; i < 100; i++) {
586 WL_IOVAR_GETINT(name, "apcschspec", (void *)&chosen);
587 if (!ret)
588 break;
589 sleep_ms(100);
592 WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen);
593 return chosen;
596 /* PHY type/BAND conversion */
597 #define WLCONF_PHYTYPE2BAND(phy) ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
598 /* PHY type conversion */
599 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
600 (phy) == PHY_TYPE_B ? "b" : \
601 (phy) == PHY_TYPE_LP ? "l" : \
602 (phy) == PHY_TYPE_G ? "g" : "n")
603 #define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
604 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \
605 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \
606 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N)
608 #define PREFIX_LEN 32 /* buffer size for wlXXX_ prefix */
610 struct bsscfg_info {
611 int idx; /* bsscfg index */
612 char ifname[PREFIX_LEN]; /* OS name of interface (debug only) */
613 char prefix[PREFIX_LEN]; /* prefix for nvram params (eg. "wl0.1_") */
616 struct bsscfg_list {
617 int count;
618 struct bsscfg_info bsscfgs[WL_MAXBSSCFG];
621 struct bsscfg_list *
622 wlconf_get_bsscfgs(char* ifname, char* prefix)
624 char var[80];
625 char tmp[100];
626 char *next;
628 struct bsscfg_list *bclist;
629 struct bsscfg_info *bsscfg;
631 bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list));
632 if (bclist == NULL)
633 return NULL;
634 memset(bclist, 0, sizeof(struct bsscfg_list));
636 /* Set up Primary BSS Config information */
637 bsscfg = &bclist->bsscfgs[0];
638 bsscfg->idx = 0;
639 strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1);
640 strcpy(bsscfg->prefix, prefix);
641 bclist->count = 1;
643 /* additional virtual BSS Configs from wlX_vifs */
644 foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) {
645 if (bclist->count == WL_MAXBSSCFG) {
646 WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
647 "in nvram %s\n"
648 "while configuring interface \"%s\"\n",
649 ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var);
650 continue;
652 bsscfg = &bclist->bsscfgs[bclist->count];
653 if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) {
654 WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
655 "name \"%s\"\n",
656 ifname, var);
657 continue;
659 strncpy(bsscfg->ifname, var, PREFIX_LEN-1);
660 snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname);
661 bclist->count++;
664 return bclist;
667 static void
668 wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool id_supp)
670 int i;
671 int val;
672 int ret;
673 char tmp[100];
675 /* Set WSEC */
677 * Need to check errors (card may have changed) and change to
678 * defaults since the new chip may not support the requested
679 * encryptions after the card has been changed.
681 if (wlconf_set_wsec(name, prefix, bsscfg_idx)) {
682 /* change nvram only, code below will pass them on */
683 wlconf_restore_var(prefix, "auth_mode");
684 wlconf_restore_var(prefix, "auth");
685 /* reset wep to default */
686 wlconf_restore_var(prefix, "crypto");
687 wlconf_restore_var(prefix, "wep");
688 wlconf_set_wsec(name, prefix, bsscfg_idx);
691 val = wlconf_akm_options(prefix);
692 /* enable in-driver wpa supplicant? */
693 if (id_supp && (CHECK_PSK(val))) {
694 wsec_pmk_t psk;
695 char *key;
697 if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) &&
698 (strlen(key) < WSEC_MAX_PSK_LEN)) {
699 psk.key_len = (ushort) strlen(key);
700 psk.flags = WSEC_PASSPHRASE;
701 strcpy((char *)psk.key, key);
702 WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
704 wl_iovar_setint(name, "sup_wpa", 1);
706 WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val);
708 /* EAP Restrict if we have an AKM or radius authentication */
709 val = ((val != 0) || (nvram_match(strcat_r(prefix, "auth_mode", tmp), "radius")));
710 WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val);
712 /* Set WEP keys */
713 if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) {
714 for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++)
715 wlconf_set_wep_key(name, prefix, bsscfg_idx, i);
718 /* Set 802.11 authentication mode - open/shared */
719 val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp)));
720 WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val);
724 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled
725 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
726 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off,
727 * afterburner is enabled/disabled based on the nvram settings.
729 * WME/WMM is also set in this procedure as it depends on N and afterburner.
730 * N ==> WMM is on by default
731 * N (or ampdu) ==> afterburner is off
732 * WMM ==> afterburner is off
734 * Returns whether afterburner is on in the system.
736 static int
737 wlconf_aburn_ampdu_amsdu_set(char *name, char prefix[PREFIX_LEN], int nmode, int btc_mode)
739 bool ampdu_valid_option = FALSE;
740 bool amsdu_valid_option = FALSE;
741 bool aburn_valid_option = FALSE;
742 int val, aburn_option_val = OFF, ampdu_option_val = OFF, amsdu_option_val = OFF;
743 int wme_option_val = ON; /* On by default */
744 char tmp[100], var[80], *next, *wme_val;
745 char buf[WLC_IOCTL_SMLEN];
746 int ret;
748 /* First, clear WMM and afterburner settings to avoid conflicts */
749 WL_IOVAR_SETINT(name, "wme", OFF);
750 WL_IOVAR_SETINT(name, "afterburner_override", OFF);
752 /* Get WME setting from NVRAM if present */
753 wme_val = nvram_get(strcat_r(prefix, "wme", tmp));
754 if (wme_val && !strcmp(wme_val, "off")) {
755 wme_option_val = OFF;
758 /* Set options based on capability */
759 wl_iovar_get(name, "cap", (void *)tmp, 100);
760 foreach(var, tmp, next) {
761 char *nvram_str = nvram_get(strcat_r(prefix, var, buf));
763 if (!nvram_str)
764 continue;
766 if (!strcmp(nvram_str, "on"))
767 val = ON;
768 else if (!strcmp(nvram_str, "off"))
769 val = OFF;
770 else if (!strcmp(nvram_str, "auto"))
771 val = AUTO;
772 else
773 continue;
775 if (btc_mode != WL_BTC_PREMPT && strncmp(var, "afterburner", sizeof(var)) == 0) {
776 aburn_valid_option = TRUE;
777 aburn_option_val = val;
780 if (strncmp(var, "ampdu", sizeof(var)) == 0) {
781 ampdu_valid_option = TRUE;
782 ampdu_option_val = val;
785 if (strncmp(var, "amsdu", sizeof(var)) == 0) {
786 amsdu_valid_option = TRUE;
787 amsdu_option_val = val;
791 if (nmode != OFF) { /* N-mode is ON/AUTO */
793 if (aburn_valid_option) { /* Turn off afterburner in N-mode */
794 WL_IOVAR_SETINT(name, "afterburner_override", OFF);
797 if (ampdu_valid_option) {
798 if (ampdu_option_val != OFF) {
799 WL_IOVAR_SETINT(name, "amsdu", OFF);
800 WL_IOVAR_SETINT(name, "ampdu", ampdu_option_val);
801 } else {
802 WL_IOVAR_SETINT(name, "ampdu", OFF);
806 if (amsdu_valid_option) {
807 if (amsdu_option_val != OFF) { /* AMPDU (above) has priority over AMSDU */
808 if (ampdu_option_val == OFF) {
809 WL_IOVAR_SETINT(name, "ampdu", OFF);
810 WL_IOVAR_SETINT(name, "amsdu", amsdu_option_val);
812 } else
813 WL_IOVAR_SETINT(name, "amsdu", OFF);
815 } else {
816 /* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
817 * if WME is off, set the afterburner based on the configured nvram setting.
819 wl_iovar_setint(name, "amsdu", OFF);
820 wl_iovar_setint(name, "ampdu", OFF);
821 if (wme_option_val != OFF) { /* Can't have afterburner with WMM */
822 if (aburn_valid_option) {
823 WL_IOVAR_SETINT(name, "afterburner_override", OFF);
825 } else if (aburn_valid_option) { /* Okay, use NVRam setting for afterburner */
826 WL_IOVAR_SETINT(name, "afterburner_override", aburn_option_val);
830 if (wme_option_val) {
831 WL_IOVAR_SETINT(name, "wme", wme_option_val);
832 wlconf_set_wme(name, prefix);
835 return wme_option_val;
838 #define VIFNAME_LEN 16
840 /* configure the specified wireless interface */
842 wlconf(char *name)
844 int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0;
845 int bcmerr;
846 int error_bg, error_a;
847 struct bsscfg_list *bclist = NULL;
848 struct bsscfg_info *bsscfg;
849 char tmp[100], prefix[PREFIX_LEN];
850 char var[80], *next, phy[] = "a", *str, *addr = NULL;
851 /* Pay attention to buffer length requirements when using this */
852 char buf[WLC_IOCTL_SMLEN];
853 char *country;
854 wlc_rev_info_t rev;
855 channel_info_t ci;
856 struct maclist *maclist;
857 struct ether_addr *ea;
858 wlc_ssid_t ssid;
859 wl_rateset_t rs;
860 unsigned int i;
861 char eaddr[32];
862 int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0;
863 char country_code[4];
864 int nas_will_run = 0;
865 char *ba;
866 #ifdef BCMWPA2
867 char *preauth;
868 int set_preauth;
869 #endif
870 int ii;
871 int wlunit = -1;
872 int wlsubunit = -1;
873 int wl_ap_build = 0; /* wl compiled with AP capabilities */
874 char cap[WLC_IOCTL_SMLEN];
875 char caps[WLC_IOCTL_SMLEN];
876 int btc_mode;
877 uint32 leddc;
878 uint nbw = WL_CHANSPEC_BW_20;
879 int nmode = OFF; /* 802.11n support */
880 char vif_addr[WLC_IOCTL_SMLEN];
881 int max_no_vifs = 0;
882 int wme_global;
883 int max_assoc = -1;
884 bool ure_enab = FALSE;
885 bool radar_enab = FALSE;
887 /* wlconf doesn't work for virtual i/f, so if we are given a
888 * virtual i/f return 0 if that interface is in it's parent's "vifs"
889 * list otherwise return -1
891 if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0)
893 if (wlsubunit >= 0)
895 /* we have been given a virtual i/f,
896 * is it in it's parent i/f's virtual i/f list?
898 sprintf(tmp, "wl%d_vifs", wlunit);
900 if (strstr(nvram_safe_get(tmp), name) == NULL)
901 return -1; /* config error */
902 else
903 return 0; /* okay */
906 else
908 return -1;
911 /* clean up tmp */
912 memset(tmp, 0, sizeof(tmp));
914 /* because of ifdefs in wl driver, when we don't have AP capabilities we
915 * can't use the same iovars to configure the wl.
916 * so we use "wl_ap_build" to help us know how to configure the driver
918 if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
919 return -1;
921 foreach(cap, caps, next) {
922 if (!strcmp(cap, "ap")) {
923 wl_ap_build = 1;
925 else if (!strcmp(cap, "mbss16"))
926 max_no_vifs = 16;
927 else if (!strcmp(cap, "mbss4"))
928 max_no_vifs = 4;
931 /* Check interface (fail silently for non-wl interfaces) */
932 if ((ret = wl_probe(name)))
933 return ret;
935 /* Get MAC address */
936 (void) wl_hwaddr(name, (uchar *)buf);
937 memcpy(vif_addr, buf, ETHER_ADDR_LEN);
939 /* Get instance */
940 WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit));
941 snprintf(prefix, sizeof(prefix), "wl%d_", unit);
943 /* Restore defaults if per-interface parameters do not exist */
944 restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
945 wlconf_validate_all(prefix, restore_defaults);
946 nvram_set(strcat_r(prefix, "ifname", tmp), name);
947 nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr));
948 snprintf(buf, sizeof(buf), "%d", unit);
949 nvram_set(strcat_r(prefix, "unit", tmp), buf);
952 /* Bring the interface down */
953 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
955 /* Disable all BSS Configs */
956 for (i = 0; i < WL_MAXBSSCFG; i++) {
957 struct {int bsscfg_idx; int enable;} setbuf;
958 setbuf.bsscfg_idx = i;
959 setbuf.enable = 0;
961 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
962 if (ret) {
963 wl_iovar_getint(name, "bcmerror", &bcmerr);
964 /* fail quietly on a range error since the driver may
965 * support fewer bsscfgs than we are prepared to configure
967 if (bcmerr == BCME_RANGE)
968 break;
970 if (ret)
971 WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
972 " (down) failed, ret = %d, bcmerr = %d\n",
973 __LINE__, name, i, ret, bcmerr);
976 /* Get the list of BSS Configs */
977 bclist = wlconf_get_bsscfgs(name, prefix);
978 if (bclist == NULL) {
979 ret = -1;
980 goto exit;
984 /* create a wlX.Y_ifname nvram setting */
985 for (i = 1; i < bclist->count; i++) {
986 bsscfg = &bclist->bsscfgs[i];
987 #if defined(linux)
988 strcpy(var, bsscfg->ifname);
989 #endif
990 nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var);
993 /* If ure_disable is not present or is 1, ure is not enabled;
994 * that is, if it is present and 0, ure is enabled.
996 if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
997 ure_enab = TRUE;
999 if (wl_ap_build) {
1000 /* Enable MBSS mode if appropriate */
1001 if (!ure_enab) {
1002 WL_IOVAR_SETINT(name, "mbss", (bclist->count > 1));
1006 * Set SSID for each BSS Config
1008 for (i = 0; i < bclist->count; i++) {
1009 bsscfg = &bclist->bsscfgs[i];
1010 strcat_r(bsscfg->prefix, "ssid", tmp);
1011 ssid.SSID_len = strlen(nvram_safe_get(tmp));
1012 if (ssid.SSID_len > sizeof(ssid.SSID))
1013 ssid.SSID_len = sizeof(ssid.SSID);
1014 strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len);
1015 WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1016 "with SSID \"%s\"\n", name, bsscfg->idx,
1017 bsscfg->ifname, nvram_safe_get(tmp));
1018 WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid,
1019 sizeof(ssid));
1023 /* Create addresses for VIFs */
1024 if (!ure_enab) {
1025 /* set local bit for our MBSS vif base */
1026 ETHER_SET_LOCALADDR(vif_addr);
1028 /* construct and set other wlX.Y_hwaddr */
1029 for (i = 1; i < max_no_vifs; i++) {
1030 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i);
1031 addr = nvram_safe_get(tmp);
1032 if (!strcmp(addr, "")) {
1033 vif_addr[5] = (vif_addr[5] & ~(max_no_vifs-1))
1034 | ((max_no_vifs-1) & (vif_addr[5]+1));
1036 nvram_set(tmp, ether_etoa((uchar *)vif_addr,
1037 eaddr));
1040 /* The addresses are available in NVRAM, so set them */
1041 for (i = 1; i < max_no_vifs; i++) {
1042 snprintf(tmp, sizeof(tmp), "wl%d.%d_bss_enabled",
1043 unit, i);
1044 if (!strcmp(nvram_safe_get(tmp), "1")) {
1045 snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr",
1046 unit, i);
1047 ether_atoe(nvram_safe_get(tmp), eaddr);
1048 WL_BSSIOVAR_SET(name, "cur_etheraddr", i,
1049 eaddr, ETHER_ADDR_LEN);
1052 } else { /* URE is enabled */
1053 /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
1054 snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit);
1055 WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr,
1056 ETHER_ADDR_LEN);
1057 nvram_set(tmp, ether_etoa((uchar *)vif_addr, eaddr));
1060 /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1061 str = nvram_safe_get(strcat_r(prefix, "mode", tmp));
1062 ap = (!strcmp(str, "") || !strcmp(str, "ap"));
1063 apsta = (!strcmp(str, "apsta") ||
1064 ((!strcmp(str, "sta") || !strcmp(str, "wet")) &&
1065 bclist->count > 1));
1066 sta = (!strcmp(str, "sta") && bclist->count == 1);
1067 wds = !strcmp(str, "wds");
1068 wet = !strcmp(str, "wet");
1069 mac_spoof = !strcmp(str, "mac_spoof");
1071 /* Set AP mode */
1072 val = (ap || apsta || wds) ? 1 : 0;
1073 WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val));
1075 WL_IOVAR_SETINT(name, "apsta", apsta);
1077 /* Set mode: WET */
1078 if (wet)
1079 WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet));
1081 if (mac_spoof) {
1082 sta = 1;
1083 WL_IOVAR_SETINT(name, "mac_spoof", 1);
1086 /* For STA configurations, configure association retry time.
1087 * Use specified time (capped), or mode-specific defaults.
1089 if (sta || wet || apsta) {
1090 char *retry_time = nvram_safe_get(strcat_r(prefix, "sta_retry_time", tmp));
1091 val = atoi(retry_time);
1092 WL_IOVAR_SETINT(name, "sta_retry_time", val);
1095 /* Retain remaining WET effects only if not APSTA */
1096 wet &= !apsta;
1098 /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1099 val = 1;
1100 if (wet || sta)
1101 val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp)));
1102 WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val));
1104 /* Set The AP MAX Associations Limit */
1105 if (ap | apsta) {
1106 max_assoc = val = atoi(nvram_safe_get(strcat_r(prefix, "maxassoc", tmp)));
1107 if (val > 0) {
1108 WL_IOVAR_SETINT(name, "maxassoc", val);
1109 } else { /* Get value from driver if not in nvram */
1110 WL_IOVAR_GETINT(name, "maxassoc", &max_assoc);
1114 for (i = 0; i < bclist->count; i++) {
1115 char *subprefix;
1116 bsscfg = &bclist->bsscfgs[i];
1118 #ifdef BCMWPA2
1119 /* XXXMBSS: The note about setting preauth now does not seem right.
1120 * NAS brings the BSS up if it runs, so setting the preauth value
1121 * will make it in the bcn/prb. If that is right, we can move this
1122 * chunk out of wlconf.
1125 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1126 * if we do it in the NAS we need to bring down the interface and up to make
1127 * it affect in the beacons
1129 if (ap || (apsta && bsscfg->idx != 0)) {
1130 set_preauth = 1;
1131 preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp));
1132 if (strlen (preauth) != 0) {
1133 set_preauth = atoi(preauth);
1135 wlconf_set_preauth(name, bsscfg->idx, set_preauth);
1137 #endif /* BCMWPA2 */
1139 subprefix = apsta ? prefix : bsscfg->prefix;
1141 if (ap || (apsta && bsscfg->idx != 0)) {
1142 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "bss_maxassoc", tmp)));
1143 if (val > 0) {
1144 WL_BSSIOVAR_SETINT(name, "bss_maxassoc", bsscfg->idx, val);
1145 } else if (max_assoc > 0) { /* Set maxassoc same as global if not set */
1146 snprintf(var, sizeof(var), "%d", max_assoc);
1147 nvram_set(tmp, var);
1151 /* Set network type */
1152 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "closed", tmp)));
1153 WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val);
1155 /* Set the ap isolate mode */
1156 val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "ap_isolate", tmp)));
1157 WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val);
1160 /* Set up the country code */
1161 (void) strcat_r(prefix, "country_code", tmp);
1162 country = nvram_get(tmp);
1163 if (country && country[0] != '\0') {
1164 strncpy(country_code, country, sizeof(country_code));
1165 WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
1166 } else {
1167 /* Get the default country code if undefined */
1168 WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code));
1170 /* Add the new NVRAM variable */
1171 nvram_set("wl_country_code", country_code);
1172 (void) strcat_r(prefix, "country_code", tmp);
1173 nvram_set(tmp, country_code);
1176 /* Change LED Duty Cycle */
1177 leddc = (uint32)strtoul(nvram_safe_get(strcat_r(prefix, "leddc", tmp)), NULL, 16);
1178 if (leddc)
1179 WL_IOVAR_SETINT(name, "leddc", leddc);
1181 /* Enable or disable the radio */
1182 val = nvram_match(strcat_r(prefix, "radio", tmp), "0");
1183 val += WL_RADIO_SW_DISABLE << 16;
1184 WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
1186 /* Get supported phy types */
1187 WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var));
1188 nvram_set(strcat_r(prefix, "phytypes", tmp), var);
1190 /* Get radio IDs */
1191 *(next = buf) = '\0';
1192 for (i = 0; i < strlen(var); i++) {
1193 /* Switch to band */
1194 phy[0] = var[i];
1195 val = WLCONF_STR2PHYTYPE(phy);
1196 if (val == PHY_TYPE_N) {
1197 WL_GETINT(name, WLC_GET_BAND, &val);
1198 } else
1199 val = WLCONF_PHYTYPE2BAND(val);
1200 WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
1201 /* Get radio ID on this band */
1202 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1203 next += sprintf(next, "%sBCM%X", i ? " " : "",
1204 (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT);
1206 nvram_set(strcat_r(prefix, "radioids", tmp), buf);
1208 /* Set band */
1209 str = nvram_get(strcat_r(prefix, "phytype", tmp));
1210 val = WLCONF_STR2PHYTYPE(str);
1211 /* For NPHY use band value from NVRAM */
1212 if (val == PHY_TYPE_N) {
1213 str = nvram_get(strcat_r(prefix, "nband", tmp));
1214 if (str)
1215 val = atoi(str);
1216 else {
1217 WL_GETINT(name, WLC_GET_BAND, &val);
1219 } else
1220 val = WLCONF_PHYTYPE2BAND(val);
1222 WL_SETINT(name, WLC_SET_BAND, val);
1224 /* Check errors (card may have changed) */
1225 if (ret) {
1226 /* default band to the first band in band list */
1227 phy[0] = var[0];
1228 val = WLCONF_STR2PHYTYPE(phy);
1229 val = WLCONF_PHYTYPE2BAND(val);
1230 WL_SETINT(name, WLC_SET_BAND, val);
1233 /* Store the resolved bandtype */
1234 bandtype = val;
1236 /* Get current core revision */
1237 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1238 snprintf(buf, sizeof(buf), "%d", rev.corerev);
1239 nvram_set(strcat_r(prefix, "corerev", tmp), buf);
1241 /* Get current phy type */
1242 WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
1243 snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype));
1244 nvram_set(strcat_r(prefix, "phytype", tmp), buf);
1246 /* Setup regulatory mode */
1247 strcat_r(prefix, "reg_mode", tmp);
1248 if (nvram_match(tmp, "off")) {
1249 val = 0;
1250 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1251 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1252 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1253 } else if (nvram_match(tmp, "h")) {
1254 val = 0;
1255 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1256 val = 1;
1257 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1258 radar_enab = TRUE;
1259 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1261 /* Set the CAC parameters */
1262 val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_preism", tmp)));
1263 wl_iovar_setint(name, "dfs_preism", val);
1264 val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_postism", tmp)));
1265 wl_iovar_setint(name, "dfs_postism", val);
1266 val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp)));
1267 WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val));
1269 } else if (nvram_match(tmp, "d")) {
1270 val = 0;
1271 WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1272 WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1273 val = 1;
1274 WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1277 /* set bandwidth capability for nphy and calculate nbw */
1278 if (phytype == PHY_TYPE_N) {
1279 /* Get the user nmode setting now */
1280 nmode = AUTO; /* enable by default for NPHY */
1281 /* Set n mode */
1282 strcat_r(prefix, "nmode", tmp);
1283 if (nvram_match(tmp, "0"))
1284 nmode = OFF;
1286 val = (nmode != OFF) ? atoi(nvram_safe_get(strcat_r(prefix, "nbw_cap", tmp))) :
1287 WLC_N_BW_20ALL;
1289 WL_IOVAR_SETINT(name, "nmode", (uint32)nmode);
1290 WL_IOVAR_SETINT(name, "mimo_bw_cap", val);
1292 if (((bandtype == WLC_BAND_2G) && (val == WLC_N_BW_40ALL)) ||
1293 ((bandtype == WLC_BAND_5G) &&
1294 (val == WLC_N_BW_40ALL || val == WLC_N_BW_20IN2G_40IN5G)))
1295 nbw = WL_CHANSPEC_BW_40;
1296 else
1297 nbw = WL_CHANSPEC_BW_20;
1300 /* Set channel before setting gmode or rateset */
1301 /* Manual Channel Selection - when channel # is not 0 */
1302 val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp)));
1303 if (val && phytype != PHY_TYPE_N) {
1304 WL_SETINT(name, WLC_SET_CHANNEL, val);
1305 if (ret) {
1306 /* Use current channel (card may have changed) */
1307 WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
1308 snprintf(buf, sizeof(buf), "%d", ci.target_channel);
1309 nvram_set(strcat_r(prefix, "channel", tmp), buf);
1311 } else if (val && phytype == PHY_TYPE_N) {
1312 chanspec_t chanspec = 0;
1313 uint channel;
1314 uint nctrlsb = WL_CHANSPEC_CTL_SB_NONE;
1316 channel = val;
1318 /* Get Ctrl SB for 40MHz channel */
1319 if (nbw == WL_CHANSPEC_BW_40) {
1320 str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp));
1322 /* Adjust the channel to be center channel */
1323 if (!strcmp(str, "lower")) {
1324 nctrlsb = WL_CHANSPEC_CTL_SB_LOWER;
1325 channel = channel + 2;
1326 } else if (!strcmp(str, "upper")) {
1327 nctrlsb = WL_CHANSPEC_CTL_SB_UPPER;
1328 channel = channel - 2;
1332 /* band | BW | CTRL SB | Channel */
1333 chanspec |= ((bandtype << WL_CHANSPEC_BAND_SHIFT) |
1334 (nbw | nctrlsb | channel));
1336 WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec);
1339 /* Set up number of Tx and Rx streams */
1340 if (phytype == PHY_TYPE_N) {
1341 int count;
1342 int streams;
1344 wl_iovar_getint(name, "txchain_cnt", &count);
1345 /* update NVRAM with capabilities */
1346 snprintf(var, sizeof(var), "%d", count);
1347 nvram_set(strcat_r(prefix, "txchain_cnt", tmp), var);
1349 /* Verify that there is an NVRAM param for txstreams, if not create it and
1350 * set it to txchain_cnt
1352 streams = atoi(nvram_safe_get(strcat_r(prefix, "txstreams", tmp)));
1353 if (streams == 0) {
1354 /* invalid - NVRAM needs to be fixed/initialized */
1355 nvram_set(strcat_r(prefix, "txstreams", tmp), var);
1356 streams = count;
1358 /* Apply user configured txstreams, use 1 if user disabled nmode */
1359 if (nmode == OFF)
1360 streams = 1;
1361 WL_IOVAR_SETINT(name, "txstreams", streams);
1363 wl_iovar_getint(name, "rxchain_cnt", &count);
1364 /* update NVRAM with capabilities */
1365 snprintf(var, sizeof(var), "%d", count);
1366 nvram_set(strcat_r(prefix, "rxchain_cnt", tmp), var);
1368 /* Verify that there is an NVRAM param for rxstreams, if not create it and
1369 * set it to txchain_cnt
1371 streams = atoi(nvram_safe_get(strcat_r(prefix, "rxstreams", tmp)));
1372 if (streams == 0) {
1373 /* invalid - NVRAM needs to be fixed/initialized */
1374 nvram_set(strcat_r(prefix, "rxstreams", tmp), var);
1375 streams = count;
1378 /* Apply user configured rxstreams, use 1 if user disabled nmode */
1379 if (nmode == OFF)
1380 streams = 1;
1381 WL_IOVAR_SETINT(name, "rxstreams", streams);
1384 /* Reset to hardware rateset (band may have changed) */
1385 WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t));
1386 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1388 /* Set gmode */
1389 if (bandtype == WLC_BAND_2G) {
1390 int override = WLC_G_PROTECTION_OFF;
1391 int control = WLC_G_PROTECTION_CTL_OFF;
1393 /* Set gmode */
1394 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp)));
1395 WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode));
1397 /* Set gmode protection override and control algorithm */
1398 strcat_r(prefix, "gmode_protection", tmp);
1399 if (nvram_match(tmp, "auto")) {
1400 override = WLC_G_PROTECTION_AUTO;
1401 control = WLC_G_PROTECTION_CTL_OVERLAP;
1403 WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override));
1404 WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control));
1407 /* Set nmode_protection */
1408 if (phytype == PHY_TYPE_N) {
1409 int override = WLC_PROTECTION_OFF;
1410 int control = WLC_PROTECTION_CTL_OFF;
1412 /* Set n protection override and control algorithm */
1413 strcat_r(prefix, "nmode_protection", tmp);
1415 if (nvram_match(tmp, "auto")) {
1416 override = WLC_PROTECTION_AUTO;
1417 control = WLC_PROTECTION_CTL_OVERLAP;
1420 WL_IOVAR_SETINT(name, "nmode_protection_override",
1421 (uint32)override);
1422 WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control));
1425 /* Set 802.11n required */
1426 if (nmode != OFF) {
1427 uint32 nreqd = OFF; /* default */
1429 strcat_r(prefix, "nreqd", tmp);
1431 if (nvram_match(tmp, "1"))
1432 nreqd = ON;
1434 WL_IOVAR_SETINT(name, "nreqd", nreqd);
1437 /* Set vlan_prio_mode */
1439 uint32 mode = OFF; /* default */
1441 strcat_r(prefix, "vlan_prio_mode", tmp);
1443 if (nvram_match(tmp, "on"))
1444 mode = ON;
1446 WL_IOVAR_SETINT(name, "vlan_mode", mode);
1449 /* Get bluetooth coexistance(BTC) mode */
1450 btc_mode = atoi(nvram_safe_get(strcat_r(prefix, "btc_mode", tmp)));
1452 /* Set the afterburner, AMPDU and AMSDU options based on the N-mode */
1453 wme_global = wlconf_aburn_ampdu_amsdu_set(name, prefix, nmode, btc_mode);
1455 /* Now that wme_global is known, check per-BSS disable settings */
1456 for (i = 0; i < bclist->count; i++) {
1457 char *subprefix;
1458 bsscfg = &bclist->bsscfgs[i];
1460 subprefix = apsta ? prefix : bsscfg->prefix;
1462 /* For each BSS, check WME; make sure wme is set properly for this interface */
1463 strcat_r(subprefix, "wme", tmp);
1464 nvram_set(tmp, wme_global ? "on" : "off");
1466 str = nvram_safe_get(strcat_r(bsscfg->prefix, "wme_bss_disable", tmp));
1467 val = (str[0] == '1') ? 1 : 0;
1468 WL_BSSIOVAR_SETINT(name, "wme_bss_disable", bsscfg->idx, val);
1472 /* Get current rateset (gmode may have changed) */
1473 WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof(wl_rateset_t));
1475 strcat_r(prefix, "rateset", tmp);
1476 if (nvram_match(tmp, "all")) {
1477 /* Make all rates basic */
1478 for (i = 0; i < rs.count; i++)
1479 rs.rates[i] |= 0x80;
1480 } else if (nvram_match(tmp, "12")) {
1481 /* Make 1 and 2 basic */
1482 for (i = 0; i < rs.count; i++) {
1483 if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4)
1484 rs.rates[i] |= 0x80;
1485 else
1486 rs.rates[i] &= ~0x80;
1490 /* Set BTC mode */
1491 if (!wl_iovar_setint(name, "btc_mode", btc_mode)) {
1492 if (btc_mode == WL_BTC_PREMPT) {
1493 wl_rateset_t rs_tmp = rs;
1494 /* remove 1Mbps and 2 Mbps from rateset */
1495 for (i = 0, rs.count = 0; i < rs_tmp.count; i++) {
1496 if ((rs_tmp.rates[i] & 0x7f) == 2 || (rs_tmp.rates[i] & 0x7f) == 4)
1497 continue;
1498 rs.rates[rs.count++] = rs_tmp.rates[i];
1503 /* Set rateset */
1504 WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1506 /* Allow short preamble override for b cards */
1507 if (phytype == PHY_TYPE_B ||
1508 (phytype == PHY_TYPE_G && (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) {
1509 strcat_r(prefix, "plcphdr", tmp);
1510 if (nvram_match(tmp, "long"))
1511 val = WLC_PLCP_AUTO;
1512 else
1513 val = WLC_PLCP_SHORT;
1514 WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val));
1517 /* Set rate in 500 Kbps units */
1518 val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000;
1520 /* Convert Auto mcsidx to Auto rate */
1521 if (phytype == PHY_TYPE_N) {
1522 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1524 /* -1 mcsidx used to designate AUTO rate */
1525 if (mcsidx == -1)
1526 val = 0;
1529 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1530 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1531 /* Must b/g band. Set to 5.5Mbps */
1532 val = 11;
1534 /* it is band-blind. try both band */
1535 error_bg = wl_iovar_setint(name, "bg_rate", val);
1536 error_a = wl_iovar_setint(name, "a_rate", val);
1538 if (error_bg && error_a) {
1539 /* both failed. Try default rate (card may have changed) */
1540 val = 0;
1542 error_bg = wl_iovar_setint(name, "bg_rate", val);
1543 error_a = wl_iovar_setint(name, "a_rate", val);
1545 snprintf(buf, sizeof(buf), "%d", val);
1546 nvram_set(strcat_r(prefix, "rate", tmp), buf);
1549 /* check if nrate needs to be applied */
1550 if (nmode != OFF) {
1551 uint32 nrate = 0;
1552 int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1553 bool ismcs = (mcsidx >= 0);
1555 /* mcsidx of 32 is valid only for 40 Mhz */
1556 if (mcsidx == 32 && nbw == WL_CHANSPEC_BW_20) {
1557 mcsidx = -1;
1558 ismcs = FALSE;
1559 nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1");
1562 /* Use nrate iovar only for MCS rate. */
1563 if (ismcs) {
1564 nrate |= NRATE_MCS_INUSE;
1565 nrate |= mcsidx & NRATE_RATE_MASK;
1567 WL_IOVAR_SETINT(name, "nrate", nrate);
1571 /* Set multicast rate in 500 Kbps units */
1572 val = atoi(nvram_safe_get(strcat_r(prefix, "mrate", tmp))) / 500000;
1573 /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1574 if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1575 /* Must b/g band. Set to 5.5Mbps */
1576 val = 11;
1578 /* it is band-blind. try both band */
1579 error_bg = wl_iovar_setint(name, "bg_mrate", val);
1580 error_a = wl_iovar_setint(name, "a_mrate", val);
1582 if (error_bg && error_a) {
1583 /* Try default rate (card may have changed) */
1584 val = 0;
1586 wl_iovar_setint(name, "bg_mrate", val);
1587 wl_iovar_setint(name, "a_mrate", val);
1589 snprintf(buf, sizeof(buf), "%d", val);
1590 nvram_set(strcat_r(prefix, "mrate", tmp), buf);
1593 /* Set fragmentation threshold */
1594 val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp)));
1595 wl_iovar_setint(name, "fragthresh", val);
1597 /* Set RTS threshold */
1598 val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp)));
1599 wl_iovar_setint(name, "rtsthresh", val);
1601 /* Set DTIM period */
1602 val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp)));
1603 WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val));
1605 /* Set beacon period */
1606 val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp)));
1607 WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val));
1609 /* Set framebursting mode */
1610 if (btc_mode == WL_BTC_PREMPT)
1611 val = FALSE;
1612 else
1613 val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on");
1614 WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val));
1616 /* Set RIFS mode based on framebursting */
1617 if (phytype == PHY_TYPE_N) {
1618 char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp));
1619 if (!strcmp(nvram_str, "on"))
1620 wl_iovar_setint(name, "rifs", ON);
1621 else if (!strcmp(nvram_str, "off"))
1622 wl_iovar_setint(name, "rifs", OFF);
1625 /* Override BA mode only if set to on/off */
1626 ba = nvram_safe_get(strcat_r(prefix, "ba", tmp));
1627 if (!strcmp(ba, "on"))
1628 wl_iovar_setint(name, "ba", ON);
1629 else if (!strcmp(ba, "off"))
1630 wl_iovar_setint(name, "ba", OFF);
1632 if (phytype == PHY_TYPE_N) {
1633 val = AVG_DMA_XFER_RATE;
1634 wl_iovar_set(name, "avg_dma_xfer_rate", &val, sizeof(val));
1637 /* Bring the interface back up */
1638 WL_IOCTL(name, WLC_UP, NULL, 0);
1640 /* Set antenna */
1641 val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp)));
1642 WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val));
1644 /* Set radar parameters if it is enabled */
1645 if (radar_enab) {
1646 wlconf_set_radarthrs(name, prefix);
1649 /* Auto Channel Selection - when channel # is 0 in AP mode
1651 * The following condition(s) must be met in order for
1652 * Auto Channel Selection to work.
1653 * - the I/F must be up for the channel scan
1654 * - the AP must not be supporting a BSS (all BSS Configs must be disabled)
1656 if (ap || apsta) {
1657 if (!(val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))))) {
1658 if (phytype == PHY_TYPE_N) {
1659 chanspec_t chanspec = wlconf_auto_chanspec(name);
1660 if (chanspec != 0)
1661 WL_IOVAR_SETINT(name, "chanspec", chanspec);
1663 else {
1664 /* select a channel */
1665 val = wlconf_auto_channel(name);
1666 /* switch to the selected channel */
1667 if (val != 0)
1668 WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
1670 /* set the auto channel scan timer in the driver when in auto mode */
1671 val = 15; /* 15 minutes for now */
1672 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1674 else {
1675 /* reset the channel scan timer in the driver when not in auto mode */
1676 val = 0;
1677 WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1681 /* Security settings for each BSS Configuration */
1682 for (i = 0; i < bclist->count; i++) {
1683 bsscfg = &bclist->bsscfgs[i];
1684 wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, mac_spoof);
1687 /* AP only config */
1688 if (ap || apsta || wds) {
1689 /* Set lazy WDS mode */
1690 val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp)));
1691 WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val));
1693 /* Set the WDS list */
1694 maclist = (struct maclist *) buf;
1695 maclist->count = 0;
1696 ea = maclist->ea;
1697 foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
1698 if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)])))
1699 break;
1700 ether_atoe(var, ea->octet);
1701 maclist->count++;
1702 ea++;
1704 WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
1706 /* Set WDS link detection timeout */
1707 val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp)));
1708 wl_iovar_setint(name, "wdstimeout", val);
1710 if (wds) {
1711 wl_iovar_setint(name, "radio_init", 1);
1716 * Finally enable BSS Configs or Join BSS
1718 * AP: Enable BSS Config to bring AP up only when nas will not run
1719 * STA: Join the BSS regardless.
1721 for (i = 0; i < bclist->count; i++) {
1722 struct {int bsscfg_idx; int enable;} setbuf;
1723 char vifname[VIFNAME_LEN];
1724 char *name_ptr = name;
1726 setbuf.bsscfg_idx = bclist->bsscfgs[i].idx;
1727 setbuf.enable = 0;
1729 bsscfg = &bclist->bsscfgs[i];
1730 if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) {
1731 setbuf.enable = 1;
1734 /* Set the MAC list */
1735 maclist = (struct maclist *)buf;
1736 maclist->count = 0;
1737 if (!nvram_match(strcat_r(bsscfg->prefix, "macmode", tmp), "disabled")) {
1738 ea = maclist->ea;
1739 foreach(var, nvram_safe_get(strcat_r(bsscfg->prefix, "maclist", tmp)),
1740 next) {
1741 if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)])))
1742 break;
1743 if (ether_atoe(var, ea->octet)) {
1744 maclist->count++;
1745 ea++;
1750 if (setbuf.bsscfg_idx == 0) {
1751 name_ptr = name;
1752 } else { /* Non-primary BSS; changes name syntax */
1753 char tmp[VIFNAME_LEN];
1754 int len;
1756 /* Remove trailing _ if present */
1757 memset(tmp, 0, sizeof(tmp));
1758 strncpy(tmp, bsscfg->prefix, VIFNAME_LEN - 1);
1759 if (((len = strlen(tmp)) > 0) && (tmp[len - 1] == '_')) {
1760 tmp[len - 1] = 0;
1762 nvifname_to_osifname(tmp, vifname, VIFNAME_LEN);
1763 name_ptr = vifname;
1766 WL_IOCTL(name_ptr, WLC_SET_MACLIST, buf, sizeof(buf));
1768 /* Set macmode for each VIF */
1769 (void) strcat_r(bsscfg->prefix, "macmode", tmp);
1771 if (nvram_match(tmp, "deny"))
1772 val = WLC_MACMODE_DENY;
1773 else if (nvram_match(tmp, "allow"))
1774 val = WLC_MACMODE_ALLOW;
1775 else
1776 val = WLC_MACMODE_DISABLED;
1778 WL_IOCTL(name_ptr, WLC_SET_MACMODE, &val, sizeof(val));
1780 /* NAS runs if we have an AKM or radius authentication */
1781 nas_will_run = wlconf_akm_options(bclist->bsscfgs[i].prefix) ||
1782 nvram_match(strcat_r(bclist->bsscfgs[i].prefix, "auth_mode", tmp),
1783 "radius");
1785 if (((ap || apsta) && !nas_will_run) || sta || wet) {
1786 for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) {
1787 if (wl_ap_build) {
1788 WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf));
1790 else {
1791 strcat_r(prefix, "ssid", tmp);
1792 ssid.SSID_len = strlen(nvram_safe_get(tmp));
1793 if (ssid.SSID_len > sizeof(ssid.SSID))
1794 ssid.SSID_len = sizeof(ssid.SSID);
1795 strncpy((char *)ssid.SSID, nvram_safe_get(tmp),
1796 ssid.SSID_len);
1797 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1799 if (apsta && (ret != 0))
1800 sleep_ms(1000);
1801 else
1802 break;
1807 ret = 0;
1808 exit:
1809 if (bclist != NULL)
1810 free(bclist);
1812 return ret;
1816 wlconf_down(char *name)
1818 int val, ret = 0;
1819 int i;
1820 int wlsubunit;
1821 int bcmerr;
1822 struct {int bsscfg_idx; int enable;} setbuf;
1823 int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */
1824 char cap[WLC_IOCTL_SMLEN];
1825 char caps[WLC_IOCTL_SMLEN];
1826 char *next;
1827 wlc_ssid_t ssid;
1829 /* wlconf doesn't work for virtual i/f */
1830 if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) {
1831 WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name);
1832 return 0;
1835 /* Check interface (fail silently for non-wl interfaces) */
1836 if ((ret = wl_probe(name)))
1837 return ret;
1839 /* because of ifdefs in wl driver, when we don't have AP capabilities we
1840 * can't use the same iovars to configure the wl.
1841 * so we use "wl_ap_build" to help us know how to configure the driver
1843 if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
1844 return -1;
1846 foreach(cap, caps, next) {
1847 if (!strcmp(cap, "ap")) {
1848 wl_ap_build = 1;
1852 if (wl_ap_build) {
1853 /* Bring down the interface */
1854 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1856 /* Disable all BSS Configs */
1857 for (i = 0; i < WL_MAXBSSCFG; i++) {
1858 setbuf.bsscfg_idx = i;
1859 setbuf.enable = 0;
1861 ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
1862 if (ret) {
1863 wl_iovar_getint(name, "bcmerror", &bcmerr);
1864 /* fail quietly on a range error since the driver may
1865 * support fewer bsscfgs than we are prepared to configure
1867 if (bcmerr == BCME_RANGE)
1868 break;
1872 else {
1873 WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
1874 if (val) {
1875 /* Nuke SSID */
1876 ssid.SSID_len = 0;
1877 ssid.SSID[0] = '\0';
1878 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1880 /* Bring down the interface */
1881 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1885 /* Nuke the WDS list */
1886 wlconf_wds_clear(name);
1888 return 0;
1891 #if defined(linux)
1893 main(int argc, char *argv[])
1895 /* Check parameters and branch based on action */
1896 if (argc == 3 && !strcmp(argv[2], "up"))
1897 return wlconf(argv[1]);
1898 else if (argc == 3 && !strcmp(argv[2], "down"))
1899 return wlconf_down(argv[1]);
1900 else {
1901 fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
1902 return -1;
1905 #endif