will be removed as soon as we have another solution, seems to be compatible with...
authorWaldemar Brodkorb <mail@waldemar-brodkorb.de>
Wed, 1 Jun 2005 13:47:19 +0000 (13:47 +0000)
committerWaldemar Brodkorb <mail@waldemar-brodkorb.de>
Wed, 1 Jun 2005 13:47:19 +0000 (13:47 +0000)
SVN-Revision: 1128

openwrt/package/openwrt/Makefile
openwrt/package/openwrt/include/wlioctl.h
openwrt/package/openwrt/wlconf.c [new file with mode: 0755]

index 71edbee3af58d890ad4668bfe812da942fe4bf1b..73e7329dbf6343754646d5417f474b3f9d7c1791 100644 (file)
@@ -31,30 +31,11 @@ $(PKG_IPK_DIR)/usr/sbin/wlc: wlc.c libshared-install
        mkdir -p $(PKG_IPK_DIR)/usr/sbin
        $(TARGET_CC) -o $@ $< -lshared -L./libshared -I$(SHARED_INCLUDE)
 
-# wlconf tool extracted from linksys firmware GPL.unpackedtree
-# WRT54GS_3_37_2_1109_US
-LINKSYS_TGZ_SITE=http://openwrt.openbsd-geek.de
-LINKSYS_TGZ_MD5SUM=1b596e5bf26d2898d1eab5bd200bee58
-LINKSYS_WLCONF_TGZ=linksys-wlconf.tar.gz
-LINKSYS_WLCONF_DIR=$(BUILD_DIR)/linksys-wlconf
-
-$(DL_DIR)/$(LINKSYS_WLCONF_TGZ):
-       $(SCRIPT_DIR)/download.pl $(DL_DIR) $(LINKSYS_WLCONF_TGZ) $(LINKSYS_TGZ_MD5SUM) $(LINKSYS_TGZ_SITE)
-
-$(LINKSYS_WLCONF_DIR)/.unpacked: $(DL_DIR)/$(LINKSYS_WLCONF_TGZ)
-       zcat $(DL_DIR)/$(LINKSYS_WLCONF_TGZ) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
-       touch $(LINKSYS_WLCONF_DIR)/.unpacked
-       
-$(TARGET_DIR)/usr/sbin/wlconf: $(LINKSYS_WLCONF_DIR)/.unpacked 
-       $(MAKE) -C $(LINKSYS_WLCONF_DIR) INSTALLDIR=$(TARGET_DIR) \
-               CC=$(TARGET_CC) LD=$(TARGET_CROSS)ld STRIP="$(STRIP)" \
-               CFLAGS="$(TARGET_CFLAGS) -I. -I$(SHARED_INCLUDE) \
-                       -Wall -DOPENWRT_WLCONF" \
-               LDFLAGS="-lnvram -lshared" \
-                       install
-       $(STRIP) $@
+$(PKG_IPK_DIR)/usr/sbin/wlconf: wlconf.c libshared-install libnvram-install
+       mkdir -p $(PKG_IPK_DIR)/usr/sbin
+       $(TARGET_CC) -o $@ $< -lshared -L./libshared -lnvram -L./libnvram -I$(SHARED_INCLUDE)
 
