1/*
2 * Wireless Network Adapter Configuration Utility
3 *
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.
11 *
12 * $Id: wlconf.c,v 1.1.1.1 2008/10/15 03:31:23 james26_jang Exp $
13 */
14
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>
25
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
33
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
36 */
37#define MAX_BSS_UP_RETRIES 5
38
39/* notify the average dma xfer rate (in kbps) to the driver */
40#define AVG_DMA_XFER_RATE 120000
41
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
49
50/*
51 * Debugging Macros
52 */
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))
69
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
75
76/* prototypes */
77struct bsscfg_list *wlconf_get_bsscfgs(char* ifname, char* prefix);
78int wlconf(char *name);
79int wlconf_down(char *name);
80
81int wlconf_ssid(void);
82int wlconf_set_ssid(char *tmpssid);
83int wlconf_txant(char *var);
84int wlconf_antdiv(char *var);
85int wlconf_radio(char *act);
86int wlconf_auth(char *act);
87int wlconf_wsec(char *var);
88int wlconf_wpa_auth(char *var);
89int wlconf_eap(char *var);
90int wlconf_rate(char *var);
91int wlconf_led(void);
92int wlconf_set_led(char *tmpssid);
93
94static int
95wlconf_getint(char* ifname, int cmd, int *pval)
96{
97	return wl_ioctl(ifname, cmd, pval, sizeof(int));
98}
99
100static int
101wlconf_setint(char* ifname, int cmd, int val)
102{
103	return wl_ioctl(ifname, cmd, &val, sizeof(int));
104}
105
106static int
107wlconf_wds_clear(char *name)
108{
109	struct maclist maclist;
110	int    ret;
111
112	maclist.count = 0;
113	WL_IOCTL(name, WLC_SET_WDSLIST, &maclist, sizeof(maclist));
114
115	return ret;
116}
117
118/* set WEP key */
119static int
120wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i)
121{
122	wl_wsec_key_t key;
123	char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
124	char *keystr, hex[] = "XX";
125	unsigned char *data = key.data;
126	int ret = 0;
127
128	memset(&key, 0, sizeof(key));
129	key.index = i - 1;
130	sprintf(wl_key, "%skey%d", prefix, i);
131	keystr = nvram_safe_get(wl_key);
132
133	switch (strlen(keystr)) {
134	case WEP1_KEY_SIZE:
135	case WEP128_KEY_SIZE:
136		key.len = strlen(keystr);
137		strcpy((char *)key.data, keystr);
138		break;
139	case WEP1_KEY_HEX_SIZE:
140	case WEP128_KEY_HEX_SIZE:
141		key.len = strlen(keystr) / 2;
142		while (*keystr) {
143			strncpy(hex, keystr, 2);
144			*data++ = (unsigned char) strtoul(hex, NULL, 16);
145			keystr += 2;
146		}
147		break;
148	default:
149		key.len = 0;
150		break;
151	}
152
153	/* Set current WEP key */
154	if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key))))
155		key.flags = WL_PRIMARY_KEY;
156
157	WL_BSSIOVAR_SET(name, "wsec_key", bsscfg_idx, &key, sizeof(key));
158
159	return ret;
160}
161
162extern struct nvram_tuple router_defaults[];
163
164/* validate/restore all per-interface related variables */
165static void
166wlconf_validate_all(char *prefix, bool restore)
167{
168	struct nvram_tuple *t;
169	char tmp[100];
170	char *v;
171	for (t = router_defaults; t->name; t++) {
172		if (!strncmp(t->name, "wl_", 3)) {
173			strcat_r(prefix, &t->name[3], tmp);
174			if (!restore && nvram_get(tmp))
175				continue;
176			v = nvram_get(t->name);
177			nvram_set(tmp, v ? v : t->value);
178		}
179	}
180}
181
182/* restore specific per-interface variable */
183static void
184wlconf_restore_var(char *prefix, char *name)
185{
186	struct nvram_tuple *t;
187	char tmp[100];
188	for (t = router_defaults; t->name; t++) {
189		if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) {
190			nvram_set(strcat_r(prefix, name, tmp), t->value);
191			break;
192		}
193	}
194}
195static int
196wlconf_akm_options(char *prefix)
197{
198	char comb[32];
199	char *wl_akm;
200	int akm_ret_val = 0;
201	char akm[32];
202	char *next;
203
204	wl_akm = nvram_safe_get(strcat_r(prefix, "akm", comb));
205	foreach(akm, wl_akm, next) {
206		if (!strcmp(akm, "wpa"))
207			akm_ret_val |= WPA_AUTH_UNSPECIFIED;
208		if (!strcmp(akm, "psk"))
209			akm_ret_val |= WPA_AUTH_PSK;
210#ifdef BCMWPA2
211		if (!strcmp(akm, "wpa2"))
212			akm_ret_val |= WPA2_AUTH_UNSPECIFIED;
213		if (!strcmp(akm, "psk2"))
214			akm_ret_val |= WPA2_AUTH_PSK;
215		if (!strcmp(akm, "brcm_psk"))
216			akm_ret_val |= BRCM_AUTH_PSK;
217#endif
218	}
219	return akm_ret_val;
220}
221
222/* Set up wsec */
223static int
224wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx)
225{
226	char tmp[100];
227	int val = 0;
228	int akm_val;
229	int ret;
230
231	/* Set wsec bitvec */
232	akm_val = wlconf_akm_options(prefix);
233	if (akm_val != 0) {
234		if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip"))
235			val = TKIP_ENABLED;
236		else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes"))
237			val = AES_ENABLED;
238		else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes"))
239			val = TKIP_ENABLED | AES_ENABLED;
240	}
241	if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled"))
242		val |= WEP_ENABLED;
243	WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val);
244	/* Set wsec restrict if WSEC_ENABLED */
245	WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0);
246
247	return 0;
248}
249
250#ifdef BCMWPA2
251static int
252wlconf_set_preauth(char *name, int bsscfg_idx, int preauth)
253{
254	uint cap;
255	int ret;
256
257	WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint));
258	if (ret != 0) return -1;
259
260	if (preauth)
261		cap |= WPA_CAP_WPA2_PREAUTH;
262	else
263		cap &= ~WPA_CAP_WPA2_PREAUTH;
264
265	WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap);
266
267	return ret;
268}
269#endif /* BCMWPA2 */
270
271static void
272wlconf_set_radarthrs(char *name, char *prefix)
273{
274	wl_radar_thr_t  radar_thr;
275	int  i, ret, len;
276	char nv_buf[NVRAM_MAX_VALUE_LEN], *rargs, *v, *endptr;
277	char buf[WLC_IOCTL_SMLEN];
278	char *version = NULL, *thr0_20_lo = NULL, *thr1_20_lo = NULL, *thr0_40_lo = NULL;
279	char *thr1_40_lo = NULL, *thr0_20_hi = NULL, *thr1_20_hi = NULL, *thr0_40_hi = NULL;
280	char *thr1_40_hi = NULL;
281	char **locals[] = { &version, &thr0_20_lo, &thr1_20_lo, &thr0_40_lo, &thr1_40_lo,
282	                    &thr0_20_hi, &thr1_20_hi, &thr0_40_hi, &thr1_40_hi };
283
284	rargs = nvram_safe_get(strcat_r(prefix, "radarthrs", nv_buf));
285	if (!rargs)
286		goto err;
287
288	len = strlen(rargs);
289	if ((len > NVRAM_MAX_VALUE_LEN) || (len == 0))
290		goto err;
291
292	memset(nv_buf, 0, sizeof(nv_buf));
293	strncpy(nv_buf, rargs, len);
294	v = nv_buf;
295	for (i = 0; i < (sizeof(locals) / sizeof(locals[0])); i++) {
296		*locals[i] = v;
297		while (*v && *v != ' ') {
298			v++;
299		}
300		if (*v) {
301			*v = 0;
302			v++;
303		}
304		if (v >= (nv_buf + len)) /* Check for complete list, if not caught later */
305			break;
306	}
307
308	/* Start building request */
309	memset(buf, 0, sizeof(buf));
310	strcpy(buf, "radarthrs");
311	/* Retrieve radar thrs parameters */
312	if (!version)
313		goto err;
314	radar_thr.version = atoi(version);
315	if (radar_thr.version > WL_RADAR_THR_VERSION)
316		goto err;
317
318	/* Retrieve ver 0 params */
319	if (!thr0_20_lo)
320		goto err;
321	radar_thr.thresh0_20_lo = (uint16)strtol(thr0_20_lo, &endptr, 0);
322	if (*endptr != '\0')
323		goto err;
324
325	if (!thr1_20_lo)
326		goto err;
327	radar_thr.thresh1_20_lo = (uint16)strtol(thr1_20_lo, &endptr, 0);
328	if (*endptr != '\0')
329		goto err;
330
331	if (!thr0_40_lo)
332		goto err;
333	radar_thr.thresh0_40_lo = (uint16)strtol(thr0_40_lo, &endptr, 0);
334	if (*endptr != '\0')
335		goto err;
336
337	if (!thr1_40_lo)
338		goto err;
339	radar_thr.thresh1_40_lo = (uint16)strtol(thr1_40_lo, &endptr, 0);
340	if (*endptr != '\0')
341		goto err;
342
343	if (radar_thr.version == 0) {
344		/*
345		 * Attempt a best effort update of ver 0 to ver 1 by updating
346		 * the appropriate values with the specified defaults.  The defaults
347		 * are from the reference design.
348		 */
349		radar_thr.version = WL_RADAR_THR_VERSION; /* avoid driver rejecting it */
350		radar_thr.thresh0_20_hi = 0x6ac;
351		radar_thr.thresh1_20_hi = 0x6cc;
352		radar_thr.thresh0_40_hi = 0x6bc;
353		radar_thr.thresh1_40_hi = 0x6e0;
354	} else {
355		/* Retrieve ver 1 params */
356		if (!thr0_20_hi)
357			goto err;
358		radar_thr.thresh0_20_hi = (uint16)strtol(thr0_20_hi, &endptr, 0);
359		if (*endptr != '\0')
360			goto err;
361
362		if (!thr1_20_hi)
363			goto err;
364		radar_thr.thresh1_20_hi = (uint16)strtol(thr1_20_hi, &endptr, 0);
365		if (*endptr != '\0')
366			goto err;
367
368		if (!thr0_40_hi)
369			goto err;
370		radar_thr.thresh0_40_hi = (uint16)strtol(thr0_40_hi, &endptr, 0);
371		if (*endptr != '\0')
372			goto err;
373
374		if (!thr1_40_hi)
375			goto err;
376		radar_thr.thresh1_40_hi = (uint16)strtol(thr1_40_hi, &endptr, 0);
377		if (*endptr != '\0')
378			goto err;
379	}
380
381	/* Copy radar parameters into buffer and plug them to the driver */
382	memcpy((char*)(buf + strlen(buf) + 1), (char*)&radar_thr, sizeof(wl_radar_thr_t));
383	WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
384
385	return;
386
387err:
388	WLCONF_DBG("Did not parse radar thrs params, using driver defaults\n");
389	return;
390}
391
392
393/* Set up WME */
394static void
395wlconf_set_wme(char *name, char *prefix)
396{
397	int i, j, k;
398	int val, ret;
399	int phytype, gmode, no_ack, apsd, dp[2];
400	edcf_acparam_t *acparams;
401	/* Pay attention to buffer length requirements when using this */
402	char buf[WLC_IOCTL_SMLEN];
403	char *v, *nv_value, nv[100];
404	char nv_name[] = "%swme_%s_%s";
405	char *ac[] = {"be", "bk", "vi", "vo"};
406	char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first;
407	char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced,
408	                    &oldest_first };
409	struct {char *req; char *str;} mode[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"},
410	                                         {"wme_tx_params", "txp"}};
411
412	/* query the phy type */
413	WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
414	/* get gmode */
415	gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", nv)));
416
417	/* WME sta setting first */
418	for (i = 0; i < 2; i++) {
419		/* build request block */
420		memset(buf, 0, sizeof(buf));
421		strcpy(buf, mode[i].req);
422		/* put push wmeac params after "wme-ac" in buf */
423		acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1);
424		dp[i] = 0;
425		for (j = 0; j < AC_COUNT; j++) {
426			/* get packed nvram parameter */
427			snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]);
428			nv_value = nvram_safe_get(nv);
429			strcpy(nv, nv_value);
430			/* unpack it */
431			v = nv;
432			for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
433				*locals[k] = v;
434				while (*v && *v != ' ')
435					v++;
436				if (*v) {
437					*v = 0;
438					v++;
439				}
440			}
441
442			/* update CWmin */
443			acparams->ECW &= ~EDCF_ECWMIN_MASK;
444			val = atoi(cwmin);
445			for (val++, k = 0; val; val >>= 1, k++);
446			acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK;
447			/* update CWmax */
448			acparams->ECW &= ~EDCF_ECWMAX_MASK;
449			val = atoi(cwmax);
450			for (val++, k = 0; val; val >>= 1, k++);
451			acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK;
452			/* update AIFSN */
453			acparams->ACI &= ~EDCF_AIFSN_MASK;
454			acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK;
455			/* update ac */
456			acparams->ACI &= ~EDCF_ACI_MASK;
457			acparams->ACI |= j << EDCF_ACI_SHIFT;
458			/* update TXOP */
459			if (phytype == PHY_TYPE_B || gmode == 0)
460				val = atoi(txop_b);
461			else
462				val = atoi(txop_ag);
463			acparams->TXOP = val / 32;
464			/* update acm */
465			acparams->ACI &= ~EDCF_ACM_MASK;
466			val = strcmp(admin_forced, "on") ? 0 : 1;
467			acparams->ACI |= val << 4;
468
469			/* configure driver */
470			WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
471		}
472	}
473
474	/* set no-ack */
475	v = nvram_safe_get(strcat_r(prefix, "wme_no_ack", nv));
476	no_ack = strcmp(v, "on") ? 0 : 1;
477	WL_IOVAR_SETINT(name, "wme_noack", no_ack);
478
479	/* set APSD */
480	v = nvram_safe_get(strcat_r(prefix, "wme_apsd", nv));
481	apsd = strcmp(v, "on") ? 0 : 1;
482	WL_IOVAR_SETINT(name, "wme_apsd", apsd);
483
484	/* set per-AC discard policy */
485	strcpy(buf, "wme_dp");
486	WL_IOVAR_SETINT(name, "wme_dp", dp[1]);
487
488	/* WME Tx parameters setting */
489	{
490		wme_tx_params_t txparams[AC_COUNT];
491		char *srl, *sfbl, *lrl, *lfbl, *maxrate;
492		char **locals[] = { &srl, &sfbl, &lrl, &lfbl, &maxrate };
493
494		/* build request block */
495		memset(txparams, 0, sizeof(txparams));
496
497		for (j = 0; j < AC_COUNT; j++) {
498			/* get packed nvram parameter */
499			snprintf(nv, sizeof(nv), nv_name, prefix, mode[2].str, ac[j]);
500			nv_value = nvram_safe_get(nv);
501			strcpy(nv, nv_value);
502			/* unpack it */
503			v = nv;
504			for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
505				*locals[k] = v;
506				while (*v && *v != ' ')
507					v++;
508				if (*v) {
509					*v = 0;
510					v++;
511				}
512			}
513
514			/* update short retry limit */
515			txparams[j].short_retry = atoi(srl);
516
517			/* update short fallback limit */
518			txparams[j].short_fallback = atoi(sfbl);
519
520			/* update long retry limit */
521			txparams[j].long_retry = atoi(lrl);
522
523			/* update long fallback limit */
524			txparams[j].long_fallback = atoi(lfbl);
525
526			/* update max rate */
527			txparams[j].max_rate = atoi(maxrate);
528		}
529
530		/* set the WME tx parameters */
531		WL_IOVAR_SET(name, mode[2].req, txparams, sizeof(txparams));
532	}
533
534	return;
535}
536
537#if defined(linux)
538#include <unistd.h>
539static void
540sleep_ms(const unsigned int ms)
541{
542	usleep(1000*ms);
543}
544#else
545#error "sleep_ms() not defined for this OS!!!"
546#endif /* defined(linux) */
547
548/*
549* The following condition(s) must be met when Auto Channel Selection
550* is enabled.
551*  - the I/F is up (change radio channel requires it is up?)
552*  - the AP must not be associated (setting SSID to empty should
553*    make sure it for us)
554*/
555static uint8
556wlconf_auto_channel(char *name)
557{
558	int chosen = 0;
559	wl_uint32_list_t request;
560	int phytype;
561	int ret;
562	int i;
563
564	/* query the phy type */
565	WL_GETINT(name, WLC_GET_PHYTYPE, &phytype);
566
567	request.count = 0;	/* let the ioctl decide */
568	WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
569	if (!ret) {
570		sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
571		for (i = 0; i < 100; i++) {
572			WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen);
573			if (!ret)
574				break;
575			sleep_ms(100);
576		}
577	}
578	WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
579	return chosen;
580}
581
582static chanspec_t
583wlconf_auto_chanspec(char *name)
584{
585	chanspec_t chosen = 0;
586	wl_uint32_list_t request;
587	int bandtype;
588	int ret;
589	int i;
590
591	/* query the band type */
592	WL_GETINT(name, WLC_GET_BAND, &bandtype);
593
594	request.count = 0;	/* let the ioctl decide */
595	WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
596	if (!ret) {
597		sleep_ms(1000);
598		for (i = 0; i < 100; i++) {
599			WL_IOVAR_GETINT(name, "apcschspec", (void *)&chosen);
600			if (!ret)
601				break;
602			sleep_ms(100);
603		}
604	}
605	WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen);
606	return chosen;
607}
608
609/* PHY type/BAND conversion */
610#define WLCONF_PHYTYPE2BAND(phy)	((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
611/* PHY type conversion */
612#define WLCONF_PHYTYPE2STR(phy)	((phy) == PHY_TYPE_A ? "a" : \
613				 (phy) == PHY_TYPE_B ? "b" : \
614				 (phy) == PHY_TYPE_LP ? "l" : \
615				 (phy) == PHY_TYPE_G ? "g" : "n")
616#define WLCONF_STR2PHYTYPE(phy)	((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
617				 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \
618				 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \
619				 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N)
620
621#define PREFIX_LEN 32			/* buffer size for wlXXX_ prefix */
622
623struct bsscfg_info {
624	int idx;			/* bsscfg index */
625	char ifname[PREFIX_LEN];	/* OS name of interface (debug only) */
626	char prefix[PREFIX_LEN];	/* prefix for nvram params (eg. "wl0.1_") */
627};
628
629struct bsscfg_list {
630	int count;
631	struct bsscfg_info bsscfgs[WL_MAXBSSCFG];
632};
633
634struct bsscfg_list *
635wlconf_get_bsscfgs(char* ifname, char* prefix)
636{
637	char var[80];
638	char tmp[100];
639	char *next;
640
641	struct bsscfg_list *bclist;
642	struct bsscfg_info *bsscfg;
643
644	bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list));
645	if (bclist == NULL)
646		return NULL;
647	memset(bclist, 0, sizeof(struct bsscfg_list));
648
649	/* Set up Primary BSS Config information */
650	bsscfg = &bclist->bsscfgs[0];
651	bsscfg->idx = 0;
652	strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1);
653	strcpy(bsscfg->prefix, prefix);
654	bclist->count = 1;
655
656	/* additional virtual BSS Configs from wlX_vifs */
657	foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) {
658		if (bclist->count == WL_MAXBSSCFG) {
659			WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
660			           "in nvram %s\n"
661			           "while configuring interface \"%s\"\n",
662			           ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var);
663			continue;
664		}
665		bsscfg = &bclist->bsscfgs[bclist->count];
666		if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) {
667			WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
668			           "name \"%s\"\n",
669			           ifname, var);
670			continue;
671		}
672		strncpy(bsscfg->ifname, var, PREFIX_LEN-1);
673		snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname);
674		bclist->count++;
675	}
676
677	return bclist;
678}
679
680static void
681wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool id_supp)
682{
683	int i;
684	int val;
685	int ret;
686	char tmp[100];
687
688	/* Set WSEC */
689	/*
690	* Need to check errors (card may have changed) and change to
691	* defaults since the new chip may not support the requested
692	* encryptions after the card has been changed.
693	*/
694	if (wlconf_set_wsec(name, prefix, bsscfg_idx)) {
695		/* change nvram only, code below will pass them on */
696		wlconf_restore_var(prefix, "auth_mode");
697		wlconf_restore_var(prefix, "auth");
698		/* reset wep to default */
699		wlconf_restore_var(prefix, "crypto");
700		wlconf_restore_var(prefix, "wep");
701		wlconf_set_wsec(name, prefix, bsscfg_idx);
702	}
703
704	val = wlconf_akm_options(prefix);
705	/* enable in-driver wpa supplicant? */
706	if (id_supp && (CHECK_PSK(val))) {
707		wsec_pmk_t psk;
708		char *key;
709
710		if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) &&
711		    (strlen(key) < WSEC_MAX_PSK_LEN)) {
712			psk.key_len = (ushort) strlen(key);
713			psk.flags = WSEC_PASSPHRASE;
714			strcpy((char *)psk.key, key);
715			WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
716		}
717		wl_iovar_setint(name, "sup_wpa", 1);
718	}
719	WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val);
720
721	/* EAP Restrict if we have an AKM or radius authentication */
722	val = ((val != 0) || (nvram_match(strcat_r(prefix, "auth_mode", tmp), "radius")));
723	WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val);
724
725	/* Set WEP keys */
726	if (nvram_match(strcat_r(prefix, "wep", tmp), "enabled")) {
727		for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++)
728			wlconf_set_wep_key(name, prefix, bsscfg_idx, i);
729	}
730
731	/* Set 802.11 authentication mode - open/shared */
732	val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp)));
733	WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val);
734}
735
736/*
737 * When N-mode is ON, afterburner is disabled and AMPDU, AMSDU are enabled/disabled
738 * based on the nvram setting. Only one of the AMPDU or AMSDU options is enabled any
739 * time. When N-mode is OFF or the device is non N-phy, AMPDU and AMSDU are turned off,
740 * afterburner is enabled/disabled based on the nvram settings.
741 *
742 * WME/WMM is also set in this procedure as it depends on N and afterburner.
743 *     N ==> WMM is on by default
744 *     N (or ampdu) ==> afterburner is off
745 *     WMM ==> afterburner is off
746 *
747 * Returns whether afterburner is on in the system.
748 */
749static int
750wlconf_aburn_ampdu_amsdu_set(char *name, char prefix[PREFIX_LEN], int nmode, int btc_mode)
751{
752	bool ampdu_valid_option = FALSE;
753	bool amsdu_valid_option = FALSE;
754	bool aburn_valid_option = FALSE;
755	int  val, aburn_option_val = OFF, ampdu_option_val = OFF, amsdu_option_val = OFF;
756	int wme_option_val = ON;  /* On by default */
757	char tmp[100], var[80], *next, *wme_val;
758	char buf[WLC_IOCTL_SMLEN];
759	int ret;
760
761	/* First, clear WMM and afterburner settings to avoid conflicts */
762	WL_IOVAR_SETINT(name, "wme", OFF);
763	WL_IOVAR_SETINT(name, "afterburner_override", OFF);
764
765	/* Get WME setting from NVRAM if present */
766	wme_val = nvram_get(strcat_r(prefix, "wme", tmp));
767	if (wme_val && !strcmp(wme_val, "off")) {
768		wme_option_val = OFF;
769	}
770
771	/* Set options based on capability */
772	wl_iovar_get(name, "cap", (void *)tmp, 100);
773	foreach(var, tmp, next) {
774		char *nvram_str = nvram_get(strcat_r(prefix, var, buf));
775
776		if (!nvram_str)
777			continue;
778
779		if (!strcmp(nvram_str, "on"))
780			val = ON;
781		else if (!strcmp(nvram_str, "off"))
782			val = OFF;
783		else if (!strcmp(nvram_str, "auto"))
784			val = AUTO;
785		else
786			continue;
787
788		if (btc_mode != WL_BTC_PREMPT && strncmp(var, "afterburner", sizeof(var)) == 0) {
789			aburn_valid_option = TRUE;
790			aburn_option_val = val;
791		}
792
793		if (strncmp(var, "ampdu", sizeof(var)) == 0) {
794			ampdu_valid_option = TRUE;
795			ampdu_option_val = val;
796		}
797
798		if (strncmp(var, "amsdu", sizeof(var)) == 0) {
799			amsdu_valid_option = TRUE;
800			amsdu_option_val = val;
801		}
802	}
803
804	if (nmode != OFF) { /* N-mode is ON/AUTO */
805
806		if (aburn_valid_option) { /* Turn off afterburner in N-mode */
807			WL_IOVAR_SETINT(name, "afterburner_override", OFF);
808		}
809
810		if (ampdu_valid_option) {
811			if (ampdu_option_val != OFF) {
812				WL_IOVAR_SETINT(name, "amsdu", OFF);
813				WL_IOVAR_SETINT(name, "ampdu", ampdu_option_val);
814			} else {
815				WL_IOVAR_SETINT(name, "ampdu", OFF);
816			}
817		}
818
819		if (amsdu_valid_option) {
820			if (amsdu_option_val != OFF) { /* AMPDU (above) has priority over AMSDU */
821				if (ampdu_option_val == OFF) {
822					WL_IOVAR_SETINT(name, "ampdu", OFF);
823					WL_IOVAR_SETINT(name, "amsdu", amsdu_option_val);
824				}
825			} else
826				WL_IOVAR_SETINT(name, "amsdu", OFF);
827		}
828	} else {
829		/* When N-mode is off or for non N-phy device, turn off AMPDU, AMSDU;
830		 * if WME is off, set the afterburner based on the configured nvram setting.
831		 */
832		wl_iovar_setint(name, "amsdu", OFF);
833		wl_iovar_setint(name, "ampdu", OFF);
834		if (wme_option_val != OFF) { /* Can't have afterburner with WMM */
835			if (aburn_valid_option) {
836				WL_IOVAR_SETINT(name, "afterburner_override", OFF);
837			}
838		} else if (aburn_valid_option) { /* Okay, use NVRam setting for afterburner */
839			WL_IOVAR_SETINT(name, "afterburner_override", aburn_option_val);
840		}
841	}
842
843	if (wme_option_val) {
844		WL_IOVAR_SETINT(name, "wme", wme_option_val);
845		wlconf_set_wme(name, prefix);
846	}
847
848	return wme_option_val;
849}
850
851#define VIFNAME_LEN 16
852
853/* configure the specified wireless interface */
854int
855wlconf(char *name)
856{
857	int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0;
858	int bcmerr;
859	int error_bg, error_a;
860	struct bsscfg_list *bclist = NULL;
861	struct bsscfg_info *bsscfg;
862	char tmp[100], prefix[PREFIX_LEN];
863	char var[80], *next, phy[] = "a", *str, *addr = NULL;
864	/* Pay attention to buffer length requirements when using this */
865	char buf[WLC_IOCTL_SMLEN];
866	char *country;
867	wlc_rev_info_t rev;
868	channel_info_t ci;
869	struct maclist *maclist;
870	struct ether_addr *ea;
871	wlc_ssid_t ssid;
872	wl_rateset_t rs;
873	unsigned int i;
874	char eaddr[32];
875	int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0;
876	char country_code[4];
877	int nas_will_run = 0;
878	char *ba;
879#ifdef BCMWPA2
880	char *preauth;
881	int set_preauth;
882#endif
883	int ii;
884	int wlunit = -1;
885	int wlsubunit = -1;
886	int wl_ap_build = 0; /* wl compiled with AP capabilities */
887	char cap[WLC_IOCTL_SMLEN];
888	char caps[WLC_IOCTL_SMLEN];
889	int btc_mode;
890	uint32 leddc;
891	uint nbw = WL_CHANSPEC_BW_20;
892	int nmode = OFF; /* 802.11n support */
893	char vif_addr[WLC_IOCTL_SMLEN];
894	int max_no_vifs = 0;
895	int wme_global;
896	int max_assoc = -1;
897	bool ure_enab = FALSE;
898	bool radar_enab = FALSE;
899
900	/* wlconf doesn't work for virtual i/f, so if we are given a
901	 * virtual i/f return 0 if that interface is in it's parent's "vifs"
902	 * list otherwise return -1
903	 */
904	if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0)
905	{
906		if (wlsubunit >= 0)
907		{
908			/* we have been given a virtual i/f,
909			 * is it in it's parent i/f's virtual i/f list?
910			 */
911			sprintf(tmp, "wl%d_vifs", wlunit);
912
913			if (strstr(nvram_safe_get(tmp), name) == NULL)
914				return -1; /* config error */
915			else
916				return 0; /* okay */
917		}
918	}
919	else
920	{
921		return -1;
922	}
923
924	/* clean up tmp */
925	memset(tmp, 0, sizeof(tmp));
926
927	/* because of ifdefs in wl driver,  when we don't have AP capabilities we
928	 * can't use the same iovars to configure the wl.
929	 * so we use "wl_ap_build" to help us know how to configure the driver
930	 */
931	if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
932		return -1;
933
934	foreach(cap, caps, next) {
935		if (!strcmp(cap, "ap")) {
936			wl_ap_build = 1;
937		}
938		else if (!strcmp(cap, "mbss16"))
939			max_no_vifs = 16;
940		else if (!strcmp(cap, "mbss4"))
941			max_no_vifs = 4;
942	}
943
944	/* Check interface (fail silently for non-wl interfaces) */
945	if ((ret = wl_probe(name)))
946		return ret;
947
948	/* Get MAC address */
949	(void) wl_hwaddr(name, (uchar *)buf);
950	memcpy(vif_addr, buf, ETHER_ADDR_LEN);
951
952	/* Get instance */
953	WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit));
954	snprintf(prefix, sizeof(prefix), "wl%d_", unit);
955
956	/* Restore defaults if per-interface parameters do not exist */
957	restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
958	wlconf_validate_all(prefix, restore_defaults);
959	nvram_set(strcat_r(prefix, "ifname", tmp), name);
960	nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr));
961	snprintf(buf, sizeof(buf), "%d", unit);
962	nvram_set(strcat_r(prefix, "unit", tmp), buf);
963
964
965	/* Bring the interface down */
966	WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
967
968	/* Disable all BSS Configs */
969	for (i = 0; i < WL_MAXBSSCFG; i++) {
970		struct {int bsscfg_idx; int enable;} setbuf;
971		setbuf.bsscfg_idx = i;
972		setbuf.enable = 0;
973
974		ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
975		if (ret) {
976			wl_iovar_getint(name, "bcmerror", &bcmerr);
977			/* fail quietly on a range error since the driver may
978			 * support fewer bsscfgs than we are prepared to configure
979			 */
980			if (bcmerr == BCME_RANGE)
981				break;
982		}
983		if (ret)
984			WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
985			           " (down) failed, ret = %d, bcmerr = %d\n",
986			           __LINE__, name, i, ret, bcmerr);
987	}
988
989	/* Get the list of BSS Configs */
990	bclist = wlconf_get_bsscfgs(name, prefix);
991	if (bclist == NULL) {
992		ret = -1;
993		goto exit;
994	}
995
996
997	/* create a wlX.Y_ifname nvram setting */
998	for (i = 1; i < bclist->count; i++) {
999		bsscfg = &bclist->bsscfgs[i];
1000#if defined(linux)
1001		strcpy(var, bsscfg->ifname);
1002#endif
1003		nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var);
1004	}
1005
1006	/* If ure_disable is not present or is 1, ure is not enabled;
1007	 * that is, if it is present and 0, ure is enabled.
1008	 */
1009	if (!strcmp(nvram_safe_get("ure_disable"), "0")) { /* URE is enabled */
1010		ure_enab = TRUE;
1011	}
1012	if (wl_ap_build) {
1013		/* Enable MBSS mode if appropriate */
1014		if (!ure_enab) {
1015			WL_IOVAR_SETINT(name, "mbss", (bclist->count > 1));
1016		}
1017
1018		/*
1019		 * Set SSID for each BSS Config
1020		 */
1021		for (i = 0; i < bclist->count; i++) {
1022			bsscfg = &bclist->bsscfgs[i];
1023			strcat_r(bsscfg->prefix, "ssid", tmp);
1024			ssid.SSID_len = strlen(nvram_safe_get(tmp));
1025			if (ssid.SSID_len > sizeof(ssid.SSID))
1026				ssid.SSID_len = sizeof(ssid.SSID);
1027			strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len);
1028			WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) "
1029			           "with SSID \"%s\"\n", name, bsscfg->idx,
1030			           bsscfg->ifname, nvram_safe_get(tmp));
1031			WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid,
1032			                sizeof(ssid));
1033		}
1034	}
1035
1036	/* Create addresses for VIFs */
1037	if (!ure_enab) {
1038		/* set local bit for our MBSS vif base */
1039		ETHER_SET_LOCALADDR(vif_addr);
1040
1041		/* construct and set other wlX.Y_hwaddr */
1042		for (i = 1; i < max_no_vifs; i++) {
1043			snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i);
1044			addr = nvram_safe_get(tmp);
1045			if (!strcmp(addr, "")) {
1046				vif_addr[5] = (vif_addr[5] & ~(max_no_vifs-1))
1047				        | ((max_no_vifs-1) & (vif_addr[5]+1));
1048
1049				nvram_set(tmp, ether_etoa((uchar *)vif_addr,
1050				                          eaddr));
1051			}
1052		}
1053		/* The addresses are available in NVRAM, so set them */
1054		for (i = 1; i < max_no_vifs; i++) {
1055			snprintf(tmp, sizeof(tmp), "wl%d.%d_bss_enabled",
1056			         unit, i);
1057			if (!strcmp(nvram_safe_get(tmp), "1")) {
1058				snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr",
1059				         unit, i);
1060				ether_atoe(nvram_safe_get(tmp), eaddr);
1061				WL_BSSIOVAR_SET(name, "cur_etheraddr", i,
1062				                eaddr, ETHER_ADDR_LEN);
1063			}
1064		}
1065	} else { /* URE is enabled */
1066		/* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
1067		snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit);
1068		WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr,
1069		                ETHER_ADDR_LEN);
1070		nvram_set(tmp, ether_etoa((uchar *)vif_addr, eaddr));
1071	}
1072
1073	/* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
1074	str = nvram_safe_get(strcat_r(prefix, "mode", tmp));
1075	ap = (!strcmp(str, "") || !strcmp(str, "ap"));
1076	apsta = (!strcmp(str, "apsta") ||
1077	         ((!strcmp(str, "sta") || !strcmp(str, "wet")) &&
1078	          bclist->count > 1));
1079	sta = (!strcmp(str, "sta") && bclist->count == 1);
1080	wds = !strcmp(str, "wds");
1081	wet = !strcmp(str, "wet");
1082	mac_spoof = !strcmp(str, "mac_spoof");
1083
1084	/* Set AP mode */
1085	val = (ap || apsta || wds) ? 1 : 0;
1086	WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val));
1087
1088	WL_IOVAR_SETINT(name, "apsta", apsta);
1089
1090	/* Set mode: WET */
1091	if (wet)
1092		WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet));
1093
1094	if (mac_spoof) {
1095		sta = 1;
1096		WL_IOVAR_SETINT(name, "mac_spoof", 1);
1097	}
1098
1099	/* For STA configurations, configure association retry time.
1100	 * Use specified time (capped), or mode-specific defaults.
1101	 */
1102	if (sta || wet || apsta) {
1103		char *retry_time = nvram_safe_get(strcat_r(prefix, "sta_retry_time", tmp));
1104		val = atoi(retry_time);
1105		WL_IOVAR_SETINT(name, "sta_retry_time", val);
1106	}
1107
1108	/* Retain remaining WET effects only if not APSTA */
1109	wet &= !apsta;
1110
1111	/* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
1112	val = 1;
1113	if (wet || sta)
1114		val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp)));
1115	WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val));
1116
1117	/* Set The AP MAX Associations Limit */
1118	if (ap | apsta) {
1119		max_assoc = val = atoi(nvram_safe_get(strcat_r(prefix, "maxassoc", tmp)));
1120		if (val > 0) {
1121			WL_IOVAR_SETINT(name, "maxassoc", val);
1122		} else { /* Get value from driver if not in nvram */
1123			WL_IOVAR_GETINT(name, "maxassoc", &max_assoc);
1124		}
1125	}
1126
1127	for (i = 0; i < bclist->count; i++) {
1128		char *subprefix;
1129		bsscfg = &bclist->bsscfgs[i];
1130
1131#ifdef BCMWPA2
1132		/* XXXMBSS: The note about setting preauth now does not seem right.
1133		 * NAS brings the BSS up if it runs, so setting the preauth value
1134		 * will make it in the bcn/prb. If that is right, we can move this
1135		 * chunk out of wlconf.
1136		 */
1137		/*
1138		 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
1139		 * if we do it in the NAS we need to bring down the interface and up to make
1140		 * it affect in the  beacons
1141		 */
1142		if (ap || (apsta && bsscfg->idx != 0)) {
1143			set_preauth = 1;
1144			preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp));
1145			if (strlen (preauth) != 0) {
1146				set_preauth = atoi(preauth);
1147			}
1148			wlconf_set_preauth(name, bsscfg->idx, set_preauth);
1149		}
1150#endif /* BCMWPA2 */
1151
1152		subprefix = apsta ? prefix : bsscfg->prefix;
1153
1154		if (ap || (apsta && bsscfg->idx != 0)) {
1155			val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "bss_maxassoc", tmp)));
1156			if (val > 0) {
1157				WL_BSSIOVAR_SETINT(name, "bss_maxassoc", bsscfg->idx, val);
1158			} else if (max_assoc > 0) { /* Set maxassoc same as global if not set */
1159				snprintf(var, sizeof(var), "%d", max_assoc);
1160				nvram_set(tmp, var);
1161			}
1162		}
1163
1164		/* Set network type */
1165		val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "closed", tmp)));
1166		WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val);
1167
1168		/* Set the ap isolate mode */
1169		val = atoi(nvram_safe_get(strcat_r(bsscfg->prefix, "ap_isolate", tmp)));
1170		WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val);
1171	}
1172
1173	/* Set up the country code */
1174	(void) strcat_r(prefix, "country_code", tmp);
1175	country = nvram_get(tmp);
1176	if (country && country[0] != '\0') {
1177		strncpy(country_code, country, sizeof(country_code));
1178		WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
1179	} else {
1180		/* Get the default country code if undefined */
1181		WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code));
1182
1183		/* Add the new NVRAM variable */
1184		nvram_set("wl_country_code", country_code);
1185		(void) strcat_r(prefix, "country_code", tmp);
1186		nvram_set(tmp, country_code);
1187	}
1188
1189	/* Change LED Duty Cycle */
1190	leddc = (uint32)strtoul(nvram_safe_get(strcat_r(prefix, "leddc", tmp)), NULL, 16);
1191	if (leddc)
1192		WL_IOVAR_SETINT(name, "leddc", leddc);
1193
1194	/* Enable or disable the radio */
1195	val = nvram_match(strcat_r(prefix, "radio", tmp), "0");
1196	val += WL_RADIO_SW_DISABLE << 16;
1197	WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
1198
1199	/* Get supported phy types */
1200	WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var));
1201	nvram_set(strcat_r(prefix, "phytypes", tmp), var);
1202
1203	/* Get radio IDs */
1204	*(next = buf) = '\0';
1205	for (i = 0; i < strlen(var); i++) {
1206		/* Switch to band */
1207		phy[0] = var[i];
1208		val = WLCONF_STR2PHYTYPE(phy);
1209		if (val == PHY_TYPE_N) {
1210			WL_GETINT(name, WLC_GET_BAND, &val);
1211		} else
1212			val = WLCONF_PHYTYPE2BAND(val);
1213		WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
1214		/* Get radio ID on this band */
1215		WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1216		next += sprintf(next, "%sBCM%X", i ? " " : "",
1217		                (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT);
1218	}
1219	nvram_set(strcat_r(prefix, "radioids", tmp), buf);
1220
1221	/* Set band */
1222	str = nvram_get(strcat_r(prefix, "phytype", tmp));
1223	val = WLCONF_STR2PHYTYPE(str);
1224	/* For NPHY use band value from NVRAM */
1225	if (val == PHY_TYPE_N) {
1226		str = nvram_get(strcat_r(prefix, "nband", tmp));
1227		if (str)
1228			val = atoi(str);
1229		else {
1230			WL_GETINT(name, WLC_GET_BAND, &val);
1231		}
1232	} else
1233		val = WLCONF_PHYTYPE2BAND(val);
1234
1235	WL_SETINT(name, WLC_SET_BAND, val);
1236
1237	/* Check errors (card may have changed) */
1238	if (ret) {
1239		/* default band to the first band in band list */
1240		phy[0] = var[0];
1241		val = WLCONF_STR2PHYTYPE(phy);
1242		val = WLCONF_PHYTYPE2BAND(val);
1243		WL_SETINT(name, WLC_SET_BAND, val);
1244	}
1245
1246	/* Store the resolved bandtype */
1247	bandtype = val;
1248
1249	/* Get current core revision */
1250	WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1251	snprintf(buf, sizeof(buf), "%d", rev.corerev);
1252	nvram_set(strcat_r(prefix, "corerev", tmp), buf);
1253
1254	/* Get current phy type */
1255	WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
1256	snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype));
1257	nvram_set(strcat_r(prefix, "phytype", tmp), buf);
1258
1259	/* Setup regulatory mode */
1260	strcat_r(prefix, "reg_mode", tmp);
1261	if (nvram_match(tmp, "off"))  {
1262		val = 0;
1263		WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1264		WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1265		WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1266	} else if (nvram_match(tmp, "h")) {
1267		val = 0;
1268		WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1269		val = 1;
1270		WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1271		radar_enab = TRUE;
1272		WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1273
1274		/* Set the CAC parameters */
1275		val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_preism", tmp)));
1276		wl_iovar_setint(name, "dfs_preism", val);
1277		val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_postism", tmp)));
1278		wl_iovar_setint(name, "dfs_postism", val);
1279		val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp)));
1280		WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val));
1281
1282	} else if (nvram_match(tmp, "d")) {
1283		val = 0;
1284		WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
1285		WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
1286		val = 1;
1287		WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
1288	}
1289
1290	/* set bandwidth capability for nphy and calculate nbw */
1291	if (phytype == PHY_TYPE_N) {
1292		/* Get the user nmode setting now */
1293		nmode = AUTO;	/* enable by default for NPHY */
1294		/* Set n mode */
1295		strcat_r(prefix, "nmode", tmp);
1296		if (nvram_match(tmp, "0"))
1297			nmode = OFF;
1298
1299		val = (nmode != OFF) ? atoi(nvram_safe_get(strcat_r(prefix, "nbw_cap", tmp))) :
1300		    WLC_N_BW_20ALL;
1301
1302		WL_IOVAR_SETINT(name, "nmode", (uint32)nmode);
1303		WL_IOVAR_SETINT(name, "mimo_bw_cap", val);
1304
1305		if (((bandtype == WLC_BAND_2G) && (val == WLC_N_BW_40ALL)) ||
1306		    ((bandtype == WLC_BAND_5G) &&
1307		     (val == WLC_N_BW_40ALL || val == WLC_N_BW_20IN2G_40IN5G)))
1308			nbw = WL_CHANSPEC_BW_40;
1309		else
1310			nbw = WL_CHANSPEC_BW_20;
1311	}
1312
1313	/* Set channel before setting gmode or rateset */
1314	/* Manual Channel Selection - when channel # is not 0 */
1315	val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp)));
1316	if (val && phytype != PHY_TYPE_N) {
1317		WL_SETINT(name, WLC_SET_CHANNEL, val);
1318		if (ret) {
1319			/* Use current channel (card may have changed) */
1320			WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
1321			snprintf(buf, sizeof(buf), "%d", ci.target_channel);
1322			nvram_set(strcat_r(prefix, "channel", tmp), buf);
1323		}
1324	} else if (val && phytype == PHY_TYPE_N) {
1325		chanspec_t chanspec = 0;
1326		uint channel;
1327		uint nctrlsb = WL_CHANSPEC_CTL_SB_NONE;
1328
1329		channel = val;
1330
1331		/* Get Ctrl SB for 40MHz channel */
1332		if (nbw == WL_CHANSPEC_BW_40) {
1333			str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp));
1334
1335			/* Adjust the channel to be center channel */
1336			if (!strcmp(str, "lower")) {
1337				nctrlsb = WL_CHANSPEC_CTL_SB_LOWER;
1338				channel = channel + 2;
1339			} else if (!strcmp(str, "upper")) {
1340				nctrlsb = WL_CHANSPEC_CTL_SB_UPPER;
1341				channel = channel - 2;
1342			}
1343		}
1344
1345		/* band | BW | CTRL SB | Channel */
1346		chanspec |= ((bandtype << WL_CHANSPEC_BAND_SHIFT) |
1347		             (nbw | nctrlsb | channel));
1348
1349		WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec);
1350	}
1351
1352	/* Set up number of Tx and Rx streams */
1353	if (phytype == PHY_TYPE_N) {
1354		int count;
1355		int streams;
1356
1357		wl_iovar_getint(name, "txchain_cnt", &count);
1358		/* update NVRAM with capabilities */
1359		snprintf(var, sizeof(var), "%d", count);
1360		nvram_set(strcat_r(prefix, "txchain_cnt", tmp), var);
1361
1362		/* Verify that there is an NVRAM param for txstreams, if not create it and
1363		 * set it to txchain_cnt
1364		 */
1365		streams = atoi(nvram_safe_get(strcat_r(prefix, "txstreams", tmp)));
1366		if (streams == 0) {
1367			/* invalid - NVRAM needs to be fixed/initialized */
1368			nvram_set(strcat_r(prefix, "txstreams", tmp), var);
1369			streams = count;
1370		}
1371		/* Apply user configured txstreams, use 1 if user disabled nmode */
1372		if (nmode == OFF)
1373			streams = 1;
1374		WL_IOVAR_SETINT(name, "txstreams", streams);
1375
1376		wl_iovar_getint(name, "rxchain_cnt", &count);
1377		/* update NVRAM with capabilities */
1378		snprintf(var, sizeof(var), "%d", count);
1379		nvram_set(strcat_r(prefix, "rxchain_cnt", tmp), var);
1380
1381		/* Verify that there is an NVRAM param for rxstreams, if not create it and
1382		 * set it to txchain_cnt
1383		 */
1384		streams = atoi(nvram_safe_get(strcat_r(prefix, "rxstreams", tmp)));
1385		if (streams == 0) {
1386			/* invalid - NVRAM needs to be fixed/initialized */
1387			nvram_set(strcat_r(prefix, "rxstreams", tmp), var);
1388			streams = count;
1389		}
1390
1391		/* Apply user configured rxstreams, use 1 if user disabled nmode */
1392		if (nmode == OFF)
1393			streams = 1;
1394		WL_IOVAR_SETINT(name, "rxstreams", streams);
1395	}
1396
1397	/* Reset to hardware rateset (band may have changed) */
1398	WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t));
1399	WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1400
1401	/* Set gmode */
1402	if (bandtype == WLC_BAND_2G) {
1403		int override = WLC_G_PROTECTION_OFF;
1404		int control = WLC_G_PROTECTION_CTL_OFF;
1405
1406		/* Set gmode */
1407		gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp)));
1408		WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode));
1409
1410		/* Set gmode protection override and control algorithm */
1411		strcat_r(prefix, "gmode_protection", tmp);
1412		if (nvram_match(tmp, "auto")) {
1413			override = WLC_G_PROTECTION_AUTO;
1414			control = WLC_G_PROTECTION_CTL_OVERLAP;
1415		}
1416		WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override));
1417		WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control));
1418	}
1419
1420	/* Set nmode_protection */
1421	if (phytype == PHY_TYPE_N) {
1422		int override = WLC_PROTECTION_OFF;
1423		int control = WLC_PROTECTION_CTL_OFF;
1424
1425		/* Set n protection override and control algorithm */
1426		strcat_r(prefix, "nmode_protection", tmp);
1427
1428		if (nvram_match(tmp, "auto")) {
1429			override = WLC_PROTECTION_AUTO;
1430			control = WLC_PROTECTION_CTL_OVERLAP;
1431		}
1432
1433		WL_IOVAR_SETINT(name, "nmode_protection_override",
1434		                (uint32)override);
1435		WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control));
1436	}
1437
1438	/* Set 802.11n required */
1439	if (nmode != OFF) {
1440		uint32 nreqd = OFF; /* default */
1441
1442		strcat_r(prefix, "nreqd", tmp);
1443
1444		if (nvram_match(tmp, "1"))
1445			nreqd = ON;
1446
1447		WL_IOVAR_SETINT(name, "nreqd", nreqd);
1448	}
1449
1450	/* Set vlan_prio_mode */
1451	{
1452		uint32 mode = OFF; /* default */
1453
1454		strcat_r(prefix, "vlan_prio_mode", tmp);
1455
1456		if (nvram_match(tmp, "on"))
1457			mode = ON;
1458
1459		WL_IOVAR_SETINT(name, "vlan_mode", mode);
1460	}
1461
1462	/* Get bluetooth coexistance(BTC) mode */
1463	btc_mode = atoi(nvram_safe_get(strcat_r(prefix, "btc_mode", tmp)));
1464
1465	/* Set the afterburner, AMPDU and AMSDU options based on the N-mode */
1466	wme_global = wlconf_aburn_ampdu_amsdu_set(name, prefix, nmode, btc_mode);
1467
1468	/* Now that wme_global is known, check per-BSS disable settings */
1469	for (i = 0; i < bclist->count; i++) {
1470		char *subprefix;
1471		bsscfg = &bclist->bsscfgs[i];
1472
1473		subprefix = apsta ? prefix : bsscfg->prefix;
1474
1475		/* For each BSS, check WME; make sure wme is set properly for this interface */
1476		strcat_r(subprefix, "wme", tmp);
1477		nvram_set(tmp, wme_global ? "on" : "off");
1478
1479		str = nvram_safe_get(strcat_r(bsscfg->prefix, "wme_bss_disable", tmp));
1480		val = (str[0] == '1') ? 1 : 0;
1481		WL_BSSIOVAR_SETINT(name, "wme_bss_disable", bsscfg->idx, val);
1482	}
1483
1484
1485	/* Get current rateset (gmode may have changed) */
1486	WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof(wl_rateset_t));
1487
1488	strcat_r(prefix, "rateset", tmp);
1489	if (nvram_match(tmp, "all"))  {
1490		/* Make all rates basic */
1491		for (i = 0; i < rs.count; i++)
1492			rs.rates[i] |= 0x80;
1493	} else if (nvram_match(tmp, "12")) {
1494		/* Make 1 and 2 basic */
1495		for (i = 0; i < rs.count; i++) {
1496			if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4)
1497				rs.rates[i] |= 0x80;
1498			else
1499				rs.rates[i] &= ~0x80;
1500		}
1501	}
1502
1503	/* Set BTC mode */
1504	if (!wl_iovar_setint(name, "btc_mode", btc_mode)) {
1505		if (btc_mode == WL_BTC_PREMPT) {
1506			wl_rateset_t rs_tmp = rs;
1507			/* remove 1Mbps and 2 Mbps from rateset */
1508			for (i = 0, rs.count = 0; i < rs_tmp.count; i++) {
1509				if ((rs_tmp.rates[i] & 0x7f) == 2 || (rs_tmp.rates[i] & 0x7f) == 4)
1510					continue;
1511				rs.rates[rs.count++] = rs_tmp.rates[i];
1512			}
1513		}
1514	}
1515
1516	/* Set rateset */
1517	WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1518
1519	/* Allow short preamble override for b cards */
1520	if (phytype == PHY_TYPE_B ||
1521	    (phytype == PHY_TYPE_G && (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) {
1522		strcat_r(prefix, "plcphdr", tmp);
1523		if (nvram_match(tmp, "long"))
1524			val = WLC_PLCP_AUTO;
1525		else
1526			val = WLC_PLCP_SHORT;
1527		WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val));
1528	}
1529
1530	/* Set rate in 500 Kbps units */
1531	val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000;
1532
1533	/* Convert Auto mcsidx to Auto rate */
1534	if (phytype == PHY_TYPE_N) {
1535		int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1536
1537		/* -1 mcsidx used to designate AUTO rate */
1538		if (mcsidx == -1)
1539			val = 0;
1540	}
1541
1542	/* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1543	if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1544		/* Must b/g band.  Set to 5.5Mbps */
1545		val = 11;
1546
1547	/* it is band-blind. try both band */
1548	error_bg = wl_iovar_setint(name, "bg_rate", val);
1549	error_a = wl_iovar_setint(name, "a_rate", val);
1550
1551	if (error_bg && error_a) {
1552		/* both failed. Try default rate (card may have changed) */
1553		val = 0;
1554
1555		error_bg = wl_iovar_setint(name, "bg_rate", val);
1556		error_a = wl_iovar_setint(name, "a_rate", val);
1557
1558		snprintf(buf, sizeof(buf), "%d", val);
1559		nvram_set(strcat_r(prefix, "rate", tmp), buf);
1560	}
1561
1562	/* check if nrate needs to be applied */
1563	if (nmode != OFF) {
1564		uint32 nrate = 0;
1565		int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1566		bool ismcs = (mcsidx >= 0);
1567
1568		/* mcsidx of 32 is valid only for 40 Mhz */
1569		if (mcsidx == 32 && nbw == WL_CHANSPEC_BW_20) {
1570			mcsidx =  -1;
1571			ismcs = FALSE;
1572			nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1");
1573		}
1574
1575		/* Use nrate iovar only for MCS rate. */
1576		if (ismcs) {
1577			nrate |= NRATE_MCS_INUSE;
1578			nrate |= mcsidx & NRATE_RATE_MASK;
1579
1580			WL_IOVAR_SETINT(name, "nrate", nrate);
1581		}
1582	}
1583
1584	/* Set multicast rate in 500 Kbps units */
1585	val = atoi(nvram_safe_get(strcat_r(prefix, "mrate", tmp))) / 500000;
1586	/* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1587	if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1588		/* Must b/g band.  Set to 5.5Mbps */
1589		val = 11;
1590
1591	/* it is band-blind. try both band */
1592	error_bg = wl_iovar_setint(name, "bg_mrate", val);
1593	error_a = wl_iovar_setint(name, "a_mrate", val);
1594
1595	if (error_bg && error_a) {
1596		/* Try default rate (card may have changed) */
1597		val = 0;
1598
1599		wl_iovar_setint(name, "bg_mrate", val);
1600		wl_iovar_setint(name, "a_mrate", val);
1601
1602		snprintf(buf, sizeof(buf), "%d", val);
1603		nvram_set(strcat_r(prefix, "mrate", tmp), buf);
1604	}
1605
1606	/* Set fragmentation threshold */
1607	val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp)));
1608	wl_iovar_setint(name, "fragthresh", val);
1609
1610	/* Set RTS threshold */
1611	val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp)));
1612	wl_iovar_setint(name, "rtsthresh", val);
1613
1614	/* Set DTIM period */
1615	val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp)));
1616	WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val));
1617
1618	/* Set beacon period */
1619	val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp)));
1620	WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val));
1621
1622	/* Set framebursting mode */
1623	if (btc_mode == WL_BTC_PREMPT)
1624		val = FALSE;
1625	else
1626		val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on");
1627	WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val));
1628
1629	/* Set RIFS mode based on framebursting */
1630	if (phytype == PHY_TYPE_N) {
1631		char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp));
1632		if (!strcmp(nvram_str, "on"))
1633			wl_iovar_setint(name, "rifs", ON);
1634		else if (!strcmp(nvram_str, "off"))
1635			wl_iovar_setint(name, "rifs", OFF);
1636	}
1637
1638	/* Override BA mode only if set to on/off */
1639	ba = nvram_safe_get(strcat_r(prefix, "ba", tmp));
1640	if (!strcmp(ba, "on"))
1641		wl_iovar_setint(name, "ba", ON);
1642	else if (!strcmp(ba, "off"))
1643		wl_iovar_setint(name, "ba", OFF);
1644
1645	if (phytype == PHY_TYPE_N) {
1646		val = AVG_DMA_XFER_RATE;
1647		wl_iovar_set(name, "avg_dma_xfer_rate", &val, sizeof(val));
1648	}
1649
1650	/* Bring the interface back up */
1651	WL_IOCTL(name, WLC_UP, NULL, 0);
1652
1653	/* Set antenna */
1654	val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp)));
1655	WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val));
1656
1657	/* Set radar parameters if it is enabled */
1658	if (radar_enab) {
1659		wlconf_set_radarthrs(name, prefix);
1660	}
1661
1662	/* Auto Channel Selection - when channel # is 0 in AP mode
1663	 *
1664	 * The following condition(s) must be met in order for
1665	 * Auto Channel Selection to work.
1666	 *  - the I/F must be up for the channel scan
1667	 *  - the AP must not be supporting a BSS (all BSS Configs must be disabled)
1668	 */
1669	if (ap || apsta) {
1670		if (!(val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))))) {
1671			if (phytype == PHY_TYPE_N) {
1672				chanspec_t chanspec = wlconf_auto_chanspec(name);
1673				if (chanspec != 0)
1674					WL_IOVAR_SETINT(name, "chanspec", chanspec);
1675			}
1676			else {
1677				/* select a channel */
1678				val = wlconf_auto_channel(name);
1679				/* switch to the selected channel */
1680				if (val != 0)
1681					WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
1682			}
1683			/* set the auto channel scan timer in the driver when in auto mode */
1684			val = 15;	/* 15 minutes for now */
1685			WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1686		}
1687		else {
1688			/* reset the channel scan timer in the driver when not in auto mode */
1689			val = 0;
1690			WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1691		}
1692	}
1693
1694	/* Security settings for each BSS Configuration */
1695	for (i = 0; i < bclist->count; i++) {
1696		bsscfg = &bclist->bsscfgs[i];
1697		wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, mac_spoof);
1698	}
1699
1700	/* AP only config */
1701	if (ap || apsta || wds) {
1702		/* Set lazy WDS mode */
1703		val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp)));
1704		WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val));
1705
1706		/* Set the WDS list */
1707		maclist = (struct maclist *) buf;
1708		maclist->count = 0;
1709		ea = maclist->ea;
1710		foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
1711			if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)])))
1712				break;
1713			ether_atoe(var, ea->octet);
1714			maclist->count++;
1715			ea++;
1716		}
1717		WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
1718
1719		/* Set WDS link detection timeout */
1720		val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp)));
1721		wl_iovar_setint(name, "wdstimeout", val);
1722
1723		if (wds) {
1724			wl_iovar_setint(name, "radio_init", 1);
1725		}
1726	}
1727
1728	/*
1729	 * Finally enable BSS Configs or Join BSS
1730	 *
1731	 * AP: Enable BSS Config to bring AP up only when nas will not run
1732	 * STA: Join the BSS regardless.
1733	 */
1734	for (i = 0; i < bclist->count; i++) {
1735		struct {int bsscfg_idx; int enable;} setbuf;
1736		char vifname[VIFNAME_LEN];
1737		char *name_ptr = name;
1738
1739		setbuf.bsscfg_idx = bclist->bsscfgs[i].idx;
1740		setbuf.enable = 0;
1741
1742		bsscfg = &bclist->bsscfgs[i];
1743		if (nvram_match(strcat_r(bsscfg->prefix, "bss_enabled", tmp), "1")) {
1744			setbuf.enable = 1;
1745		}
1746
1747		/* Set the MAC list */
1748		maclist = (struct maclist *)buf;
1749		maclist->count = 0;
1750		if (!nvram_match(strcat_r(bsscfg->prefix, "macmode", tmp), "disabled")) {
1751			ea = maclist->ea;
1752			foreach(var, nvram_safe_get(strcat_r(bsscfg->prefix, "maclist", tmp)),
1753				next) {
1754				if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)])))
1755					break;
1756				if (ether_atoe(var, ea->octet)) {
1757					maclist->count++;
1758					ea++;
1759				}
1760			}
1761		}
1762
1763		if (setbuf.bsscfg_idx == 0) {
1764			name_ptr = name;
1765		} else { /* Non-primary BSS; changes name syntax */
1766			char tmp[VIFNAME_LEN];
1767			int len;
1768
1769			/* Remove trailing _ if present */
1770			memset(tmp, 0, sizeof(tmp));
1771			strncpy(tmp, bsscfg->prefix, VIFNAME_LEN - 1);
1772			if (((len = strlen(tmp)) > 0) && (tmp[len - 1] == '_')) {
1773				tmp[len - 1] = 0;
1774			}
1775			nvifname_to_osifname(tmp, vifname, VIFNAME_LEN);
1776			name_ptr = vifname;
1777		}
1778
1779		WL_IOCTL(name_ptr, WLC_SET_MACLIST, buf, sizeof(buf));
1780
1781		/* Set macmode for each VIF */
1782		(void) strcat_r(bsscfg->prefix, "macmode", tmp);
1783
1784		if (nvram_match(tmp, "deny"))
1785			val = WLC_MACMODE_DENY;
1786		else if (nvram_match(tmp, "allow"))
1787			val = WLC_MACMODE_ALLOW;
1788		else
1789			val = WLC_MACMODE_DISABLED;
1790
1791		WL_IOCTL(name_ptr, WLC_SET_MACMODE, &val, sizeof(val));
1792
1793		/* NAS runs if we have an AKM or radius authentication */
1794		nas_will_run = wlconf_akm_options(bclist->bsscfgs[i].prefix) ||
1795		        nvram_match(strcat_r(bclist->bsscfgs[i].prefix, "auth_mode", tmp),
1796		                    "radius");
1797
1798		if (((ap || apsta) && !nas_will_run) || sta || wet) {
1799			for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) {
1800				if (wl_ap_build) {
1801					WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf));
1802				}
1803				else {
1804					strcat_r(prefix, "ssid", tmp);
1805					ssid.SSID_len = strlen(nvram_safe_get(tmp));
1806					if (ssid.SSID_len > sizeof(ssid.SSID))
1807						ssid.SSID_len = sizeof(ssid.SSID);
1808					strncpy((char *)ssid.SSID, nvram_safe_get(tmp),
1809					        ssid.SSID_len);
1810					WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1811				}
1812				if (apsta && (ret != 0))
1813					sleep_ms(1000);
1814				else
1815					break;
1816			}
1817		}
1818	}
1819
1820	ret = 0;
1821exit:
1822	if (bclist != NULL)
1823		free(bclist);
1824
1825	return ret;
1826}
1827
1828int
1829wlconf_down(char *name)
1830{
1831	int val, ret = 0;
1832	int i;
1833	int wlsubunit;
1834	int bcmerr;
1835	struct {int bsscfg_idx; int enable;} setbuf;
1836	int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */
1837	char cap[WLC_IOCTL_SMLEN];
1838	char caps[WLC_IOCTL_SMLEN];
1839	char *next;
1840	wlc_ssid_t ssid;
1841
1842	/* wlconf doesn't work for virtual i/f */
1843	if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) {
1844		WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name);
1845		return 0;
1846	}
1847
1848	/* Check interface (fail silently for non-wl interfaces) */
1849	if ((ret = wl_probe(name)))
1850		return ret;
1851
1852	/* because of ifdefs in wl driver,  when we don't have AP capabilities we
1853	 * can't use the same iovars to configure the wl.
1854	 * so we use "wl_ap_build" to help us know how to configure the driver
1855	 */
1856	if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
1857		return -1;
1858
1859	foreach(cap, caps, next) {
1860		if (!strcmp(cap, "ap")) {
1861			wl_ap_build = 1;
1862		}
1863	}
1864
1865	if (wl_ap_build) {
1866		/* Bring down the interface */
1867		WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1868
1869		/* Disable all BSS Configs */
1870		for (i = 0; i < WL_MAXBSSCFG; i++) {
1871			setbuf.bsscfg_idx = i;
1872			setbuf.enable = 0;
1873
1874			ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
1875			if (ret) {
1876				wl_iovar_getint(name, "bcmerror", &bcmerr);
1877				/* fail quietly on a range error since the driver may
1878				 * support fewer bsscfgs than we are prepared to configure
1879				 */
1880				if (bcmerr == BCME_RANGE)
1881					break;
1882			}
1883		}
1884	}
1885	else {
1886		WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
1887		if (val) {
1888			/* Nuke SSID  */
1889			ssid.SSID_len = 0;
1890			ssid.SSID[0] = '\0';
1891			WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1892
1893			/* Bring down the interface */
1894			WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1895		}
1896	}
1897
1898	/* Nuke the WDS list */
1899	wlconf_wds_clear(name);
1900
1901	return 0;
1902}
1903
1904int
1905wlconf_ssid(void)
1906{
1907//	struct bsscfg_info *bsscfg;
1908	wlc_ssid_t ssid;
1909	char name[32];
1910//	char ssid[256];
1911	int ret;
1912
1913
1914	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
1915//	printf("name=%s\n",name);
1916	ssid.SSID_len = 0;
1917	ssid.SSID[0] = '\0';
1918
1919	WL_IOCTL(name, WLC_GET_SSID, &ssid, sizeof(ssid));
1920
1921	printf("Current SSID:\"%s\"\n", ssid.SSID);
1922//	printf("wlconfig(%s): configuring bsscfg #%d (%s) with SSID \"%s\"\n",
1923//		name, bsscfg->idx, bsscfg->ifname, nvram_safe_get(tmp));
1924//	WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, sizeof(ssid));
1925	return 0;
1926}
1927
1928int
1929wlconf_set_ssid(char *tmpssid)
1930{
1931	wlc_ssid_t ssid;
1932	char name[32];
1933	int ret;
1934
1935	ssid.SSID_len = 0;
1936	ssid.SSID[0] = '\0';
1937
1938//	sprintf(ssid.SSID, "%s", tmpssid);
1939	strncpy((char *)ssid.SSID, tmpssid, strlen(tmpssid));
1940	ssid.SSID[strlen(tmpssid)+1] = '\0';
1941	ssid.SSID_len = strlen (tmpssid);
1942
1943//	printf("ssid.SSID=%s, tmpssid=%s, strlen=%d, SSID_LEN=%d\n", ssid.SSID, tmpssid, strlen(tmpssid), ssid.SSID_len);
1944
1945
1946	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
1947//	printf("name=%s\n!",name);
1948//	printf("tmpssid=%s!, length=%d\n", ssid.SSID, ssid.SSID_len);
1949	WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1950//	printf("SSID=%s!\n", ssid.SSID);
1951	return 0;
1952}
1953
1954int
1955wlconf_txant(char *var)
1956{
1957	char name[32];
1958	int ret;
1959	int val;
1960
1961	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
1962	val = atoi(var);
1963//	printf("val = %d, var = %s!\n", val, var);
1964	WL_IOCTL (name, WLC_SET_TXANT, &val, sizeof(val));
1965	printf("%d\n", val);
1966	return 0;
1967}
1968
1969int
1970wlconf_antdiv(char *var)
1971{
1972	char name[32];
1973	int ret;
1974	int val;
1975
1976	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
1977	val = atoi(var);
1978//	printf("val = %d, var = %s!\n", val, var);
1979	WL_IOCTL (name, WLC_SET_ANTDIV, &val, sizeof(val));
1980	printf("%d\n", val);
1981
1982	return 0;
1983}
1984
1985int
1986wlconf_radio(char *act)
1987{
1988	char name[32];
1989	int ret, val;
1990
1991	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
1992	if (!strcmp(act, "on"))
1993		val = 0;
1994	else
1995		val = 1;
1996
1997	val += WL_RADIO_SW_DISABLE << 16;
1998	WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
1999	printf("%d\n", val);
2000
2001	return 0;
2002}
2003
2004int
2005wlconf_auth(char *act)
2006{
2007	char name[32];
2008	int ret, val;
2009
2010	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2011	val = atoi(act);
2012	WL_IOCTL(name, WLC_SET_AUTH, &val, sizeof(val));
2013	printf("%d\n", val);
2014
2015	return 0;
2016}
2017
2018int
2019wlconf_wsec(char *var)
2020{
2021	char name[32];
2022	int ret, val;
2023
2024	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2025	val = atoi(var);
2026	WL_IOCTL(name, WLC_SET_WSEC, &val, sizeof(val));
2027	printf("%d\n", val);
2028
2029	return 0;
2030}
2031
2032int
2033wlconf_wpa_auth(char *var)
2034{
2035	char name[32];
2036	int ret, val;
2037
2038	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2039	val = atoi(var);
2040	WL_IOCTL(name, WLC_SET_WPA_AUTH, &val, sizeof(val));
2041	printf("%d\n", val);
2042
2043	return 0;
2044}
2045
2046int
2047wlconf_eap(char *var)
2048{
2049	char name[32];
2050	int ret, val;
2051
2052	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2053	if (!strcmp (var, "on"))
2054		val = 1;
2055	else
2056		val = 0;
2057//	val = atoi(var);
2058	WL_IOCTL(name, WLC_SET_EAP_RESTRICT, &val, sizeof(val));
2059	printf("%d\n", val);
2060
2061	return 0;
2062}
2063
2064int
2065wlconf_rate(char *var)
2066{
2067	char name[32];
2068	int ret, ret2, val;
2069
2070	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2071	val = atoi(var) *2;
2072//	WL_IOCTL(name, WLC_SET_RATE, &val, sizeof(val));
2073	ret = wl_iovar_setint(name, "bg_rate", val);
2074	ret2 = wl_iovar_setint(name, "bg_mrate", val);
2075	printf("%d Mbps\n", val/2);
2076
2077	return 0;
2078}
2079
2080int
2081wlconf_led(void)
2082{
2083//	struct bsscfg_info *bsscfg;
2084//	wlc_ssid_t ssid;
2085	char name[32];
2086	char led[256];
2087	int ret;
2088
2089
2090	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2091//	printf("name=%s\n",name);
2092//	ssid.SSID_len = 0;
2093	led[0] = '\0';
2094
2095	WL_IOCTL(name, WLC_GET_LED, &led, sizeof(led));
2096
2097	printf("LED:\"%s\"\n", led);
2098//	printf("wlconfig(%s): configuring bsscfg #%d (%s) with SSID \"%s\"\n",
2099//		name, bsscfg->idx, bsscfg->ifname, nvram_safe_get(tmp));
2100//	WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, sizeof(ssid));
2101	return 0;
2102}
2103
2104int
2105wlconf_set_led(char *led)
2106{
2107//	wlc_ssid_t ssid;
2108	char name[32];
2109	int ret;
2110
2111//	ssid.SSID_len = 0;
2112//	ssid.SSID[0] = '\0';
2113
2114//	sprintf(ssid.SSID, "%s", tmpssid);
2115//	strncpy((char *)ssid.SSID, tmpssid, strlen(tmpssid));
2116//	ssid.SSID[strlen(tmpssid)+1] = '\0';
2117//	ssid.SSID_len = strlen (tmpssid);
2118
2119//	printf("ssid.SSID=%s, tmpssid=%s, strlen=%d, SSID_LEN=%d\n", ssid.SSID, tmpssid, strlen(tmpssid), ssid.SSID_len);
2120
2121
2122	sprintf(name, "%s", nvram_safe_get("wl0_ifname"));
2123//	printf("name=%s\n!",name);
2124//	printf("tmpssid=%s!, length=%d\n", ssid.SSID, ssid.SSID_len);
2125	WL_IOCTL(name, WLC_SET_LED, &led, sizeof(led));
2126	printf("LED=%s!\n", led);
2127	return 0;
2128}
2129
2130#if defined(linux)
2131int
2132main(int argc, char *argv[])
2133{
2134	/* Check parameters and branch based on action */
2135	if (argc == 3 && !strcmp(argv[2], "up"))
2136		return wlconf(argv[1]);
2137	else if (argc == 3 && !strcmp(argv[2], "down"))
2138		return wlconf_down(argv[1]);
2139#if 0
2140	else {
2141		fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
2142		return -1;
2143	}
2144#endif
2145	else if (!strcmp(argv[1], "ssid")){
2146		if (argc == 2)
2147			return wlconf_ssid();
2148		else if (argc == 3)
2149			return wlconf_set_ssid(argv[2]);
2150		else {
2151			fprintf(stderr, "Usage: wlconf ssid (<name>) to show|set ssid\n");
2152			return -1;
2153		}
2154	}
2155	else if (!strcmp (argv[1], "txant")){
2156		if (argc == 3)
2157			return wlconf_txant(argv[2]);
2158		else {
2159			fprintf(stderr, "Usage: wlconf txant <val>\n");
2160			return 1;
2161		}
2162	}
2163	else if (!strcmp (argv[1], "antdiv")){
2164		if (argc == 3)
2165			return wlconf_antdiv(argv[2]);
2166		else {
2167			fprintf(stderr, "Usage: wlconf antdiv <val>\n");
2168			return -1;
2169		}
2170	}
2171	else if (!strcmp (argv[1], "auth")){
2172		if (argc == 3 && ( !strcmp (argv[2], "0") || !strcmp(argv[2], "1") ))
2173			return wlconf_auth(argv[2]);
2174		else {
2175			fprintf(stderr, "Usage: wlconf auth 0|1. 0:OpenSystem 1:SharedKey\n");
2176			return -1;
2177		}
2178	}
2179	else if (!strcmp (argv[1], "wsec")){
2180		if (argc == 3 )
2181			return wlconf_wsec(argv[2]);
2182		else {
2183			fprintf(stderr, "Usage: wlconf wsec <val> \n"
2184				"\t1:WEP 2:TKIP 4:AES 8:WSEC IN Software 0x80: FIPS enabled\n");
2185			return -1;
2186		}
2187	}
2188	else if (!strcmp (argv[1], "wpa_auth")){
2189		if (argc == 3 )
2190			return wlconf_wpa_auth(argv[2]);
2191		else {
2192			fprintf(stderr, "Usage: wlconf wpa_auth <val>\n"
2193				"\t1:WPA-NONE 2:WPA-802.1x 4:WPA-PSK\n"
2194				"\t64:WPA2-802.1x 128:WPA2-PSK 0:disable\n");
2195			return -1;
2196		}
2197	}
2198	else if (!strcmp (argv[1], "eap")){
2199		if (argc == 3 && (!strcmp (argv[2], "on") || !strcmp(argv[2], "off")))
2200			return wlconf_eap(argv[2]);
2201		else {
2202			fprintf(stderr, "Usage: wlconf eap on|off\n");
2203			return -1;
2204		}
2205	}
2206	else if (!strcmp (argv[1], "rate")){
2207		if (argc == 3 )
2208			return wlconf_rate(argv[2]);
2209		else {
2210			fprintf(stderr, "Usage: wlconf rate <rate>\n");
2211			return -1;
2212		}
2213	}
2214	else if (!strcmp(argv[1], "led")){
2215		if (argc == 2)
2216			return wlconf_led();
2217		else if (argc == 3)
2218			return wlconf_set_led(argv[2]);
2219		else {
2220			fprintf(stderr, "Usage: wlconf led (<value>) to show|set led\n");
2221			return -1;
2222		}
2223	}
2224	else if (!strcmp (argv[1], "radio")){
2225		if (argc == 3 && (!strcmp (argv[2], "on") || !strcmp(argv[2], "off")))
2226			return wlconf_radio(argv[2]);
2227		else {
2228			fprintf(stderr, "Usage: wlconf radio on|off\n");
2229			return -1;
2230		}
2231	}
2232	else {
2233		fprintf(stderr, "Usage: wlconf and one of:\n"
2234								"\t<interface> up|down\n"
2235								"\tssid        <name>\n"
2236								"\ttxant       <val>\n"
2237								"\tantdiv      <val>\n"
2238								"\tradio       on|off\n"
2239								"\tauth        <0|1>\n"
2240								"\twsec        on|off\n"
2241								"\twpa_auth    on|off\n"
2242								"\teap         on|off\n"
2243								"\trate        <rate>\n"
2244		);
2245	}
2246}
2247#endif
2248