source: src/router/wlconf/wlconf.c @ 9820

Last change on this file since 9820 was 9820, checked in by BrainSlayer, 5 years ago

should solve certain repeater mode problems

File size: 47.7 KB
Line 
1/*
2 * Wireless Network Adapter Configuration Utility
3 *
4 * Copyright 2006, 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$
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
81static int
82wlconf_getint(char* ifname, int cmd, int *pval)
83{
84        return wl_ioctl(ifname, cmd, pval, sizeof(int));
85}
86
87static int
88wlconf_setint(char* ifname, int cmd, int val)
89{
90        return wl_ioctl(ifname, cmd, &val, sizeof(int));
91}
92
93/* set WEP key */
94static int
95wlconf_set_wep_key(char *name, char *prefix, int bsscfg_idx, int i)
96{
97        wl_wsec_key_t key;
98        char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
99        char *keystr, hex[] = "XX";
100        unsigned char *data = key.data;
101        int ret = 0;
102
103        memset(&key, 0, sizeof(key));
104        key.index = i - 1;
105        sprintf(wl_key, "%skey%d", prefix, i);
106        keystr = nvram_safe_get(wl_key);
107
108        switch (strlen(keystr)) {
109        case WEP1_KEY_SIZE:
110        case WEP128_KEY_SIZE:
111                key.len = strlen(keystr);
112                strcpy((char *)key.data, keystr);
113                break;
114        case WEP1_KEY_HEX_SIZE:
115        case WEP128_KEY_HEX_SIZE:
116                key.len = strlen(keystr) / 2;
117                while (*keystr) {
118                        strncpy(hex, keystr, 2);
119                        *data++ = (unsigned char) strtoul(hex, NULL, 16);
120                        keystr += 2;
121                }
122                break;
123        default:
124                key.len = 0;
125                break;
126        }
127
128        /* Set current WEP key */
129        if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key))))
130                key.flags = WL_PRIMARY_KEY;
131
132        WL_BSSIOVAR_SET(name, "wsec_key", bsscfg_idx, &key, sizeof(key));
133
134        return ret;
135}
136
137extern struct nvram_tuple router_defaults[];
138
139/* Keep this table in order */
140static struct {
141        int locale;
142        char **names;
143        char *abbr;
144} countries[] = {
145        { WLC_WW,  ((char *[]) { "Worldwide", "WW", NULL }), "AU" },
146        { WLC_THA, ((char *[]) { "Thailand", "THA", NULL }), "TH" },
147        { WLC_ISR, ((char *[]) { "Israel", "ISR", NULL }), "IL" },
148        { WLC_JDN, ((char *[]) { "Jordan", "JDN", NULL }), "JO" },
149        { WLC_PRC, ((char *[]) { "China", "P.R. China", "PRC", NULL }), "CN" },
150        { WLC_JPN, ((char *[]) { "Japan", "JPN", NULL }), "JP" },
151        { WLC_FCC, ((char *[]) { "USA", "Canada", "ANZ", "New Zealand", "FCC", NULL }), "US" },
152        { WLC_EUR, ((char *[]) { "Europe", "EUR", NULL }), "DE" },
153        { WLC_USL, ((char *[]) { "USA Low", "USALow", "USL", NULL }), "US" },
154        { WLC_JPH, ((char *[]) { "Japan High", "JapanHigh", "JPH", NULL }), "JP" },
155        { WLC_ALL, ((char *[]) { "All", "AllTheChannels", NULL }), "All" },
156        };
157
158/* validate/restore all per-interface related variables */
159static void
160wlconf_validate_all(char *prefix, bool restore)
161{
162        struct nvram_tuple *t;
163        char tmp[100];
164        char *v;
165        for (t = router_defaults; t->name; t++) {
166                if (!strncmp(t->name, "wl_", 3)) {
167                        strcat_r(prefix, &t->name[3], tmp);
168                        if (!restore && nvram_get(tmp))
169                                continue;
170                        v = nvram_get(t->name);
171                        nvram_set(tmp, v ? v : t->value);
172                }
173        }
174}
175
176/* restore specific per-interface variable */
177static void
178wlconf_restore_var(char *prefix, char *name)
179{
180        struct nvram_tuple *t;
181        char tmp[100];
182        for (t = router_defaults; t->name; t++) {
183                if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) {
184                        nvram_set(strcat_r(prefix, name, tmp), t->value);
185                        break;
186                }
187        }
188}
189static int
190wlconf_akm_options(char *prefix)
191{
192        char comb[32];
193        char *wl_akm;
194        int akm_ret_val = 0;
195        char akm[32];
196        char *next;
197
198        wl_akm = nvram_default_get(strcat_r(prefix, "akm", comb),"disabled");
199        foreach(akm, wl_akm, next) {
200                if (!strcmp(akm, "wpa"))
201                        akm_ret_val |= WPA_AUTH_UNSPECIFIED;
202                if (!strcmp(akm, "psk"))
203                        akm_ret_val |= WPA_AUTH_PSK;
204#ifdef BCMWPA2
205                if (!strcmp(akm, "wpa2"))
206                        akm_ret_val |= WPA2_AUTH_UNSPECIFIED;
207                if (!strcmp(akm, "psk2"))
208                        akm_ret_val |= WPA2_AUTH_PSK;
209#endif
210        }
211        return akm_ret_val;
212}
213
214/* Set up wsec */
215static int
216wlconf_set_wsec(char *ifname, char *prefix, int bsscfg_idx)
217{
218        char tmp[100];
219        int val = 0;
220        int akm_val;
221        int ret;
222
223        nvram_default_get(strcat_r(prefix, "crypto", tmp),"off");
224        /* Set wsec bitvec */
225        akm_val = wlconf_akm_options(prefix);
226        if (akm_val != 0) {
227                if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip"))
228                        val = TKIP_ENABLED;
229                else if (nvram_match(strcat_r(prefix, "crypto", tmp), "aes"))
230                        val = AES_ENABLED;
231                else if (nvram_match(strcat_r(prefix, "crypto", tmp), "tkip+aes"))
232                        val = TKIP_ENABLED | AES_ENABLED;
233        }
234        if (nvram_default_match(strcat_r(prefix, "wep", tmp), "enabled","disabled"))
235                val |= WEP_ENABLED;
236        WL_BSSIOVAR_SETINT(ifname, "wsec", bsscfg_idx, val);
237        /* Set wsec restrict if WSEC_ENABLED */
238        WL_BSSIOVAR_SETINT(ifname, "wsec_restrict", bsscfg_idx, val ? 1 : 0);
239
240        return 0;
241}
242
243#ifdef BCMWPA2
244static int
245wlconf_set_preauth(char *name, int bsscfg_idx, int preauth)
246{
247        uint cap;
248        int ret;
249
250        WL_BSSIOVAR_GET(name, "wpa_cap", bsscfg_idx, &cap, sizeof(uint));
251        if (ret != 0) return -1;
252
253        if (preauth)
254                cap |= WPA_CAP_WPA2_PREAUTH;
255        else
256                cap &= ~WPA_CAP_WPA2_PREAUTH;
257
258        WL_BSSIOVAR_SETINT(name, "wpa_cap", bsscfg_idx, cap);
259
260        return ret;
261}
262#endif /* BCMWPA2 */
263
264/* Set up WME */
265static void
266wlconf_set_wme(char *name, char *prefix)
267{
268        int i, j, k;
269        int val, ret;
270        int phytype, gmode, no_ack, apsd, dp[2];
271        edcf_acparam_t *acparams;
272        char buf[WLC_IOCTL_MAXLEN];
273        char *v, *nv_value, nv[100];
274        char nv_name[] = "%swme_%s_%s";
275        char *ac[] = {"be", "bk", "vi", "vo"};
276        char *cwmin, *cwmax, *aifsn, *txop_b, *txop_ag, *admin_forced, *oldest_first;
277        char **locals[] = { &cwmin, &cwmax, &aifsn, &txop_b, &txop_ag, &admin_forced,
278                            &oldest_first };
279        struct {char *req; char *str;} mode[] = {{"wme_ac_sta", "sta"}, {"wme_ac_ap", "ap"}};
280
281        /* query the phy type */
282        WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
283        /* get gmode */
284        gmode = atoi(nvram_default_get(strcat_r(prefix, "gmode", nv),"1"));
285
286        /* WME sta setting first */
287        for (i = 0; i < 2; i++) {
288                /* build request block */
289                memset(buf, 0, sizeof(buf));
290                strcpy(buf, mode[i].req);
291                /* put push wmeac params after "wme-ac" in buf */
292                acparams = (edcf_acparam_t *)(buf + strlen(buf) + 1);
293                dp[i] = 0;
294                for (j = 0; j < AC_COUNT; j++) {
295                        /* get packed nvram parameter */
296                        snprintf(nv, sizeof(nv), nv_name, prefix, mode[i].str, ac[j]);
297                        nv_value = nvram_safe_get(nv);
298                        strcpy(nv, nv_value);
299                        /* unpack it */
300                        v = nv;
301                        for (k = 0; k < (sizeof(locals) / sizeof(locals[0])); k++) {
302                                *locals[k] = v;
303                                while (*v && *v != ' ')
304                                        v++;
305                                if (*v) {
306                                        *v = 0;
307                                        v++;
308                                }
309                        }
310
311                        /* update CWmin */
312                        acparams->ECW &= ~EDCF_ECWMIN_MASK;
313                        val = atoi(cwmin);
314                        for (val++, k = 0; val; val >>= 1, k++);
315                        acparams->ECW |= (k ? k - 1 : 0) & EDCF_ECWMIN_MASK;
316                        /* update CWmax */
317                        acparams->ECW &= ~EDCF_ECWMAX_MASK;
318                        val = atoi(cwmax);
319                        for (val++, k = 0; val; val >>= 1, k++);
320                        acparams->ECW |= ((k ? k - 1 : 0) << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK;
321                        /* update AIFSN */
322                        acparams->ACI &= ~EDCF_AIFSN_MASK;
323                        acparams->ACI |= atoi(aifsn) & EDCF_AIFSN_MASK;
324                        /* update ac */
325                        acparams->ACI &= ~EDCF_ACI_MASK;
326                        acparams->ACI |= j << EDCF_ACI_SHIFT;
327                        /* update TXOP */
328                        if (phytype == PHY_TYPE_B || gmode == 0)
329                                val = atoi(txop_b);
330                        else
331                                val = atoi(txop_ag);
332                        acparams->TXOP = val / 32;
333                        /* update acm */
334                        acparams->ACI &= ~EDCF_ACM_MASK;
335                        val = strcmp(admin_forced, "on") ? 0 : 1;
336                        acparams->ACI |= val << 4;
337
338                        /* configure driver */
339                        WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
340                }
341        }
342
343        /* set no-ack */
344        v = nvram_default_get(strcat_r(prefix, "wme_no_ack", nv),"off");
345        no_ack = strcmp(v, "on") ? 0 : 1;
346        WL_IOVAR_SETINT(name, "wme_noack", no_ack);
347
348        /* set APSD */
349        v = nvram_default_get(strcat_r(prefix, "wme_apsd", nv),"on");
350        apsd = strcmp(v, "on") ? 0 : 1;
351        WL_IOVAR_SETINT(name, "wme_apsd", apsd);
352
353        /* set per-AC discard policy */
354        strcpy(buf, "wme_dp");
355        WL_IOVAR_SETINT(name, "wme_dp", dp[1]);
356}
357
358#if defined(linux)
359#include <unistd.h>
360static void
361sleep_ms(const unsigned int ms)
362{
363        usleep(1000*ms);
364}
365#else
366#error "sleep_ms() not defined for this OS!!!"
367#endif /* defined(linux) */
368
369/*
370* The following condition(s) must be met when Auto Channel Selection
371* is enabled.
372*  - the I/F is up (change radio channel requires it is up?)
373*  - the AP must not be associated (setting SSID to empty should
374*    make sure it for us)
375*/
376static uint8
377wlconf_auto_channel(char *name)
378{
379        int chosen = 0;
380        wl_uint32_list_t request;
381        int phytype;
382        int ret;
383        int i;
384
385        /* query the phy type */
386        WL_GETINT(name, WLC_GET_PHYTYPE, &phytype);
387
388        request.count = 0;      /* let the ioctl decide */
389        WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
390        if (!ret) {
391                sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
392                for (i = 0; i < 100; i++) {
393                        WL_GETINT(name, WLC_GET_CHANNEL_SEL, &chosen);
394                        if (!ret)
395                                break;
396                        sleep_ms(100);
397                }
398        }
399        WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
400        return chosen;
401}
402
403static chanspec_t
404wlconf_auto_chanspec(char *name,char *prefix)
405{
406        chanspec_t chosen = 0;
407        wl_uint32_list_t request;
408        char tmp[100];
409        int bandtype;
410        int ret;
411        int i;
412        int chanspec_asus = 0;
413
414        /* query the band type */
415        WL_GETINT(name, WLC_GET_BAND, &bandtype);
416
417        request.count = 0;      /* let the ioctl decide */
418        WL_IOCTL(name, WLC_START_CHANNEL_SEL, &request, sizeof(request));
419        if (!ret) {
420                sleep_ms(1000);
421                for (i = 0; i < 100; i++) {
422                        WL_IOVAR_GETINT(name, "apcschspec", (void *)&chosen);
423                        if (!ret)
424                                break;
425                        sleep_ms(100);
426                }
427        }
428
429        WLCONF_DBG("interface %s: chanspec selected %04x\n", name, chosen);
430        return chosen;
431}
432
433
434/* PHY type/BAND conversion */
435#define WLCONF_PHYTYPE2BAND(phy)        ((phy) == PHY_TYPE_A ? WLC_BAND_5G : WLC_BAND_2G)
436/* PHY type conversion */
437#define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
438                                 (phy) == PHY_TYPE_B ? "b" : \
439                                 (phy) == PHY_TYPE_LP ? "l" : \
440                                 (phy) == PHY_TYPE_G ? "g" : "n")
441#define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
442                                 (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : \
443                                 (phy) && (phy)[0] == 'l' ? PHY_TYPE_LP : \
444                                 (phy) && (phy)[0] == 'g' ? PHY_TYPE_G : PHY_TYPE_N)
445
446
447#define PREFIX_LEN 32                   /* buffer size for wlXXX_ prefix */
448
449struct bsscfg_info {
450        int idx;                        /* bsscfg index */
451        char ifname[PREFIX_LEN];        /* OS name of interface (debug only) */
452        char prefix[PREFIX_LEN];        /* prefix for nvram params (eg. "wl0.1_") */
453};
454
455struct bsscfg_list {
456        int count;
457        struct bsscfg_info bsscfgs[WL_MAXBSSCFG];
458};
459
460struct bsscfg_list *
461wlconf_get_bsscfgs(char* ifname, char* prefix)
462{
463        char var[80];
464        char tmp[100];
465        char *next;
466
467        struct bsscfg_list *bclist;
468        struct bsscfg_info *bsscfg;
469
470        bclist = (struct bsscfg_list*)malloc(sizeof(struct bsscfg_list));
471        if (bclist == NULL)
472                return NULL;
473        memset(bclist, 0, sizeof(struct bsscfg_list));
474
475        /* Set up Primary BSS Config information */
476        bsscfg = &bclist->bsscfgs[0];
477        bsscfg->idx = 0;
478        strncpy(bsscfg->ifname, ifname, PREFIX_LEN-1);
479        strcpy(bsscfg->prefix, prefix);
480        bclist->count = 1;
481       
482        /* additional virtual BSS Configs from wlX_vifs */
483        if (nvram_default_match(strcat_r(prefix, "mode", tmp),"ap","ap") || nvram_match(strcat_r(prefix, "mode", tmp),"apsta") || nvram_match(strcat_r(prefix, "mode", tmp),"apstawet"))
484        {
485        foreach(var, nvram_safe_get(strcat_r(prefix, "vifs", tmp)), next) {
486                if (bclist->count == WL_MAXBSSCFG) {
487                        WLCONF_DBG("wlconf(%s): exceeded max number of BSS Configs (%d)"
488                                   "in nvram %s\n"
489                                   "while configuring interface \"%s\"\n",
490                                   ifname, WL_MAXBSSCFG, strcat_r(prefix, "vifs", tmp), var);
491                        continue;
492                }
493                bsscfg = &bclist->bsscfgs[bclist->count];
494                if (get_ifname_unit(var, NULL, &bsscfg->idx) != 0) {
495                        WLCONF_DBG("wlconfg(%s): unable to parse unit.subunit in interface "
496                                   "name \"%s\"\n",
497                                   ifname, var);
498                        continue;
499                }
500                strncpy(bsscfg->ifname, var, PREFIX_LEN-1);
501                snprintf(bsscfg->prefix, PREFIX_LEN, "%s_", bsscfg->ifname);
502                bclist->count++;
503        }
504        }
505
506        return bclist;
507}
508
509static void
510wlconf_security_options(char *name, char *prefix, int bsscfg_idx, bool wet)
511{
512        int i;
513        int val;
514        int ret;
515        char tmp[100];
516
517        /* Set WSEC */
518        /*
519        * Need to check errors (card may have changed) and change to
520        * defaults since the new chip may not support the requested
521        * encryptions after the card has been changed.
522        */
523        if (wlconf_set_wsec(name, prefix, bsscfg_idx)) {
524                /* change nvram only, code below will pass them on */
525                wlconf_restore_var(prefix, "auth_mode");
526                wlconf_restore_var(prefix, "auth");
527                /* reset wep to default */
528                wlconf_restore_var(prefix, "crypto");
529                wlconf_restore_var(prefix, "wep");
530                wlconf_set_wsec(name, prefix, bsscfg_idx);
531        }
532
533        val = wlconf_akm_options(prefix);
534        /* In wet mode enable in driver wpa supplicant */
535        if (wet && (CHECK_PSK(val))) {
536                wsec_pmk_t psk;
537                char *key;
538
539                if (((key = nvram_get(strcat_r(prefix, "wpa_psk", tmp))) != NULL) &&
540                    (strlen(key) < WSEC_MAX_PSK_LEN)) {
541                        psk.key_len = (ushort) strlen(key);
542                        psk.flags = WSEC_PASSPHRASE;
543                        strcpy((char *)psk.key, key);
544                        WL_IOCTL(name, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
545                }
546                wl_iovar_setint(name, "sup_wpa", 1);
547        }
548        WL_BSSIOVAR_SETINT(name, "wpa_auth", bsscfg_idx, val);
549
550        /* EAP Restrict if we have an AKM or radius authentication */
551        val = ((val != 0) || (nvram_default_match(strcat_r(prefix, "auth_mode", tmp), "radius","disabled")));
552        WL_BSSIOVAR_SETINT(name, "eap_restrict", bsscfg_idx, val);
553
554        /* Set WEP keys */
555        if (nvram_default_match(strcat_r(prefix, "wep", tmp), "enabled","disabled")) {
556                for (i = 1; i <= DOT11_MAX_DEFAULT_KEYS; i++)
557                        wlconf_set_wep_key(name, prefix, bsscfg_idx, i);
558        }
559
560        /* Set 802.11 authentication mode - open/shared */
561        val = atoi(nvram_default_get(strcat_r(prefix, "auth", tmp),"0"));
562        WL_BSSIOVAR_SETINT(name, "auth", bsscfg_idx, val);
563}
564
565/* configure the specified wireless interface */
566int
567wlconf(char *name)
568{
569        int restore_defaults, val, unit, phytype, bandtype, gmode = 0, ret = 0;
570        int buflen;
571        uint32 *val_ptr; /* required for iovars */
572        int bcmerr;
573        int error_bg, error_a;
574        struct bsscfg_list *bclist = NULL;
575        struct bsscfg_info *bsscfg;
576        char tmp[100], prefix[PREFIX_LEN];
577        char var[80], *next, phy[] = "a", *str, *addr = NULL;
578        char buf[WLC_IOCTL_MAXLEN];
579        char *country;
580        wlc_rev_info_t rev;
581        channel_info_t ci;
582        struct maclist *maclist;
583        struct ether_addr *ea;
584        wlc_ssid_t ssid;
585        wl_rateset_t rs;
586        unsigned int i;
587        char eaddr[32];
588        int ap, apsta, wds, sta = 0, wet = 0, mac_spoof = 0;
589        char country_code[4];
590        int nas_will_run = 0;
591        char *wme, *ba;
592        char vif_addr[WLC_IOCTL_SMLEN];
593#ifdef BCMWPA2
594        char *preauth;
595        int set_preauth;
596#endif
597        int ii;
598        int wlunit = -1;
599        int wlsubunit = -1;
600        int max_no_vifs = 0;
601        int mbsscap = 0;
602        int wl_ap_build = 0; /* wl compiled with AP capabilities */
603        char cap[WLC_IOCTL_SMLEN];
604        char caps[WLC_IOCTL_SMLEN];
605        int btc_mode;
606        uint32 leddc;
607        bool ure_enab = FALSE;
608
609        /* wlconf doesn't work for virtual i/f, so if we are given a
610         * virtual i/f return 0 if that interface is in it's parent's "vifs"
611         * list otherwise return -1
612         */
613cprintf("get ifname unit\n");
614        if (get_ifname_unit(name, &wlunit, &wlsubunit) == 0)
615        {
616                if (wlsubunit >= 0)
617                {
618                        /* we have been given a virtual i/f,
619                         * is it in it's parent i/f's virtual i/f list?
620                         */
621                        sprintf(tmp, "wl%d_vifs", wlunit);
622
623                        if (strstr(nvram_safe_get(tmp), name) == NULL)
624                                return -1; /* config error */
625                        else
626                                return 0; /* okay */
627                }
628        }
629        else
630        {
631                return -1;
632        }
633
634        /* clean up tmp */
635        memset(tmp, 0, sizeof(tmp));
636
637        /* because of ifdefs in wl driver,  when we don't have AP capabilities we
638         * can't use the same iovars to configure the wl.
639         * so we use "wl_ap_build" to help us know how to configure the driver
640         */
641cprintf("get caps\n");
642        if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
643                return -1;
644
645
646        foreach(cap, caps, next) {
647                if (!strcmp(cap, "ap")) {
648                        wl_ap_build = 1;
649                }
650                else if (!strcmp(cap, "mbss16"))
651                {
652                        max_no_vifs = 16;
653                        mbsscap = 1;
654                }
655                else if (!strcmp(cap, "mbss4"))
656                {
657                        max_no_vifs = 4;
658                        mbsscap = 1;
659                }
660        }
661cprintf("wl probe\n");
662        /* Check interface (fail silently for non-wl interfaces) */
663        if ((ret = wl_probe(name)))
664                return ret;
665
666cprintf("get wl addr\n");
667        /* Get MAC address */
668        (void) wl_hwaddr(name, (uchar *)buf);
669        memcpy(vif_addr, buf, ETHER_ADDR_LEN);
670        /* Get instance */
671cprintf("get instance\n");
672        WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit));
673        sprintf(tmp, "wl%d_mbss", unit);
674        if (mbsscap)
675            {
676            nvram_set(tmp,"1");
677            }else
678            {
679            nvram_set(tmp,"0");
680            }
681        /* clean up tmp */
682        memset(tmp, 0, sizeof(tmp));
683
684        snprintf(prefix, sizeof(prefix), "wl%d_", unit);
685
686        /* Restore defaults if per-interface parameters do not exist */
687        restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
688        wlconf_validate_all(prefix, restore_defaults);
689        nvram_set(strcat_r(prefix, "ifname", tmp), name);
690        nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa((uchar *)buf, eaddr));
691        snprintf(buf, sizeof(buf), "%d", unit);
692        nvram_set(strcat_r(prefix, "unit", tmp), buf);
693
694
695cprintf("shut down %s\n",name);
696        /* Bring the interface down */
697        WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
698
699cprintf("disable bss %s\n",name);
700        /* Disable all BSS Configs */
701        for (i = 0; i < WL_MAXBSSCFG; i++) {
702                struct {int bsscfg_idx; int enable;} setbuf;
703                setbuf.bsscfg_idx = i;
704                setbuf.enable = 0;
705
706                ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
707                if (ret) {
708                        wl_iovar_getint(name, "bcmerror", &bcmerr);
709                        /* fail quietly on a range error since the driver may
710                         * support fewer bsscfgs than we are prepared to configure
711                         */
712                        if (bcmerr == BCME_RANGE)
713                                break;
714                }
715                if (ret)
716                        WLCONF_DBG("%d:(%s): setting bsscfg #%d iovar \"bss\" to 0"
717                                   " (down) failed, ret = %d, bcmerr = %d\n",
718                                   __LINE__, name, i, ret, bcmerr);
719        }
720
721        /* Get the list of BSS Configs */
722        bclist = wlconf_get_bsscfgs(name, prefix);
723        if (bclist == NULL) {
724                ret = -1;
725                goto exit;
726        }
727
728
729        /* create a wlX.Y_ifname nvram setting */
730        for (i = 1; i < bclist->count; i++) {
731                bsscfg = &bclist->bsscfgs[i];
732#if defined(linux)
733                strcpy(var, bsscfg->ifname);
734#endif
735                nvram_set(strcat_r(bsscfg->prefix, "ifname", tmp), var);
736        }
737
738        /* wlX_mode settings: AP, STA, WET, BSS/IBSS, APSTA */
739        str = nvram_default_get(strcat_r(prefix, "mode", tmp),"dd-wrt");
740        ap = (!strcmp(str, "") || !strcmp(str, "ap") || !strcmp(str, "mssid"));
741        apsta = (!strcmp(str, "apsta") || !strcmp(str, "apstawet") || ((!strcmp(str, "sta") || !strcmp(str, "wet")) && bclist->count > 1));
742        sta = (!strcmp(str, "sta") && bclist->count == 1);
743        wds = !strcmp(str, "wds");
744        wet = !strcmp(str, "wet") || !strcmp(str, "apstawet");
745        mac_spoof = !strcmp(str, "mac_spoof");
746
747        if (wet && apsta) { /* URE is enabled */
748                ure_enab = TRUE;
749        }
750cprintf("set mssid flags %s\n",name);
751        if (wl_ap_build) {
752                /* Enable MSSID mode if appropriate */
753                WL_IOVAR_SETINT(name, "mssid", (bclist->count > 1));
754                if (!ure_enab && mbsscap) {
755                WL_IOVAR_SETINT(name, "mbss", (bclist->count > 1)); //compatiblitiy with newer drivers
756                }else{
757                WL_IOVAR_SETINT(name, "mbss", 0); //compatiblitiy with newer drivers
758               
759                }
760                /*
761                 * Set SSID for each BSS Config
762                 */
763                for (i = 0; i < bclist->count; i++) {
764                        bsscfg = &bclist->bsscfgs[i];
765                        strcat_r(bsscfg->prefix, "ssid", tmp);
766                        ssid.SSID_len = strlen(nvram_default_get(tmp,"dd-wrt"));
767                        if (ssid.SSID_len > sizeof(ssid.SSID))
768                                ssid.SSID_len = sizeof(ssid.SSID);
769                        strncpy((char *)ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len);
770                        WLCONF_DBG("wlconfig(%s): configuring bsscfg #%d (%s) with SSID \"%s\"\n",
771                                   name, bsscfg->idx, bsscfg->ifname, nvram_safe_get(tmp));
772                        WL_BSSIOVAR_SET(name, "ssid", bsscfg->idx, &ssid, sizeof(ssid));
773                }
774        }
775#define MBSS_UC_IDX_MASK                (4 - 1)
776
777cprintf("set local addr %s\n",name);
778        if (!ure_enab) {
779                /* set local bit for our MBSS vif base */
780                if (mbsscap)
781                    ETHER_SET_LOCALADDR(vif_addr);
782                char newmac[32];
783                memcpy(newmac,vif_addr,sizeof(vif_addr));
784                /* construct and set other wlX.Y_hwaddr */
785                for (i = 1; i < 4; i++) {
786                        snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr", unit, i);
787                        addr = nvram_safe_get(tmp);
788                                if (mbsscap)
789                                    vif_addr[5] = (newmac[5] & ~MBSS_UC_IDX_MASK) | (MBSS_UC_IDX_MASK & (newmac[5]+i));
790
791                                nvram_set(tmp, ether_etoa((uchar *)vif_addr,
792                                                          eaddr));
793                }
794                /* The addresses are available in NVRAM, so set them */
795                for (i = 1; i < 4; i++) {
796                                snprintf(tmp, sizeof(tmp), "wl%d.%d_hwaddr",
797                                         unit, i);
798                                ether_atoe(nvram_safe_get(tmp), eaddr);
799                                snprintf(tmp, sizeof(tmp), "wl%d.%d",
800                                         unit, i);
801                                WL_BSSIOVAR_SET(tmp, "cur_etheraddr", i,
802                                                eaddr, ETHER_ADDR_LEN);
803                }
804        } else { /* URE is enabled */
805                /* URE is on, so set wlX.1 hwaddr is same as that of primary interface */
806                snprintf(tmp, sizeof(tmp), "wl%d.1_hwaddr", unit);
807                WL_BSSIOVAR_SET(name, "cur_etheraddr", 1, vif_addr,
808                                ETHER_ADDR_LEN);
809        }
810
811
812        /* Set AP mode */
813        val = (ap || apsta || wds) ? 1 : 0;
814cprintf("set ap flag %s\n",name);
815        WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val));
816
817cprintf("set apsta flag %s\n",name);
818        WL_IOVAR_SETINT(name, "apsta", apsta);
819
820        /* Set mode: WET */
821cprintf("set wet flag %s\n",name);
822        if (wet)
823                WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet));
824
825cprintf("set spoof flag %s\n",name);
826        if (mac_spoof) {
827                sta = 1;
828                WL_IOVAR_SETINT(name, "mac_spoof", 1);
829        }
830
831        /* For STA configurations, configure association retry time.
832         * Use specified time (capped), or mode-specific defaults.
833         */
834cprintf("set sta retry time %s\n",name);
835        if (sta || wet || apsta) {
836                char *retry_time = nvram_default_get(strcat_r(prefix, "sta_retry_time", tmp),"5");
837                val = atoi(retry_time);
838                WL_IOVAR_SETINT(name, "sta_retry_time", val);
839        }
840
841        /* Retain remaining WET effects only if not APSTA */
842//      wet &= !apsta;
843
844        /* Set infra: BSS/IBSS (IBSS only for WET or STA modes) */
845        val = 1;
846        if (wet || sta)
847                val = atoi(nvram_default_get(strcat_r(prefix, "infra", tmp),"1"));
848cprintf("set infra flag %s\n",name);
849        WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val));
850
851cprintf("set maxassoc flag %s\n",name);
852        /* Set The AP MAX Associations Limit */
853        if (ap | apsta) {
854                val = atoi(nvram_default_get(strcat_r(prefix, "maxassoc", tmp),"128"));
855                if (val > 0)
856                        WL_IOVAR_SETINT(name, "maxassoc", val);
857        }
858cprintf("set bsscfg %s\n",name);
859
860        for (i = 0; i < bclist->count; i++) {
861                char *subprefix;
862                bsscfg = &bclist->bsscfgs[i];
863
864#ifdef BCMWPA2
865                /* XXXMSSID: The note about setting preauth now does not seem right.
866                 * NAS brings the BSS up if it runs, so setting the preauth value
867                 * will make it in the bcn/prb. If that is right, we can move this
868                 * chunk out of wlconf.
869                 */
870                /*
871                 * Set The WPA2 Pre auth cap. only reason we are doing it here is the driver is down
872                 * if we do it in the NAS we need to bring down the interface and up to make
873                 * it affect in the  beacons
874                 */
875                if (ap || (apsta && bsscfg->idx != 0)) {
876                        set_preauth = 1;
877                        preauth = nvram_safe_get(strcat_r(bsscfg->prefix, "preauth", tmp));
878                        if (strlen (preauth) != 0) {
879                                set_preauth = atoi(preauth);
880                        }
881                        wlconf_set_preauth(name, bsscfg->idx, set_preauth);
882                }
883#endif /* BCMWPA2 */
884
885                subprefix = apsta ? prefix : bsscfg->prefix;
886
887                /* Set network type */
888                val = atoi(nvram_default_get(strcat_r(subprefix, "closed", tmp),"0"));
889                WL_BSSIOVAR_SETINT(name, "closednet", bsscfg->idx, val);
890
891                /* Set the ap isolate mode */
892                val = atoi(nvram_default_get(strcat_r(subprefix, "ap_isolate", tmp),"0"));
893                WL_BSSIOVAR_SETINT(name, "ap_isolate", bsscfg->idx, val);
894        }
895
896cprintf("get phy type %s\n",name);
897        /* Get current phy type */
898        WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
899        snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype));
900        nvram_set(strcat_r(prefix, "phytype", tmp), buf);
901
902        /* Set up the country code */
903        (void) strcat_r(prefix, "country_code", tmp);
904       
905#ifdef HAVE_BUFFALO
906        country = BUFFALO_COUNTRY;
907#else
908        if (nvram_match("wl0_phytype","a"))
909            country="US";
910        else
911            country="JP";
912        if (phytype == PHY_TYPE_N)
913            {
914            if (nvram_default_match(strcat_r(prefix, "net_mode", tmp),"n-only","mixed") || nvram_match(strcat_r(prefix, "net_mode", tmp),"mixed"))
915                country="DE";
916            }
917        //country = nvram_get(tmp);
918#endif
919cprintf("set country %s\n",name);
920        if (country) {
921                strncpy(country_code, country, sizeof(country_code));
922                WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
923        }
924        else {
925                /* If country_code doesn't exist, check for country to be backward compatible */
926                (void) strcat_r(prefix, "country", tmp);
927                country = nvram_safe_get(tmp);
928                for (val = 0; val < ARRAYSIZE(countries); val++) {
929                        char **synonym;
930                        for (synonym = countries[val].names; *synonym; synonym++)
931                                if (!strcmp(country, *synonym))
932                                        break;
933                        if (*synonym)
934                                break;
935                }
936
937                /* Get the default country code if undefined or invalid and set the NVRAM */
938                if (val >= ARRAYSIZE(countries)) {
939                        WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code));
940                }
941                else {
942                        strncpy(country_code, countries[val].abbr, sizeof(country_code));
943                        WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
944                }
945
946                /* Add the new NVRAM variable */
947                nvram_set("wl_country_code", country_code);
948                (void) strcat_r(prefix, "country_code", tmp);
949                nvram_set(tmp, country_code);
950        }
951
952cprintf("set reg mode %s\n",name);
953        /* Setup regulatory mode */
954        strcat_r(prefix, "reg_mode", tmp);
955        if (nvram_default_match(tmp, "off","off"))  {
956                val = 0;
957                WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
958                WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
959                WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
960        } else if (nvram_match(tmp, "h")) {
961                val = 0;
962                WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
963                val = 1;
964                WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
965                WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
966
967                /* Set the CAC parameters */
968                val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_preism", tmp)));
969                wl_iovar_setint(name, "dfs_preism", val);
970                val = atoi(nvram_safe_get(strcat_r(prefix, "dfs_postism", tmp)));
971                wl_iovar_setint(name, "dfs_postism", val);
972                val = atoi(nvram_safe_get(strcat_r(prefix, "tpc_db", tmp)));
973                WL_IOCTL(name, WLC_SEND_PWR_CONSTRAINT, &val, sizeof(val));
974
975        } else if (nvram_match(tmp, "d")) {
976                val = 0;
977                WL_IOCTL(name, WLC_SET_RADAR, &val, sizeof(val));
978                WL_IOCTL(name, WLC_SET_SPECT_MANAGMENT, &val, sizeof(val));
979                val = 1;
980                WL_IOCTL(name, WLC_SET_REGULATORY, &val, sizeof(val));
981        }
982cprintf("set maclist %s\n",name);
983
984        /* Set the MAC list */
985        maclist = (struct maclist *) buf;
986        maclist->count = 0;
987        if (!nvram_default_match(strcat_r(prefix, "macmode", tmp), "disabled","disabled")) {
988                ea = maclist->ea;
989                foreach(var, nvram_safe_get(strcat_r(prefix, "maclist", tmp)), next) {
990                        if (((char *)((&ea[1])->octet)) > ((char *)(&buf[sizeof(buf)])))
991                                break;
992                        if (ether_atoe(var, ea->octet)) {
993                                maclist->count++;
994                                ea++;
995                        }
996                }
997        }
998        WL_IOCTL(name, WLC_SET_MACLIST, buf, sizeof(buf));
999
1000cprintf("set macmode %s\n",name);
1001        /* Set the MAC list mode */
1002        (void) strcat_r(prefix, "macmode", tmp);
1003        if (nvram_default_match(tmp, "deny","disabled"))
1004                val = WLC_MACMODE_DENY;
1005        else if (nvram_match(tmp, "allow"))
1006                val = WLC_MACMODE_ALLOW;
1007        else
1008                val = WLC_MACMODE_DISABLED;
1009        WL_IOCTL(name, WLC_SET_MACMODE, &val, sizeof(val));
1010
1011        /* Change LED Duty Cycle */
1012        leddc = (uint32)strtoul(nvram_default_get(strcat_r(prefix, "leddc", tmp),"0x640000"), NULL, 16);
1013        if (leddc)
1014                WL_IOVAR_SETINT(name, "leddc", leddc);
1015
1016        /* Enable or disable the radio */
1017cprintf("set radio flag %s\n",name);
1018        val = nvram_default_match(strcat_r(prefix, "radio", tmp), "0","1");
1019        val += WL_RADIO_SW_DISABLE << 16;
1020        WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
1021
1022cprintf("get phy flags %s\n",name);
1023        /* Get supported phy types */
1024        WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var));
1025
1026        nvram_set(strcat_r(prefix, "phytypes", tmp), var);
1027
1028        /* Get radio IDs */
1029        *(next = buf) = '\0';
1030        for (i = 0; i < strlen(var); i++) {
1031                /* Switch to band */
1032                phy[0] = var[i];
1033                val = WLCONF_STR2PHYTYPE(phy);
1034                if (val == PHY_TYPE_N) {
1035                        WL_GETINT(name, WLC_GET_BAND, &val);
1036                } else
1037                        val = WLCONF_PHYTYPE2BAND(val);
1038                WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
1039                /* Get radio ID on this band */
1040                WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1041                next += sprintf(next, "%sBCM%X", i ? " " : "",
1042                                (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT);
1043        }
1044cprintf("set radio ids %s\n",name);
1045        nvram_set(strcat_r(prefix, "radioids", tmp), buf);
1046
1047        /* Set band */
1048cprintf("set nband %s\n",name);
1049        str = nvram_get(strcat_r(prefix, "phytype", tmp));
1050        val = WLCONF_STR2PHYTYPE(str);
1051        /* For NPHY use band value from NVRAM */
1052        if (val == PHY_TYPE_N) {
1053                str = nvram_get(strcat_r(prefix, "nband", tmp));
1054                if (str)
1055                        val = atoi(str);
1056                else {
1057                        WL_GETINT(name, WLC_GET_BAND, &val);
1058                }
1059        } else
1060                val = WLCONF_PHYTYPE2BAND(val);
1061
1062cprintf("set band %s\n",name);
1063        WL_SETINT(name, WLC_SET_BAND, val);
1064
1065        /* Check errors (card may have changed) */
1066        if (ret) {
1067                /* default band to the first band in band list */
1068                phy[0] = var[0];
1069                val = WLCONF_STR2PHYTYPE(phy);
1070                val = WLCONF_PHYTYPE2BAND(val);
1071                WL_SETINT(name, WLC_SET_BAND, val);
1072        }
1073
1074        /* Store the resolved bandtype */
1075        bandtype = val;
1076
1077        /* Get current core revision */
1078cprintf("get core rev %s\n",name);
1079        WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
1080        snprintf(buf, sizeof(buf), "%d", rev.corerev);
1081        nvram_set(strcat_r(prefix, "corerev", tmp), buf);
1082
1083
1084        /* Set channel before setting gmode or rateset */
1085        /* Manual Channel Selection - when channel # is not 0 */
1086cprintf("set channel %s\n",name);
1087        val = atoi(nvram_default_get(strcat_r(prefix, "channel", tmp),"0"));
1088        if (val && phytype != PHY_TYPE_N) {
1089                WL_SETINT(name, WLC_SET_CHANNEL, val);
1090                if (ret) {
1091                        /* Use current channel (card may have changed) */
1092                        WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
1093                        snprintf(buf, sizeof(buf), "%d", ci.target_channel);
1094                        nvram_set(strcat_r(prefix, "channel", tmp), buf);
1095                }
1096        } else if (val && phytype == PHY_TYPE_N) {
1097                chanspec_t chanspec = 0;
1098                uint channel;
1099                uint nbw;
1100                uint nctrlsb = WL_CHANSPEC_CTL_SB_NONE;
1101
1102                channel = val;
1103                /* Get BW */
1104                val = atoi(nvram_safe_get(strcat_r(prefix, "nbw", tmp)));
1105                if (nvram_match(strcat_r(prefix, "net_mode", tmp),"b-only") ||  nvram_match(strcat_r(prefix, "net_mode", tmp),"g-only") || nvram_match(strcat_r(prefix, "net_mode", tmp),"a-only") ||  nvram_match(strcat_r(prefix, "net_mode", tmp),"bg-mixed"));
1106                        val = 20;
1107               
1108                fprintf(stderr,"channel %d, val %d\n",channel,val);
1109                switch (val) {
1110                case 40:
1111                        val = WL_CHANSPEC_BW_40;
1112                        break;
1113                case 20:
1114                        val = WL_CHANSPEC_BW_20;
1115                        break;
1116                case 10:
1117                        val = WL_CHANSPEC_BW_10;
1118                        break;
1119                default:
1120                        val = WL_CHANSPEC_BW_20;
1121                        nvram_set(strcat_r(prefix, "nbw", tmp), "20");
1122                }
1123                nbw = val;
1124
1125                /* Get Ctrl SB for 40MHz channel */
1126                if (nbw == WL_CHANSPEC_BW_40) {
1127                        str = nvram_safe_get(strcat_r(prefix, "nctrlsb", tmp));
1128
1129                        /* Adjust the channel to be center channel */
1130                        if (!strcmp(str, "lower")) {
1131                                nctrlsb = WL_CHANSPEC_CTL_SB_LOWER;
1132                                channel = channel + 2;
1133                        } else if (!strcmp(str, "upper")) {
1134                                nctrlsb = WL_CHANSPEC_CTL_SB_UPPER;
1135                                channel = channel - 2;
1136                        }
1137                }
1138
1139                /* band | BW | CTRL SB | Channel */
1140                fprintf(stderr,"%X, %X, %X\n",nbw,nctrlsb,channel);
1141                chanspec |= ((bandtype << WL_CHANSPEC_BAND_SHIFT) |
1142                             (nbw | nctrlsb | channel));
1143                fprintf(stderr,"spec %X\n",chanspec);
1144
1145                WL_IOVAR_SETINT(name, "chanspec", (uint32)chanspec);
1146        }
1147
1148cprintf("set rate set %s\n",name);
1149        /* Reset to hardware rateset (band may have changed) */
1150        WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof(wl_rateset_t));
1151        WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1152
1153cprintf("set g mode %s\n",name);
1154        /* Set gmode */
1155        if (bandtype == WLC_BAND_2G) {
1156                int override = WLC_G_PROTECTION_OFF;
1157                int control = WLC_G_PROTECTION_CTL_OFF;
1158
1159                /* Set gmode */
1160                gmode = atoi(nvram_default_get(strcat_r(prefix, "gmode", tmp),"1"));
1161                WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode));
1162
1163                /* Set gmode protection override and control algorithm */
1164                strcat_r(prefix, "gmode_protection", tmp);
1165                if (nvram_default_match(tmp, "auto","auto")) {
1166                        override = WLC_G_PROTECTION_AUTO;
1167                        control = WLC_G_PROTECTION_CTL_OVERLAP;
1168                }
1169                WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override));
1170                WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control));
1171        }
1172
1173cprintf("set n prot mode %s\n",name);
1174        /* Set nmode_protectoin */
1175        if (phytype == PHY_TYPE_N) {
1176                int override = WLC_PROTECTION_OFF;
1177                int control = WLC_PROTECTION_CTL_OFF;
1178                int nmode = AUTO;
1179
1180                /* Set n mode */
1181
1182
1183                strcat_r(prefix, "nreqd", tmp);
1184                if (nvram_default_match(tmp, "0","0"))
1185                        nmode = 0;
1186                if (nvram_match(tmp, "1"))
1187                        nmode = 1;
1188                WL_IOVAR_SETINT(name, "nreqd", (uint32)nmode);
1189
1190                strcat_r(prefix, "nmode", tmp);
1191                if (nvram_default_match(tmp, "0","-1"))
1192                        nmode = OFF;
1193                if (nvram_match(tmp, "-1"))
1194                        nmode = AUTO;
1195                if (nvram_match(tmp, "2"))
1196                        nmode = WL_NMODE_NONLY;
1197                WL_IOVAR_SETINT(name, "nmode", (uint32)nmode);
1198
1199                /* Set n protection override and control algorithm */
1200                strcat_r(prefix, "nmode_protection", tmp);
1201
1202                if (nvram_default_match(tmp, "auto","auto")) {
1203                        override = WLC_PROTECTION_AUTO;
1204                        control = WLC_PROTECTION_CTL_OVERLAP;
1205                }
1206
1207                memset(buf, 0, WLC_IOCTL_MAXLEN);
1208                strcpy(buf, "nmode_protection_override");
1209                buflen = strlen(buf) + 1;
1210
1211                val_ptr = (uint32*)(buf + buflen);
1212                buflen += sizeof(override);
1213                memcpy(val_ptr, &override, sizeof(override));
1214                WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
1215                WL_IOCTL(name, WLC_SET_PROTECTION_CONTROL, &control, sizeof(control));
1216        }
1217
1218        /* Set WME mode */
1219        /* This needs to be done before afterburner as wme has precedence
1220         *   -disable afterburner mode to allow any wme mode be configured
1221         *   -set wme mode before set afterburner mode
1222         */
1223cprintf("set afterburner override %s\n",name);
1224        val = OFF;
1225        strcpy(var, "afterburner_override");
1226        wl_iovar_setint(name, var, val);
1227        wme = nvram_default_get(strcat_r(prefix, "wme", tmp),"on");
1228        val = strcmp(wme, "on") ? 0 : 1;
1229cprintf("set wme %s\n",name);
1230        wl_iovar_set(name, "wme", &val, sizeof(val));
1231        if (val)
1232                wlconf_set_wme(name, prefix);
1233
1234cprintf("set btc mode %s\n",name);
1235        /* Get bluetootch coexistance(BTC) mode */
1236        btc_mode = atoi(nvram_default_get(strcat_r(prefix, "btc_mode", tmp),"0"));
1237
1238        /* Set options based on capability */
1239cprintf("get caps %s\n",name);
1240        wl_iovar_get(name, "cap", (void *)tmp, 100);
1241        foreach(var, tmp, next) {
1242                bool valid_option = FALSE;
1243                char *nvram_str = nvram_get(strcat_r(prefix, var, buf));
1244
1245                if (!nvram_str)
1246                        continue;
1247
1248                if (!strcmp(nvram_str, "on"))
1249                        val = ON;
1250                else if (!strcmp(nvram_str, "off"))
1251                        val = OFF;
1252                else if (!strcmp(nvram_str, "auto"))
1253                        val = AUTO;
1254                else
1255                        continue;
1256
1257                if (btc_mode != WL_BTC_PREMPT && strncmp(var, "afterburner", sizeof(var)) == 0) {
1258                        if (val == ON || val == OFF || val == AUTO)
1259                                valid_option = TRUE;
1260                        strcpy(var, "afterburner_override");
1261                }
1262                if ((strncmp(var, "amsdu", sizeof(var)) == 0) ||
1263                    (strncmp(var, "ampdu", sizeof(var)) == 0)) {
1264                        if (val == ON || val == OFF || val == AUTO)
1265                                valid_option = TRUE;
1266                }
1267                if (valid_option)
1268                        wl_iovar_setint(name, var, val);
1269        }
1270
1271        /* Get current rateset (gmode may have changed) */
1272        WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof(wl_rateset_t));
1273
1274        strcat_r(prefix, "rateset", tmp);
1275        if (nvram_default_match(tmp, "all","default"))  {
1276                /* Make all rates basic */
1277                for (i = 0; i < rs.count; i++)
1278                        rs.rates[i] |= 0x80;
1279        } else if (nvram_match(tmp, "12")) {
1280                /* Make 1 and 2 basic */
1281                for (i = 0; i < rs.count; i++) {
1282                        if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4)
1283                                rs.rates[i] |= 0x80;
1284                        else
1285                                rs.rates[i] &= ~0x80;
1286                }
1287        }
1288cprintf("set btc mode %s\n",name);
1289
1290        /* Set BTC mode */
1291        if (!wl_iovar_setint(name, "btc_mode", btc_mode)) {
1292                if (btc_mode == WL_BTC_PREMPT) {
1293                        wl_rateset_t rs_tmp = rs;
1294                        /* remove 1Mbps and 2 Mbps from rateset */
1295                        for (i = 0, rs.count = 0; i < rs_tmp.count; i++) {
1296                                if ((rs_tmp.rates[i] & 0x7f) == 2 || (rs_tmp.rates[i] & 0x7f) == 4)
1297                                        continue;
1298                                rs.rates[rs.count++] = rs_tmp.rates[i];
1299                        }
1300                }
1301        }
1302
1303cprintf("set rate set %s\n",name);
1304        /* Set rateset */
1305        WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof(wl_rateset_t));
1306
1307cprintf("set plcphdr %s\n",name);
1308        /* Allow short preamble override for b cards */
1309        if (phytype == PHY_TYPE_B ||
1310            (phytype == PHY_TYPE_G && (gmode == GMODE_LEGACY_B || gmode == GMODE_AUTO))) {
1311                strcat_r(prefix, "plcphdr", tmp);
1312                if (nvram_default_match(tmp, "long","long"))
1313                        val = WLC_PLCP_AUTO;
1314                else
1315                        val = WLC_PLCP_SHORT;
1316                WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val));
1317        }
1318
1319        /* Set rate in 500 Kbps units */
1320        val = atoi(nvram_default_get(strcat_r(prefix, "rate", tmp),"0")) / 500000;
1321
1322
1323        /* Convert Auto mcsidx to Auto rate */
1324        if (phytype == PHY_TYPE_N) {
1325                int mcsidx = atoi(nvram_default_get(strcat_r(prefix, "nmcsidx", tmp),"-1"));
1326                /* -1 mcsidx used to designate AUTO rate */
1327                if (mcsidx == -1)
1328                        val = 0;
1329        }
1330
1331        /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1332        if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1333                /* Must b/g band.  Set to 5.5Mbps */
1334                val = 11;
1335
1336cprintf("set get rates %s\n",name);
1337        /* it is band-blind. try both band */
1338        error_bg = wl_iovar_setint(name, "bg_rate", val);
1339        error_a = wl_iovar_setint(name, "a_rate", val);
1340
1341        if (error_bg && error_a) {
1342                /* both failed. Try default rate (card may have changed) */
1343                val = 0;
1344
1345                error_bg = wl_iovar_setint(name, "bg_rate", val);
1346                error_a = wl_iovar_setint(name, "a_rate", val);
1347
1348                snprintf(buf, sizeof(buf), "%d", val);
1349                nvram_set(strcat_r(prefix, "rate", tmp), buf);
1350        }
1351
1352        /* For N-Phy, check if nrate needs to be applied */
1353        if (phytype == PHY_TYPE_N) {
1354                uint32 nrate = 0;
1355                int mcsidx = atoi(nvram_safe_get(strcat_r(prefix, "nmcsidx", tmp)));
1356                bool ismcs = (mcsidx >= 0);
1357                uint nbw  = atoi(nvram_safe_get(strcat_r(prefix, "nbw", tmp)));
1358
1359                /* mcsidx of 32 is valid only for 40 Mhz */
1360                if (mcsidx == 32 && nbw == 20) {
1361                        mcsidx =  -1;
1362                        ismcs = FALSE;
1363                        nvram_set(strcat_r(prefix, "nmcsidx", tmp), "-1");
1364                }
1365
1366                /* Use nrate iovar only for MCS rate. */
1367                if (ismcs) {
1368                        nrate |= NRATE_MCS_INUSE;
1369                        nrate |= mcsidx & NRATE_RATE_MASK;
1370
1371                        memset(buf, 0, WLC_IOCTL_MAXLEN);
1372                        strcpy(buf, "nrate");
1373                        buflen = strlen(buf) + 1;
1374
1375                        val_ptr = (uint32*)(buf + buflen);
1376                        buflen += sizeof(nrate);
1377                        memcpy(val_ptr, &nrate, sizeof(nrate));
1378                        WL_IOCTL(name, WLC_SET_VAR, buf, sizeof(buf));
1379                }
1380        }
1381
1382cprintf("set mrates %s\n",name);
1383        /* Set multicast rate in 500 Kbps units */
1384        val = atoi(nvram_default_get(strcat_r(prefix, "mrate", tmp),"0")) / 500000;
1385        /* 1Mbps and 2 Mbps are not allowed in BTC pre-emptive mode */
1386        if (btc_mode == WL_BTC_PREMPT && (val == 2 || val == 4))
1387                /* Must b/g band.  Set to 5.5Mbps */
1388                val = 11;
1389
1390        /* it is band-blind. try both band */
1391        error_bg = wl_iovar_setint(name, "bg_mrate", val);
1392        error_a = wl_iovar_setint(name, "a_mrate", val);
1393
1394        if (error_bg && error_a) {
1395                /* Try default rate (card may have changed) */
1396                val = 0;
1397
1398                wl_iovar_setint(name, "bg_mrate", val);
1399                wl_iovar_setint(name, "a_mrate", val);
1400
1401                snprintf(buf, sizeof(buf), "%d", val);
1402                nvram_set(strcat_r(prefix, "mrate", tmp), buf);
1403        }
1404
1405cprintf("set frag tres %s\n",name);
1406        /* Set fragmentation threshold */
1407        val = atoi(nvram_default_get(strcat_r(prefix, "frag", tmp),"2346"));
1408        wl_iovar_setint(name, "fragthresh", val);
1409
1410        /* Set RTS threshold */
1411        val = atoi(nvram_default_get(strcat_r(prefix, "rts", tmp),"2347"));
1412        wl_iovar_setint(name, "rtsthresh", val);
1413
1414        /* Set DTIM period */
1415        val = atoi(nvram_default_get(strcat_r(prefix, "dtim", tmp),"1"));
1416        WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val));
1417
1418        /* Set beacon period */
1419        val = atoi(nvram_default_get(strcat_r(prefix, "bcn", tmp),"100"));
1420        WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val));
1421
1422cprintf("set wds %s\n",name);
1423        /* AP only config */
1424        if (ap || apsta || wds) {
1425                /* Set lazy WDS mode */
1426                val = atoi(nvram_default_get(strcat_r(prefix, "lazywds", tmp),"0"));
1427                WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val));
1428
1429                /* Set the WDS list */
1430                maclist = (struct maclist *) buf;
1431                maclist->count = 0;
1432                ea = maclist->ea;
1433                foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
1434                        if (((char *)(ea->octet)) > ((char *)(&buf[sizeof(buf)])))
1435                                break;
1436                        ether_atoe(var, ea->octet);
1437                        maclist->count++;
1438                        ea++;
1439                }
1440                WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
1441
1442                /* Set WDS link detection timeout */
1443                val = atoi(nvram_safe_get(strcat_r(prefix, "wds_timeout", tmp)));
1444                wl_iovar_setint(name, "wdstimeout", val);
1445        }
1446
1447cprintf("set wframeburst %s\n",name);
1448        /* Set framebursting mode */
1449        if (btc_mode == WL_BTC_PREMPT)
1450                val = FALSE;
1451        else
1452                val = nvram_default_match(strcat_r(prefix, "frameburst", tmp), "on","off");
1453        WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val));
1454
1455cprintf("set rifs mode %s\n",name);
1456        /* Set RIFS mode based on framebursting */
1457        if (phytype == PHY_TYPE_N) {
1458                char *nvram_str = nvram_safe_get(strcat_r(prefix, "rifs", tmp));
1459                if (!strcmp(nvram_str, "on"))
1460                        wl_iovar_setint(name, "rifs", ON);
1461                else if (!strcmp(nvram_str, "off"))
1462                        wl_iovar_setint(name, "rifs", OFF);
1463        }
1464
1465cprintf("set ba mode %s\n",name);
1466        /* Override BA mode only if set to on/off */
1467        ba = nvram_safe_get(strcat_r(prefix, "ba", tmp));
1468        if (!strcmp(ba, "on"))
1469                wl_iovar_setint(name, "ba", ON);
1470        else if (!strcmp(ba, "off"))
1471                wl_iovar_setint(name, "ba", OFF);
1472
1473cprintf("set up %s\n",name);
1474        /* Bring the interface back up */
1475        WL_IOCTL(name, WLC_UP, NULL, 0);
1476
1477cprintf("set antdiv mode %s\n",name);
1478        /* Set antenna */
1479        val = atoi(nvram_default_get(strcat_r(prefix, "antdiv", tmp),"3"));
1480        WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val));
1481
1482        /* Auto Channel Selection - when channel # is 0 in AP mode
1483         *
1484         * The following condition(s) must be met in order for
1485         * Auto Channel Selection to work.
1486         *  - the I/F must be up for the channel scan
1487         *  - the AP must not be supporting a BSS (all BSS Configs must be disabled)
1488         */
1489        if (ap || apsta) {
1490                if (!(val = atoi(nvram_default_get(strcat_r(prefix, "channel", tmp),"0")))) {
1491                        if (phytype == PHY_TYPE_N) {
1492                                chanspec_t chanspec = wlconf_auto_chanspec(name,prefix);
1493                                if (chanspec != 0)
1494                                        {
1495//                                      fprintf(stderr,"auto chanspec %X\n",chanspec);
1496                                        WL_IOVAR_SETINT(name, "chanspec", chanspec);
1497                                        }
1498                        }
1499                        else {
1500                                /* select a channel */
1501                                val = wlconf_auto_channel(name);
1502                                /* switch to the selected channel */
1503                                if (val != 0)
1504                                        WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
1505                        }
1506                        /* set the auto channel scan timer in the driver when in auto mode */
1507                        val = 15;       /* 15 minutes for now */
1508                        WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1509                }
1510                else {
1511                        /* reset the channel scan timer in the driver when not in auto mode */
1512                        val = 0;
1513                        WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
1514                }
1515        }
1516
1517        /* Security settings for each BSS Configuration */
1518        for (i = 0; i < bclist->count; i++) {
1519                bsscfg = &bclist->bsscfgs[i];
1520                wlconf_security_options(name, bsscfg->prefix, bsscfg->idx, wet);
1521        }
1522
1523        /*
1524         * Finally enable BSS Configs or Join BSS
1525         *
1526         * AP: Enable BSS Config to bring AP up only when nas will not run
1527         * STA: Join the BSS regardless.
1528         */
1529        for (i = 0; i < bclist->count; i++) {
1530                struct {int bsscfg_idx; int enable;} setbuf;
1531
1532                setbuf.bsscfg_idx = bclist->bsscfgs[i].idx;
1533                setbuf.enable = 1;
1534
1535                /* NAS runs if we have an AKM or radius authentication */
1536                nas_will_run = wlconf_akm_options(bclist->bsscfgs[i].prefix) ||
1537                        nvram_default_match(strcat_r(bclist->bsscfgs[i].prefix, "auth_mode", tmp),
1538                                    "radius","disabled");
1539
1540                if (((ap || apsta) && !nas_will_run) || sta || wet) {
1541                        for (ii = 0; ii < MAX_BSS_UP_RETRIES; ii++) {
1542                                if (wl_ap_build) {
1543                                        WL_IOVAR_SET(name, "bss", &setbuf, sizeof(setbuf));
1544                                }
1545                                else {
1546                                        strcat_r(prefix, "ssid", tmp);
1547                                        ssid.SSID_len = strlen(nvram_safe_get(tmp));
1548                                        if (ssid.SSID_len > sizeof(ssid.SSID))
1549                                                ssid.SSID_len = sizeof(ssid.SSID);
1550                                        strncpy((char *)ssid.SSID, nvram_safe_get(tmp),
1551                                                ssid.SSID_len);
1552                                        WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1553                                }
1554                                if (apsta && (ret != 0))
1555                                        sleep_ms(1000);
1556                                else
1557                                        break;
1558                        }
1559                }
1560        }
1561
1562        ret = 0;
1563exit:
1564        if (bclist != NULL)
1565                free(bclist);
1566
1567        return ret;
1568}
1569
1570int
1571wlconf_down(char *name)
1572{
1573        int val, ret = 0;
1574        int i;
1575        int wlsubunit;
1576        int bcmerr;
1577        unsigned char buf[WLC_IOCTL_MAXLEN];
1578        struct maclist *maclist;
1579        struct {int bsscfg_idx; int enable;} setbuf;
1580        int wl_ap_build = 0; /* 1 = wl compiled with AP capabilities */
1581        char cap[WLC_IOCTL_SMLEN];
1582        char caps[WLC_IOCTL_SMLEN];
1583        char *next;
1584        wlc_ssid_t ssid;
1585
1586        /* wlconf doesn't work for virtual i/f */
1587        if (get_ifname_unit(name, NULL, &wlsubunit) == 0 && wlsubunit >= 0) {
1588                WLCONF_DBG("wlconf: skipping virtual interface \"%s\"\n", name);
1589                return 0;
1590        }
1591
1592        /* Check interface (fail silently for non-wl interfaces) */
1593        if ((ret = wl_probe(name)))
1594                return ret;
1595
1596        /* because of ifdefs in wl driver,  when we don't have AP capabilities we
1597         * can't use the same iovars to configure the wl.
1598         * so we use "wl_ap_build" to help us know how to configure the driver
1599         */
1600        if (wl_iovar_get(name, "cap", (void *)caps, WLC_IOCTL_SMLEN))
1601                return -1;
1602
1603        foreach(cap, caps, next) {
1604                if (!strcmp(cap, "ap")) {
1605                        wl_ap_build = 1;
1606                }
1607        }
1608
1609        if (wl_ap_build) {
1610                /* Bring down the interface */
1611                WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1612
1613                /* Disable all BSS Configs */
1614                for (i = 0; i < WL_MAXBSSCFG; i++) {
1615                        setbuf.bsscfg_idx = i;
1616                        setbuf.enable = 0;
1617
1618                        ret = wl_iovar_set(name, "bss", &setbuf, sizeof(setbuf));
1619                        if (ret) {
1620                                wl_iovar_getint(name, "bcmerror", &bcmerr);
1621                                /* fail quietly on a range error since the driver may
1622                                 * support fewer bsscfgs than we are prepared to configure
1623                                 */
1624                                if (bcmerr == BCME_RANGE)
1625                                        break;
1626                        }
1627                }
1628        }
1629        else {
1630                WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
1631                if (val) {
1632                        /* Nuke SSID  */
1633                        ssid.SSID_len = 0;
1634                        ssid.SSID[0] = '\0';
1635                        WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
1636
1637                        /* Bring down the interface */
1638                        WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
1639                }
1640        }
1641
1642        /* Nuke the WDS list */
1643        maclist = (struct maclist *) buf;
1644        maclist->count = 0;
1645        WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
1646
1647        return 0;
1648}
1649
1650#if defined(linux)
1651int
1652main(int argc, char *argv[])
1653{
1654        /* Check parameters and branch based on action */
1655        if (argc == 3 && !strcmp(argv[2], "up"))
1656                return wlconf(argv[1]);
1657        else if (argc == 3 && !strcmp(argv[2], "down"))
1658                return wlconf_down(argv[1]);
1659        else {
1660                fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
1661                return -1;
1662        }
1663}
1664#endif
Note: See TracBrowser for help on using the repository browser.