-$(PKG_IPK): $(PKG_IPK_DIR)/sbin/mtd $(PKG_IPK_DIR)/sbin/jffs2root $(PKG_IPK_DIR)/usr/sbin/wlc
+$(PKG_IPK): $(PKG_IPK_DIR)/sbin/mtd $(PKG_IPK_DIR)/sbin/jffs2root $(PKG_IPK_DIR)/usr/sbin/wlc $(PKG_IPK_DIR)/usr/sbin/wlconf
        $(SCRIPT_DIR)/make-ipkg-dir.sh $(PKG_IPK_DIR) $(PKG_NAME).control $(PKG_RELEASE) $(ARCH)
        $(STRIP) $(PKG_IPK_DIR)/usr/sbin/*
        $(STRIP) $(PKG_IPK_DIR)/sbin/*
@@ -64,13 +45,12 @@ $(PKG_IPK): $(PKG_IPK_DIR)/sbin/mtd $(PKG_IPK_DIR)/sbin/jffs2root $(PKG_IPK_DIR)
 $(IPKG_STATE_DIR)/info/$(PKG_NAME).list: $(PKG_IPK)
        $(IPKG) install $<
 
-source: $(DL_DIR)/$(LINKSYS_WLCONF_TGZ)
-prepare: $(LINKSYS_WLCONF_DIR)/.unpacked
+source: 
+prepare: 
 compile: prepare libnvram-compile libshared-compile $(PKG_IPK) $(PKG_WLCOMPAT)
        mkdir -p $(STAGING_DIR)/usr/include
        cp -a ./include/* $(STAGING_DIR)/usr/include/
 install: libnvram-install libshared-install \
-        $(TARGET_DIR)/usr/sbin/wlconf \
         $(IPKG_STATE_DIR)/info/$(PKG_NAME).list \
 
 clean: libshared-clean libnvram-clean
index 84b6272e49ff2754f48ffacbe30d5dd5517a2fac..d5ef11f9ed0d02ea8ff17a8e39ecc0b725ca2062 100644 (file)
@@ -1087,6 +1087,8 @@ typedef struct wlc_rev_info {
 #define        ABO_OFF                 0       /* force afterburner off */
 #define        ABO_ON                  1       /* force afterburner on */
 
+#define GMODE_AFTERBURNER 6
+
 #undef PACKED
 
 #endif /* _wlioctl_h_ */
