will be removed as soon as we have another solution, seems to be compatible with...
[15.05/openwrt.git] / package / openwrt / wlconf.c
1 /* 
2  * no license, extracted from wag54gv2-AU_v1.00.39 GPL
3  * 
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10
11 #include <typedefs.h>
12 #include <bcmnvram.h>
13 #include <bcmutils.h>
14 #include <shutils.h>
15 #include <wlutils.h>
16
17 /* phy types */
18 #define PHY_TYPE_A              0
19 #define PHY_TYPE_B              1
20 #define PHY_TYPE_G              2
21 #define PHY_TYPE_NULL           0xf
22
23 /* parts of an idcode: */
24 #define IDCODE_MFG_MASK         0x00000fff
25 #define IDCODE_MFG_SHIFT        0
26 #define IDCODE_ID_MASK          0x0ffff000
27 #define IDCODE_ID_SHIFT         12
28 #define IDCODE_REV_MASK         0xf0000000
29 #define IDCODE_REV_SHIFT        28
30
31 #define WL_IOCTL(name, cmd, buf, len) ((void) wl_ioctl((name), (cmd), (buf), (len)))
32
33 /* set WEP key */
34 static int
35 wlconf_set_wep_key(char *name, char *prefix, int i)
36 {
37         wsec_key_t key;
38         char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
39         char *keystr, hex[] = "XX";
40         unsigned char *data = key.data;
41         int ret = 0;
42
43         memset(&key, 0, sizeof(key));
44         key.index = i - 1;
45         sprintf(wl_key, "%skey%d", prefix, i);
46         keystr = nvram_safe_get(wl_key);
47
48         switch (strlen(keystr)) {
49         case WEP1_KEY_SIZE:
50         case WEP128_KEY_SIZE:
51                 key.len = strlen(keystr);
52                 strcpy(key.data, keystr);
53                 break;
54         case WEP1_KEY_HEX_SIZE:
55         case WEP128_KEY_HEX_SIZE:
56                 key.len = strlen(keystr) / 2;
57                 while (*keystr) {
58                         strncpy(hex, keystr, 2);
59                         *data++ = (unsigned char) strtoul(hex, NULL, 16);
60                         keystr += 2;
61                 }
62                 break;
63         default:
64                 key.len = 0;
65                 break;
66         }
67
68         /* Set current WEP key */
69         if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key))))
70                 key.flags = WSEC_PRIMARY_KEY;
71
72         WL_IOCTL(name, WLC_SET_KEY, &key, sizeof(key));
73
74         return ret;
75 }
76
77 extern struct nvram_tuple router_defaults[];
78
79 /* Keep this table in order */
80 static struct {
81         int locale;
82         char **names;
83         char *abbr;
84 } countries[] = {
85         { WLC_WW,  ((char *[]) { "Worldwide", "WW", NULL }), "AU" },
86         { WLC_THA, ((char *[]) { "Thailand", "THA", NULL }), "TH" },
87         { WLC_ISR, ((char *[]) { "Israel", "ISR", NULL }), "IL" },
88         { WLC_JDN, ((char *[]) { "Jordan", "JDN", NULL }), "JO" },
89         { WLC_PRC, ((char *[]) { "China", "P.R. China", "PRC", NULL }), "CN" },
90         { WLC_JPN, ((char *[]) { "Japan", "JPN", NULL }), "JP" },
91         { WLC_FCC, ((char *[]) { "USA", "Canada", "ANZ", "New Zealand", "FCC", NULL }), "US" },
92         { WLC_EUR, ((char *[]) { "Europe", "EUR", NULL }), "DE" },
93         { WLC_USL, ((char *[]) { "USA Low", "USALow", "USL", NULL }), "US" },
94         { WLC_JPH, ((char *[]) { "Japan High", "JapanHigh", "JPH", NULL }), "JP" },
95         { WLC_ALL, ((char *[]) { "All", "AllTheChannels", NULL }), "All" },
96 };
97
98 /* validate/restore all per-interface related variables */
99 static void
100 wlconf_validate_all(char *prefix, bool restore)
101 {
102         struct nvram_tuple *t;
103         char tmp[100];
104         char *v;
105         for (t = router_defaults; t->name; t++) {
106                 if (!strncmp(t->name, "wl_", 3)) {
107                         strcat_r(prefix, &t->name[3], tmp);
108                         if (!restore && nvram_get(tmp))
109                                 continue;
110                         v = nvram_get(t->name);
111                         nvram_set(tmp, v ? v : t->value);
112                 }
113         }
114 }
115
116 /* restore specific per-interface variable */
117 static void
118 wlconf_restore_var(char *prefix, char *name)
119 {
120         struct nvram_tuple *t;
121         char tmp[100];
122         for (t = router_defaults; t->name; t++) {
123                 if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) {
124                         nvram_set(strcat_r(prefix, name, tmp), t->value);
125                         break;
126                 }
127         }
128 }
129
130 /* Set up wsec */
131 static int
132 wlconf_set_wsec(char *ifname, char *prefix)
133 {
134         char tmp[100];
135         int val;
136         strcat_r(prefix, "wep", tmp);
137         if (nvram_match(tmp, "wep") || nvram_match(tmp, "on") || nvram_match(tmp, "restricted"))
138                 val = WEP_ENABLED;
139         else if (nvram_match(tmp, "tkip"))
140                 val = TKIP_ENABLED;
141         else if (nvram_match(tmp, "aes"))
142                 val = AES_ENABLED;
143         else if (nvram_match(tmp, "tkip+aes"))
144                 val = TKIP_ENABLED | AES_ENABLED;
145         else
146                 val = 0;
147         return wl_ioctl(ifname, WLC_SET_WSEC, &val, sizeof(val));
148 }
149
150 /*
151 * For debugging only
152 */
153 #define WLCONF_DBG(fmt, arg...)
154
155 #if defined(linux)
156 #include <unistd.h>
157 static void
158 sleep_ms(const unsigned int ms)
159 {
160         usleep(1000*ms);
161 }
162 #endif
163
164 /*
165 * The following condition(s) must be met when Auto Channel Selection 
166 * is enabled.
167 *  - the I/F is up (change radio channel requires it is up?)
168 *  - the AP must not be associated (setting SSID to empty should 
169 *    make sure it for us)
170 */
171 static uint8
172 wlconf_auto_channel(char *name)
173 {
174         int chosen = 0;
175         wl_uint32_list_t request;
176         int phytype;
177         /* query the phy type */
178         wl_ioctl(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
179         request.count = 0;      /* let the ioctl decide */
180         if (!wl_ioctl(name, WLC_START_CHANNEL_SEL, &request, sizeof(request))) {
181                 sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
182                 while (wl_ioctl(name, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)))
183                         sleep_ms(100);
184         }
185         WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
186         return chosen;
187 }
188
189 /* PHY type/BAND conversion */
190 #define WLCONF_PHYTYPE2BAND(phy)        ((phy) == PHY_TYPE_A ? WLC_BAND_A : WLC_BAND_B)
191 /* PHY type conversion */
192 #define WLCONF_PHYTYPE2STR(phy) ((phy) == PHY_TYPE_A ? "a" : \
193                                  (phy) == PHY_TYPE_B ? "b" : "g")
194 #define WLCONF_STR2PHYTYPE(phy) ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
195                                  (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : PHY_TYPE_G)
196                                  
197 /* configure the specified wireless interface */
198 int
199 wlconf(char *name)
200 {
201         int restore_defaults, val, unit, phytype, gmode = 0, ret = 0;
202         char tmp[100], prefix[] = "wlXXXXXXXXXX_";
203         char var[80], *next, phy[] = "a", *str;
204         unsigned char buf[WLC_IOCTL_MAXLEN];
205         char *country;
206         wlc_rev_info_t rev;
207         channel_info_t ci;
208         struct maclist *maclist;
209         struct ether_addr *ea;
210         wlc_ssid_t ssid;
211         wl_rateset_t rs;
212         unsigned int i;
213         char eaddr[32];
214         int ap, sta = 0, wet = 0;
215         char country_code[4];
216
217         /* Check interface (fail silently for non-wl interfaces) */
218         if ((ret = wl_probe(name)))
219                 return ret;
220
221         /* Get MAC address */
222         (void) wl_hwaddr(name, buf);
223
224         /* Get instance */
225         WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit));
226         snprintf(prefix, sizeof(prefix), "wl%d_", unit);
227
228         /* Restore defaults if per-interface parameters do not exist */
229         restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
230         wlconf_validate_all(prefix, restore_defaults);
231         nvram_set(strcat_r(prefix, "ifname", tmp), name);
232         nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa(buf, eaddr));
233         snprintf(buf, sizeof(buf), "%d", unit);
234         nvram_set(strcat_r(prefix, "unit", tmp), buf);
235
236         /*
237         * Nuke SSID first so that the AP won't be associated when WLC_UP.
238         * This must be done here if Auto Channel Selection is enabled.
239         */
240         WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
241         if (val) {
242                 /* Nuke SSID  */
243                 ssid.SSID_len = 0;
244                 ssid.SSID[0] = '\0';
245                 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
246
247                 /* Bring the interface down */
248                 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
249         }
250
251         /* Set mode : AP, STA */
252         ap = nvram_match(strcat_r(prefix, "mode", tmp), "ap");
253         val = (ap + nvram_match(strcat_r(prefix, "mode", tmp), "wds")) ? 1 : 0;
254         WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val));
255
256         /* Set STA specific parameters */
257         if (!ap) {
258                 /* Set mode: WET */
259                 if ((wet = nvram_match(strcat_r(prefix, "mode", tmp), "wet")))
260                         WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet));
261                 /* Set infra: BSS/IBSS */
262                 if (wet || (sta = nvram_match(strcat_r(prefix, "mode", tmp), "sta"))) {
263                         val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp)));
264                         WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val));
265                 }
266         }
267
268         /* Set network type */
269         val = atoi(nvram_safe_get(strcat_r(prefix, "closed", tmp)));
270         WL_IOCTL(name, WLC_SET_CLOSED, &val, sizeof(val));
271
272         /* Set up the country code */
273         (void) strcat_r(prefix, "country_code", tmp);
274         country = nvram_get(tmp);
275         if (country) {
276                 strncpy(country_code, country, sizeof(country_code));
277                 WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
278         }
279         else {
280                 /* If country_code doesn't exist, check for country to be backward compatible */
281                 (void) strcat_r(prefix, "country", tmp);
282                 country = nvram_safe_get(tmp);
283                 for (val = 0; val < ARRAYSIZE(countries); val++) {
284                         char **synonym;
285                         for (synonym = countries[val].names; *synonym; synonym++)
286                                 if (!strcmp(country, *synonym))
287                                         break;
288                         if (*synonym)
289                                 break;
290                 }
291
292                 /* Get the default country code if undefined or invalid and set the NVRAM */
293                 if (val >= ARRAYSIZE(countries)) {
294                         WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code));
295                 }
296                 else {
297                         strncpy(country_code, countries[val].abbr, sizeof(country_code));
298                         WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
299                 }
300
301                 /* Add the new NVRAM variable */
302                 nvram_set("wl_country_code", country_code);
303                 (void) strcat_r(prefix, "country_code", tmp);
304                 nvram_set(tmp, country_code);
305         }
306         
307         /* Set the MAC list */
308         maclist = (struct maclist *) buf;
309         maclist->count = 0;
310         if (!nvram_match(strcat_r(prefix, "macmode", tmp), "disabled")) {
311                 ea = maclist->ea;
312                 foreach(var, nvram_safe_get(strcat_r(prefix, "maclist", tmp)), next) {
313                         if ((&ea[1])->octet > &buf[sizeof(buf)])
314                                 break;
315                         if (ether_atoe(var, ea->octet)) {
316                                 maclist->count++;
317                                 ea++;
318                         }
319                 }
320         }
321         WL_IOCTL(name, WLC_SET_MACLIST, buf, sizeof(buf));
322
323         /* Set the MAC list mode */
324         (void) strcat_r(prefix, "macmode", tmp);
325         if (nvram_match(tmp, "deny"))
326                 val = WLC_MACMODE_DENY;
327         else if (nvram_match(tmp, "allow"))
328                 val = WLC_MACMODE_ALLOW;
329         else
330                 val = WLC_MACMODE_DISABLED;
331         WL_IOCTL(name, WLC_SET_MACMODE, &val, sizeof(val));
332
333         /* Enable or disable the radio */
334         val = nvram_match(strcat_r(prefix, "radio", tmp), "0");
335         WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
336
337         /* Get supported phy types */
338         WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var));
339         nvram_set(strcat_r(prefix, "phytypes", tmp), var);
340
341         /* Get radio IDs */
342         *(next = buf) = '\0';
343         for (i = 0; i < strlen(var); i++) {
344                 /* Switch to band */
345                 phy[0] = var[i];
346                 val = WLCONF_STR2PHYTYPE(phy);
347                 val = WLCONF_PHYTYPE2BAND(val);
348                 WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
349                 /* Get radio ID on this band */
350                 WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
351                 next += sprintf(next, "%sBCM%X", i ? " " : "",
352                                 (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT);
353         }
354         nvram_set(strcat_r(prefix, "radioids", tmp), buf);
355
356         /* Set band */
357         str = nvram_get(strcat_r(prefix, "phytype", tmp));
358         val = WLCONF_STR2PHYTYPE(str);
359         val = WLCONF_PHYTYPE2BAND(val);
360         /* Check errors (card may have changed) */
361         if (wl_ioctl(name, WLC_SET_BAND, &val, sizeof(val))) {
362                 /* default band to the first band in band list */
363                 phy[0] = var[0];
364                 val = WLCONF_STR2PHYTYPE(phy);
365                 val = WLCONF_PHYTYPE2BAND(val);
366                 WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
367         }
368
369         /* Get current core revision */
370         WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
371         snprintf(buf, sizeof(buf), "%d", rev.corerev);
372         nvram_set(strcat_r(prefix, "corerev", tmp), buf);
373
374         /* Get current phy type */
375         WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
376         snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype));
377         nvram_set(strcat_r(prefix, "phytype", tmp), buf);
378
379         /* Set channel before setting gmode or rateset */
380         /* Manual Channel Selection - when channel # is not 0 */
381         val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp)));
382         if (val) {
383                 if (wl_ioctl(name, WLC_SET_CHANNEL, &val, sizeof(val))) {
384                         /* Use current channel (card may have changed) */
385                         WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
386                         snprintf(buf, sizeof(buf), "%d", ci.target_channel);
387                         nvram_set(strcat_r(prefix, "channel", tmp), buf);
388                 }
389         }
390         
391         /* Reset to hardware rateset (band may have changed) */
392         WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof (wl_rateset_t));
393         WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof (wl_rateset_t));
394
395         /* Set gmode */
396         if (phytype == PHY_TYPE_G) {
397
398                 /* Set gmode */
399
400                 gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp)));
401                 if (gmode == GMODE_AFTERBURNER) {
402                         if (wl_get_int(name, "abcap", &val) || !val) {
403                                 gmode = GMODE_AUTO;
404                                 snprintf(buf, sizeof(buf), "%d", gmode);
405                                 nvram_set(tmp, buf);
406                         }
407                 }
408                 WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode));
409
410                 /* Set gmode protection override and control algorithm */
411                 if (gmode != GMODE_AFTERBURNER) {
412                         int override = WLC_G_PROTECTION_OFF;
413                         int control = WLC_G_PROTECTION_CTL_OFF;
414                         strcat_r(prefix, "gmode_protection", tmp);
415                         if (nvram_match(tmp, "auto")) {
416                                 override = WLC_G_PROTECTION_AUTO;
417                                 control = WLC_G_PROTECTION_CTL_OVERLAP;
418                         }
419                         WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override));
420                         WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control));
421                 }
422         }
423
424         /* Get current rateset (gmode may have changed) */
425         WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof (wl_rateset_t));
426
427         strcat_r(prefix, "rateset", tmp);
428         if (nvram_match(tmp, "all"))  {
429                 /* Make all rates basic */
430                 for (i = 0; i < rs.count; i++)
431                         rs.rates[i] |= 0x80;
432         } else if (nvram_match(tmp, "12")) {
433                 /* Make 1 and 2 basic */
434                 for (i = 0; i < rs.count; i++) {
435                         if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4)
436                                 rs.rates[i] |= 0x80;
437                         else
438                                 rs.rates[i] &= ~0x80;
439                 }
440         }
441
442         /* Set rateset */
443         WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof (wl_rateset_t));
444
445         /* Allow short preamble override for b cards */
446         if (phytype == PHY_TYPE_B || gmode == 0) {
447                 strcat_r(prefix, "plcphdr", tmp);               
448                 if (nvram_match(tmp, "long"))
449                         val = WLC_PLCP_AUTO;
450                 else
451                         val = WLC_PLCP_SHORT;
452                 WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val));
453         }
454
455         /* Set rate in 500 Kbps units */
456         val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000;
457         if (wl_ioctl(name, WLC_SET_RATE, &val, sizeof(val))) {
458                 /* Try default rate (card may have changed) */
459                 val = 0;
460                 WL_IOCTL(name, WLC_SET_RATE, &val, sizeof(val));
461                 snprintf(buf, sizeof(buf), "%d", val);
462                 nvram_set(strcat_r(prefix, "rate", tmp), buf);
463         }
464
465         /* Set fragmentation threshold */
466         val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp)));
467         WL_IOCTL(name, WLC_SET_FRAG, &val, sizeof(val));
468
469         /* Set RTS threshold */
470         val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp)));
471         WL_IOCTL(name, WLC_SET_RTS, &val, sizeof(val));
472
473         /* Set DTIM period */
474         val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp)));
475         WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val));
476
477         /* Set beacon period */
478         val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp)));
479         WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val));
480
481         /* Set lazy WDS mode */
482         val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp)));
483         WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val));
484
485         /* Set the WDS list */
486         maclist = (struct maclist *) buf;
487         maclist->count = 0;
488         ea = maclist->ea;
489         foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
490                 if (ea->octet > &buf[sizeof(buf)])
491                         break;
492                 ether_atoe(var, ea->octet);
493                 maclist->count++;
494                 ea++;
495         }
496         WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
497
498         /* Set framebursting mode */
499         val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on");
500         WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val));
501         
502         /* Bring the interface back up */
503         WL_IOCTL(name, WLC_UP, NULL, 0);
504
505         /* Set antenna */
506         val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp)));
507         WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val));
508
509         /* Auto Channel Selection - when channel # is 0 in AP mode */
510         /*
511         * The following condition(s) must be met in order for 
512         * Auto Channel Selection to work.
513         *  - the I/F must be up (change radio channel requires it is up?)
514         *  - the AP must not be associated (setting SSID to empty should 
515         *    make sure it for us)
516         */
517         if (ap) {
518                 if (!(val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))))) {
519                         /* select a channel */
520                         val = wlconf_auto_channel(name);
521                         /* switch to the selected channel */
522                         WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
523                         /* set the auto channel scan timer in the driver when in auto mode */
524                         val = 15;       /* 15 minutes for now */
525                         WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
526                 }
527                 else {
528                         /* reset the channel scan timer in the driver when not in auto mode */
529                         val = 0;
530                         WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
531                 }
532         }
533
534         /* Set WEP keys */
535         for (i = 1; i <= WLC_MAX_DEFAULT_KEYS; i++)
536                 wlconf_set_wep_key(name, prefix, i);
537
538         /* Set WSEC */
539         /*
540         * Need to check errors (card may have changed) and change to
541         * defaults since the new chip may not support the requested 
542         * encryptions after the card has been changed.
543         */
544         if (wlconf_set_wsec(name, prefix)) {
545                 /* change nvram only, code below will pass them on */
546                 wlconf_restore_var(prefix, "auth_mode");
547                 wlconf_restore_var(prefix, "auth");
548                 /* reset wep to default */
549                 wlconf_restore_var(prefix, "wep");
550                 wlconf_set_wsec(name, prefix);
551         }
552
553         /* Set WPA authentication mode - radius/wpa/psk */
554         strcat_r(prefix, "auth_mode", tmp);
555         if (nvram_match(tmp, "radius"))
556                 val = WPA_AUTH_DISABLED;
557         else if (nvram_match(tmp, "wpa"))
558                 val = WPA_AUTH_UNSPECIFIED;
559         else if (nvram_match(tmp, "psk"))
560                 val = WPA_AUTH_PSK;
561         else /* if (nvram_match(tmp, "disabled")) */
562                 val = WPA_AUTH_DISABLED;
563         WL_IOCTL(name, WLC_SET_WPA_AUTH, &val, sizeof(val));
564         
565         /* Set non-WPA authentication mode - open/shared */
566         val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp)));
567         WL_IOCTL(name, WLC_SET_AUTH, &val, sizeof(val));
568
569         /* Set WEP restrict if WEP is not disabled */
570         val = nvram_invmatch(strcat_r(prefix, "wep", tmp), "off");
571         WL_IOCTL(name, WLC_SET_WEP_RESTRICT, &val, sizeof(val));
572
573         /* Set SSID/Join network */
574         if (ap | sta | wet) {
575                 strcat_r(prefix, "ssid", tmp);
576                 ssid.SSID_len = strlen(nvram_safe_get(tmp));
577                 if (ssid.SSID_len > sizeof(ssid.SSID))
578                         ssid.SSID_len = sizeof(ssid.SSID);
579                 strncpy(ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len);
580         } else {
581                 /* A zero length SSID turns off the AP */
582                 ssid.SSID_len = 0;
583                 ssid.SSID[0] = '\0';
584         }               
585         WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
586         
587         return 0;
588 }
589
590 int
591 wlconf_down(char *name)
592 {
593         int val, ret = 0;
594         unsigned char buf[WLC_IOCTL_MAXLEN];
595         struct maclist *maclist;
596         wlc_ssid_t ssid;
597
598         /* Check interface (fail silently for non-wl interfaces) */
599         if ((ret = wl_probe(name)))
600                 return ret;
601
602         /* Bring down the interface */
603         WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
604         if (val) {
605                 /* Nuke SSID  */
606                 ssid.SSID_len = 0;
607                 ssid.SSID[0] = '\0';
608                 WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
609
610                 /* Bring the interface down */
611                 WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
612         }
613
614         /* Nuke the WDS list */
615         maclist = (struct maclist *) buf;
616         maclist->count = 0;
617         WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
618
619         return 0;
620 }
621
622 int
623 main(int argc, char *argv[])
624 {
625         int ret = -1;
626         
627         /* Check parameters and branch based on action */
628         if (argc == 3 && !strcmp(argv[2], "up"))
629                 ret = wlconf(argv[1]);
630         else if (argc == 3 && !strcmp(argv[2], "down"))
631                 ret = wlconf_down(argv[1]);
632         else {
633                 fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
634                 return -1;
635         }
636         /* Check result */
637         if (ret) {
638                 fprintf(stderr, "wlconf: %s failed (%d)\n", argv[1], ret);
639                 return ret;
640         }
641         return 0;
642 }