diff --git a/openwrt/package/openwrt/wlconf.c b/openwrt/package/openwrt/wlconf.c
new file mode 100755 (executable)
index 0000000..e9e5348
--- /dev/null
@@ -0,0 +1,642 @@
+/* 
+ * no license, extracted from wag54gv2-AU_v1.00.39 GPL
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <typedefs.h>
+#include <bcmnvram.h>
+#include <bcmutils.h>
+#include <shutils.h>
+#include <wlutils.h>
+
+/* phy types */
+#define        PHY_TYPE_A              0
+#define        PHY_TYPE_B              1
+#define        PHY_TYPE_G              2
+#define        PHY_TYPE_NULL           0xf
+
+/* parts of an idcode: */
+#define        IDCODE_MFG_MASK         0x00000fff
+#define        IDCODE_MFG_SHIFT        0
+#define        IDCODE_ID_MASK          0x0ffff000
+#define        IDCODE_ID_SHIFT         12
+#define        IDCODE_REV_MASK         0xf0000000
+#define        IDCODE_REV_SHIFT        28
+
+#define WL_IOCTL(name, cmd, buf, len) ((void) wl_ioctl((name), (cmd), (buf), (len)))
+
+/* set WEP key */
+static int
+wlconf_set_wep_key(char *name, char *prefix, int i)
+{
+       wsec_key_t key;
+       char wl_key[] = "wlXXXXXXXXXX_keyXXXXXXXXXX";
+       char *keystr, hex[] = "XX";
+       unsigned char *data = key.data;
+       int ret = 0;
+
+       memset(&key, 0, sizeof(key));
+       key.index = i - 1;
+       sprintf(wl_key, "%skey%d", prefix, i);
+       keystr = nvram_safe_get(wl_key);
+
+       switch (strlen(keystr)) {
+       case WEP1_KEY_SIZE:
+       case WEP128_KEY_SIZE:
+               key.len = strlen(keystr);
+               strcpy(key.data, keystr);
+               break;
+       case WEP1_KEY_HEX_SIZE:
+       case WEP128_KEY_HEX_SIZE:
+               key.len = strlen(keystr) / 2;
+               while (*keystr) {
+                       strncpy(hex, keystr, 2);
+                       *data++ = (unsigned char) strtoul(hex, NULL, 16);
+                       keystr += 2;
+               }
+               break;
+       default:
+               key.len = 0;
+               break;
+       }
+
+       /* Set current WEP key */
+       if (key.len && i == atoi(nvram_safe_get(strcat_r(prefix, "key", wl_key))))
+               key.flags = WSEC_PRIMARY_KEY;
+
+       WL_IOCTL(name, WLC_SET_KEY, &key, sizeof(key));
+
+       return ret;
+}
+
+extern struct nvram_tuple router_defaults[];
+
+/* Keep this table in order */
+static struct {
+       int locale;
+       char **names;
+       char *abbr;
+} countries[] = {
+       { WLC_WW,  ((char *[]) { "Worldwide", "WW", NULL }), "AU" },
+       { WLC_THA, ((char *[]) { "Thailand", "THA", NULL }), "TH" },
+       { WLC_ISR, ((char *[]) { "Israel", "ISR", NULL }), "IL" },
+       { WLC_JDN, ((char *[]) { "Jordan", "JDN", NULL }), "JO" },
+       { WLC_PRC, ((char *[]) { "China", "P.R. China", "PRC", NULL }), "CN" },
+       { WLC_JPN, ((char *[]) { "Japan", "JPN", NULL }), "JP" },
+       { WLC_FCC, ((char *[]) { "USA", "Canada", "ANZ", "New Zealand", "FCC", NULL }), "US" },
+       { WLC_EUR, ((char *[]) { "Europe", "EUR", NULL }), "DE" },
+       { WLC_USL, ((char *[]) { "USA Low", "USALow", "USL", NULL }), "US" },
+       { WLC_JPH, ((char *[]) { "Japan High", "JapanHigh", "JPH", NULL }), "JP" },
+       { WLC_ALL, ((char *[]) { "All", "AllTheChannels", NULL }), "All" },
+};
+
+/* validate/restore all per-interface related variables */
+static void
+wlconf_validate_all(char *prefix, bool restore)
+{
+       struct nvram_tuple *t;
+       char tmp[100];
+       char *v;
+       for (t = router_defaults; t->name; t++) {
+               if (!strncmp(t->name, "wl_", 3)) {
+                       strcat_r(prefix, &t->name[3], tmp);
+                       if (!restore && nvram_get(tmp))
+                               continue;
+                       v = nvram_get(t->name);
+                       nvram_set(tmp, v ? v : t->value);
+               }
+       }
+}
+
+/* restore specific per-interface variable */
+static void
+wlconf_restore_var(char *prefix, char *name)
+{
+       struct nvram_tuple *t;
+       char tmp[100];
+       for (t = router_defaults; t->name; t++) {
+               if (!strncmp(t->name, "wl_", 3) && !strcmp(&t->name[3], name)) {
+                       nvram_set(strcat_r(prefix, name, tmp), t->value);
+                       break;
+               }
+       }
+}
+
+/* Set up wsec */
+static int
+wlconf_set_wsec(char *ifname, char *prefix)
+{
+       char tmp[100];
+       int val;
+       strcat_r(prefix, "wep", tmp);
+       if (nvram_match(tmp, "wep") || nvram_match(tmp, "on") || nvram_match(tmp, "restricted"))
+               val = WEP_ENABLED;
+       else if (nvram_match(tmp, "tkip"))
+               val = TKIP_ENABLED;
+       else if (nvram_match(tmp, "aes"))
+               val = AES_ENABLED;
+       else if (nvram_match(tmp, "tkip+aes"))
+               val = TKIP_ENABLED | AES_ENABLED;
+       else
+               val = 0;
+       return wl_ioctl(ifname, WLC_SET_WSEC, &val, sizeof(val));
+}
+
+/*
+* For debugging only
+*/
+#define WLCONF_DBG(fmt, arg...)
+
+#if defined(linux)
+#include <unistd.h>
+static void
+sleep_ms(const unsigned int ms)
+{
+       usleep(1000*ms);
+}
+#endif
+
+/*
+* The following condition(s) must be met when Auto Channel Selection 
+* is enabled.
+*  - the I/F is up (change radio channel requires it is up?)
+*  - the AP must not be associated (setting SSID to empty should 
+*    make sure it for us)
+*/
+static uint8
+wlconf_auto_channel(char *name)
+{
+       int chosen = 0;
+       wl_uint32_list_t request;
+       int phytype;
+       /* query the phy type */
+       wl_ioctl(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
+       request.count = 0;      /* let the ioctl decide */
+       if (!wl_ioctl(name, WLC_START_CHANNEL_SEL, &request, sizeof(request))) {
+               sleep_ms(phytype == PHY_TYPE_A ? 1000 : 750);
+               while (wl_ioctl(name, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)))
+                       sleep_ms(100);
+       }
+       WLCONF_DBG("interface %s: channel selected %d\n", name, chosen);
+       return chosen;
+}
+
+/* PHY type/BAND conversion */
+#define WLCONF_PHYTYPE2BAND(phy)       ((phy) == PHY_TYPE_A ? WLC_BAND_A : WLC_BAND_B)
+/* PHY type conversion */
+#define WLCONF_PHYTYPE2STR(phy)        ((phy) == PHY_TYPE_A ? "a" : \
+                                (phy) == PHY_TYPE_B ? "b" : "g")
+#define WLCONF_STR2PHYTYPE(phy)        ((phy) && (phy)[0] == 'a' ? PHY_TYPE_A : \
+                                (phy) && (phy)[0] == 'b' ? PHY_TYPE_B : PHY_TYPE_G)
+                                
+/* configure the specified wireless interface */
+int
+wlconf(char *name)
+{
+       int restore_defaults, val, unit, phytype, gmode = 0, ret = 0;
+       char tmp[100], prefix[] = "wlXXXXXXXXXX_";
+       char var[80], *next, phy[] = "a", *str;
+       unsigned char buf[WLC_IOCTL_MAXLEN];
+       char *country;
+       wlc_rev_info_t rev;
+       channel_info_t ci;
+       struct maclist *maclist;
+       struct ether_addr *ea;
+       wlc_ssid_t ssid;
+       wl_rateset_t rs;
+       unsigned int i;
+       char eaddr[32];
+       int ap, sta = 0, wet = 0;
+       char country_code[4];
+
+       /* Check interface (fail silently for non-wl interfaces) */
+       if ((ret = wl_probe(name)))
+               return ret;
+
+       /* Get MAC address */
+       (void) wl_hwaddr(name, buf);
+
+       /* Get instance */
+       WL_IOCTL(name, WLC_GET_INSTANCE, &unit, sizeof(unit));
+       snprintf(prefix, sizeof(prefix), "wl%d_", unit);
+
+       /* Restore defaults if per-interface parameters do not exist */
+       restore_defaults = !nvram_get(strcat_r(prefix, "ifname", tmp));
+       wlconf_validate_all(prefix, restore_defaults);
+       nvram_set(strcat_r(prefix, "ifname", tmp), name);
+       nvram_set(strcat_r(prefix, "hwaddr", tmp), ether_etoa(buf, eaddr));
+       snprintf(buf, sizeof(buf), "%d", unit);
+       nvram_set(strcat_r(prefix, "unit", tmp), buf);
+
+       /*
+       * Nuke SSID first so that the AP won't be associated when WLC_UP.
+       * This must be done here if Auto Channel Selection is enabled.
+       */
+       WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
+       if (val) {
+               /* Nuke SSID  */
+               ssid.SSID_len = 0;
+               ssid.SSID[0] = '\0';
+               WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
+
+               /* Bring the interface down */
+               WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
+       }
+
+       /* Set mode : AP, STA */
+       ap = nvram_match(strcat_r(prefix, "mode", tmp), "ap");
+       val = (ap + nvram_match(strcat_r(prefix, "mode", tmp), "wds")) ? 1 : 0;
+       WL_IOCTL(name, WLC_SET_AP, &val, sizeof(val));
+
+       /* Set STA specific parameters */
+       if (!ap) {
+               /* Set mode: WET */
+               if ((wet = nvram_match(strcat_r(prefix, "mode", tmp), "wet")))
+                       WL_IOCTL(name, WLC_SET_WET, &wet, sizeof(wet));
+               /* Set infra: BSS/IBSS */
+               if (wet || (sta = nvram_match(strcat_r(prefix, "mode", tmp), "sta"))) {
+                       val = atoi(nvram_safe_get(strcat_r(prefix, "infra", tmp)));
+                       WL_IOCTL(name, WLC_SET_INFRA, &val, sizeof(val));
+               }
+       }
+
+       /* Set network type */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "closed", tmp)));
+       WL_IOCTL(name, WLC_SET_CLOSED, &val, sizeof(val));
+
+       /* Set up the country code */
+       (void) strcat_r(prefix, "country_code", tmp);
+       country = nvram_get(tmp);
+       if (country) {
+               strncpy(country_code, country, sizeof(country_code));
+               WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
+       }
+       else {
+               /* If country_code doesn't exist, check for country to be backward compatible */
+               (void) strcat_r(prefix, "country", tmp);
+               country = nvram_safe_get(tmp);
+               for (val = 0; val < ARRAYSIZE(countries); val++) {
+                       char **synonym;
+                       for (synonym = countries[val].names; *synonym; synonym++)
+                               if (!strcmp(country, *synonym))
+                                       break;
+                       if (*synonym)
+                               break;
+               }
+
+               /* Get the default country code if undefined or invalid and set the NVRAM */
+               if (val >= ARRAYSIZE(countries)) {
+                       WL_IOCTL(name, WLC_GET_COUNTRY, country_code, sizeof(country_code));
+               }
+               else {
+                       strncpy(country_code, countries[val].abbr, sizeof(country_code));
+                       WL_IOCTL(name, WLC_SET_COUNTRY, country_code, strlen(country_code)+1);
+               }
+
+               /* Add the new NVRAM variable */
+               nvram_set("wl_country_code", country_code);
+               (void) strcat_r(prefix, "country_code", tmp);
+               nvram_set(tmp, country_code);
+       }
+       
+       /* Set the MAC list */
+       maclist = (struct maclist *) buf;
+       maclist->count = 0;
+       if (!nvram_match(strcat_r(prefix, "macmode", tmp), "disabled")) {
+               ea = maclist->ea;
+               foreach(var, nvram_safe_get(strcat_r(prefix, "maclist", tmp)), next) {
+                       if ((&ea[1])->octet > &buf[sizeof(buf)])
+                               break;
+                       if (ether_atoe(var, ea->octet)) {
+                               maclist->count++;
+                               ea++;
+                       }
+               }
+       }
+       WL_IOCTL(name, WLC_SET_MACLIST, buf, sizeof(buf));
+
+       /* Set the MAC list mode */
+       (void) strcat_r(prefix, "macmode", tmp);
+       if (nvram_match(tmp, "deny"))
+               val = WLC_MACMODE_DENY;
+       else if (nvram_match(tmp, "allow"))
+               val = WLC_MACMODE_ALLOW;
+       else
+               val = WLC_MACMODE_DISABLED;
+       WL_IOCTL(name, WLC_SET_MACMODE, &val, sizeof(val));
+
+       /* Enable or disable the radio */
+       val = nvram_match(strcat_r(prefix, "radio", tmp), "0");
+       WL_IOCTL(name, WLC_SET_RADIO, &val, sizeof(val));
+
+       /* Get supported phy types */
+       WL_IOCTL(name, WLC_GET_PHYLIST, var, sizeof(var));
+       nvram_set(strcat_r(prefix, "phytypes", tmp), var);
+
+       /* Get radio IDs */
+       *(next = buf) = '\0';
+       for (i = 0; i < strlen(var); i++) {
+               /* Switch to band */
+               phy[0] = var[i];
+               val = WLCONF_STR2PHYTYPE(phy);
+               val = WLCONF_PHYTYPE2BAND(val);
+               WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
+               /* Get radio ID on this band */
+               WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
+               next += sprintf(next, "%sBCM%X", i ? " " : "",
+                               (rev.radiorev & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT);
+       }
+       nvram_set(strcat_r(prefix, "radioids", tmp), buf);
+
+       /* Set band */
+       str = nvram_get(strcat_r(prefix, "phytype", tmp));
+       val = WLCONF_STR2PHYTYPE(str);
+       val = WLCONF_PHYTYPE2BAND(val);
+       /* Check errors (card may have changed) */
+       if (wl_ioctl(name, WLC_SET_BAND, &val, sizeof(val))) {
+               /* default band to the first band in band list */
+               phy[0] = var[0];
+               val = WLCONF_STR2PHYTYPE(phy);
+               val = WLCONF_PHYTYPE2BAND(val);
+               WL_IOCTL(name, WLC_SET_BAND, &val, sizeof(val));
+       }
+
+       /* Get current core revision */
+       WL_IOCTL(name, WLC_GET_REVINFO, &rev, sizeof(rev));
+       snprintf(buf, sizeof(buf), "%d", rev.corerev);
+       nvram_set(strcat_r(prefix, "corerev", tmp), buf);
+
+       /* Get current phy type */
+       WL_IOCTL(name, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
+       snprintf(buf, sizeof(buf), "%s", WLCONF_PHYTYPE2STR(phytype));
+       nvram_set(strcat_r(prefix, "phytype", tmp), buf);
+
+       /* Set channel before setting gmode or rateset */
+       /* Manual Channel Selection - when channel # is not 0 */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp)));
+       if (val) {
+               if (wl_ioctl(name, WLC_SET_CHANNEL, &val, sizeof(val))) {
+                       /* Use current channel (card may have changed) */
+                       WL_IOCTL(name, WLC_GET_CHANNEL, &ci, sizeof(ci));
+                       snprintf(buf, sizeof(buf), "%d", ci.target_channel);
+                       nvram_set(strcat_r(prefix, "channel", tmp), buf);
+               }
+       }
+       
+       /* Reset to hardware rateset (band may have changed) */
+       WL_IOCTL(name, WLC_GET_RATESET, &rs, sizeof (wl_rateset_t));
+       WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof (wl_rateset_t));
+
+       /* Set gmode */
+       if (phytype == PHY_TYPE_G) {
+
+               /* Set gmode */
+
+               gmode = atoi(nvram_safe_get(strcat_r(prefix, "gmode", tmp)));
+               if (gmode == GMODE_AFTERBURNER) {
+                       if (wl_get_int(name, "abcap", &val) || !val) {
+                               gmode = GMODE_AUTO;
+                               snprintf(buf, sizeof(buf), "%d", gmode);
+                               nvram_set(tmp, buf);
+                       }
+               }
+               WL_IOCTL(name, WLC_SET_GMODE, &gmode, sizeof(gmode));
+
+               /* Set gmode protection override and control algorithm */
+               if (gmode != GMODE_AFTERBURNER) {
+                       int override = WLC_G_PROTECTION_OFF;
+                       int control = WLC_G_PROTECTION_CTL_OFF;
+                       strcat_r(prefix, "gmode_protection", tmp);
+                       if (nvram_match(tmp, "auto")) {
+                               override = WLC_G_PROTECTION_AUTO;
+                               control = WLC_G_PROTECTION_CTL_OVERLAP;
+                       }
+                       WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_OVERRIDE, &override, sizeof(override));
+                       WL_IOCTL(name, WLC_SET_GMODE_PROTECTION_CONTROL, &control, sizeof(control));
+               }
+       }
+
+       /* Get current rateset (gmode may have changed) */
+       WL_IOCTL(name, WLC_GET_CURR_RATESET, &rs, sizeof (wl_rateset_t));
+
+       strcat_r(prefix, "rateset", tmp);
+       if (nvram_match(tmp, "all"))  {
+               /* Make all rates basic */
+               for (i = 0; i < rs.count; i++)
+                       rs.rates[i] |= 0x80;
+       } else if (nvram_match(tmp, "12")) {
+               /* Make 1 and 2 basic */
+               for (i = 0; i < rs.count; i++) {
+                       if ((rs.rates[i] & 0x7f) == 2 || (rs.rates[i] & 0x7f) == 4)
+                               rs.rates[i] |= 0x80;
+                       else
+                               rs.rates[i] &= ~0x80;
+               }
+       }
+
+       /* Set rateset */
+       WL_IOCTL(name, WLC_SET_RATESET, &rs, sizeof (wl_rateset_t));
+
+       /* Allow short preamble override for b cards */
+       if (phytype == PHY_TYPE_B || gmode == 0) {
+               strcat_r(prefix, "plcphdr", tmp);               
+               if (nvram_match(tmp, "long"))
+                       val = WLC_PLCP_AUTO;
+               else
+                       val = WLC_PLCP_SHORT;
+               WL_IOCTL(name, WLC_SET_PLCPHDR, &val, sizeof(val));
+       }
+
+       /* Set rate in 500 Kbps units */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "rate", tmp))) / 500000;
+       if (wl_ioctl(name, WLC_SET_RATE, &val, sizeof(val))) {
+               /* Try default rate (card may have changed) */
+               val = 0;
+               WL_IOCTL(name, WLC_SET_RATE, &val, sizeof(val));
+               snprintf(buf, sizeof(buf), "%d", val);
+               nvram_set(strcat_r(prefix, "rate", tmp), buf);
+       }
+
+       /* Set fragmentation threshold */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "frag", tmp)));
+       WL_IOCTL(name, WLC_SET_FRAG, &val, sizeof(val));
+
+       /* Set RTS threshold */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "rts", tmp)));
+       WL_IOCTL(name, WLC_SET_RTS, &val, sizeof(val));
+
+       /* Set DTIM period */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "dtim", tmp)));
+       WL_IOCTL(name, WLC_SET_DTIMPRD, &val, sizeof(val));
+
+       /* Set beacon period */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "bcn", tmp)));
+       WL_IOCTL(name, WLC_SET_BCNPRD, &val, sizeof(val));
+
+       /* Set lazy WDS mode */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "lazywds", tmp)));
+       WL_IOCTL(name, WLC_SET_LAZYWDS, &val, sizeof(val));
+
+       /* Set the WDS list */
+       maclist = (struct maclist *) buf;
+       maclist->count = 0;
+       ea = maclist->ea;
+       foreach(var, nvram_safe_get(strcat_r(prefix, "wds", tmp)), next) {
+               if (ea->octet > &buf[sizeof(buf)])
+                       break;
+               ether_atoe(var, ea->octet);
+               maclist->count++;
+               ea++;
+       }
+       WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
+
+       /* Set framebursting mode */
+       val = nvram_match(strcat_r(prefix, "frameburst", tmp), "on");
+       WL_IOCTL(name, WLC_SET_FAKEFRAG, &val, sizeof(val));
+       
+       /* Bring the interface back up */
+       WL_IOCTL(name, WLC_UP, NULL, 0);
+
+       /* Set antenna */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "antdiv", tmp)));
+       WL_IOCTL(name, WLC_SET_ANTDIV, &val, sizeof(val));
+
+       /* Auto Channel Selection - when channel # is 0 in AP mode */
+       /*
+       * The following condition(s) must be met in order for 
+       * Auto Channel Selection to work.
+       *  - the I/F must be up (change radio channel requires it is up?)
+       *  - the AP must not be associated (setting SSID to empty should 
+       *    make sure it for us)
+       */
+       if (ap) {
+               if (!(val = atoi(nvram_safe_get(strcat_r(prefix, "channel", tmp))))) {
+                       /* select a channel */
+                       val = wlconf_auto_channel(name);
+                       /* switch to the selected channel */
+                       WL_IOCTL(name, WLC_SET_CHANNEL, &val, sizeof(val));
+                       /* set the auto channel scan timer in the driver when in auto mode */
+                       val = 15;       /* 15 minutes for now */
+                       WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
+               }
+               else {
+                       /* reset the channel scan timer in the driver when not in auto mode */
+                       val = 0;
+                       WL_IOCTL(name, WLC_SET_CS_SCAN_TIMER, &val, sizeof(val));
+               }
+       }
+
+       /* Set WEP keys */
+       for (i = 1; i <= WLC_MAX_DEFAULT_KEYS; i++)
+               wlconf_set_wep_key(name, prefix, i);
+
+       /* Set WSEC */
+       /*
+       * Need to check errors (card may have changed) and change to
+       * defaults since the new chip may not support the requested 
+       * encryptions after the card has been changed.
+       */
+       if (wlconf_set_wsec(name, prefix)) {
+               /* change nvram only, code below will pass them on */
+               wlconf_restore_var(prefix, "auth_mode");
+               wlconf_restore_var(prefix, "auth");
+               /* reset wep to default */
+               wlconf_restore_var(prefix, "wep");
+               wlconf_set_wsec(name, prefix);
+       }
+
+       /* Set WPA authentication mode - radius/wpa/psk */
+       strcat_r(prefix, "auth_mode", tmp);
+       if (nvram_match(tmp, "radius"))
+               val = WPA_AUTH_DISABLED;
+       else if (nvram_match(tmp, "wpa"))
+               val = WPA_AUTH_UNSPECIFIED;
+       else if (nvram_match(tmp, "psk"))
+               val = WPA_AUTH_PSK;
+       else /* if (nvram_match(tmp, "disabled")) */
+               val = WPA_AUTH_DISABLED;
+       WL_IOCTL(name, WLC_SET_WPA_AUTH, &val, sizeof(val));
+       
+       /* Set non-WPA authentication mode - open/shared */
+       val = atoi(nvram_safe_get(strcat_r(prefix, "auth", tmp)));
+       WL_IOCTL(name, WLC_SET_AUTH, &val, sizeof(val));
+
+       /* Set WEP restrict if WEP is not disabled */
+       val = nvram_invmatch(strcat_r(prefix, "wep", tmp), "off");
+       WL_IOCTL(name, WLC_SET_WEP_RESTRICT, &val, sizeof(val));
+
+       /* Set SSID/Join network */
+       if (ap | sta | wet) {
+               strcat_r(prefix, "ssid", tmp);
+               ssid.SSID_len = strlen(nvram_safe_get(tmp));
+               if (ssid.SSID_len > sizeof(ssid.SSID))
+                       ssid.SSID_len = sizeof(ssid.SSID);
+               strncpy(ssid.SSID, nvram_safe_get(tmp), ssid.SSID_len);
+       } else {
+               /* A zero length SSID turns off the AP */
+               ssid.SSID_len = 0;
+               ssid.SSID[0] = '\0';
+       }               
+       WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
+       
+       return 0;
+}
+
+int
+wlconf_down(char *name)
+{
+       int val, ret = 0;
+       unsigned char buf[WLC_IOCTL_MAXLEN];
+       struct maclist *maclist;
+       wlc_ssid_t ssid;
+
+       /* Check interface (fail silently for non-wl interfaces) */
+       if ((ret = wl_probe(name)))
+               return ret;
+
+       /* Bring down the interface */
+       WL_IOCTL(name, WLC_GET_UP, &val, sizeof(val));
+       if (val) {
+               /* Nuke SSID  */
+               ssid.SSID_len = 0;
+               ssid.SSID[0] = '\0';
+               WL_IOCTL(name, WLC_SET_SSID, &ssid, sizeof(ssid));
+
+               /* Bring the interface down */
+               WL_IOCTL(name, WLC_DOWN, NULL, sizeof(val));
+       }
+
+       /* Nuke the WDS list */
+       maclist = (struct maclist *) buf;
+       maclist->count = 0;
+       WL_IOCTL(name, WLC_SET_WDSLIST, buf, sizeof(buf));
+
+       return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+       int ret = -1;
+       
+       /* Check parameters and branch based on action */
+       if (argc == 3 && !strcmp(argv[2], "up"))
+               ret = wlconf(argv[1]);
+       else if (argc == 3 && !strcmp(argv[2], "down"))
+               ret = wlconf_down(argv[1]);
+       else {
+               fprintf(stderr, "Usage: wlconf <ifname> up|down\n");
+               return -1;
+       }
+       /* Check result */
+       if (ret) {
+               fprintf(stderr, "wlconf: %s failed (%d)\n", argv[1], ret);
+               return ret;
+       }
+       return 0;
+}