update libertas driver
authorJohn Crispin <john@openwrt.org>
Sun, 30 Nov 2008 16:53:16 +0000 (16:53 +0000)
committerJohn Crispin <john@openwrt.org>
Sun, 30 Nov 2008 16:53:16 +0000 (16:53 +0000)
SVN-Revision: 13447

33 files changed:
package/libertas/Makefile
package/libertas/patches/100-compile_fix.patch [deleted file]
package/libertas/patches/100-wext.patch [new file with mode: 0644]
package/libertas/src/11d.c
package/libertas/src/11d.h
package/libertas/src/Makefile
package/libertas/src/README
package/libertas/src/assoc.c
package/libertas/src/assoc.h
package/libertas/src/cmd.c
package/libertas/src/cmd.h
package/libertas/src/cmdresp.c
package/libertas/src/debugfs.c
package/libertas/src/decl.h
package/libertas/src/defs.h
package/libertas/src/dev.h
package/libertas/src/ethtool.c
package/libertas/src/host.h
package/libertas/src/hostcmd.h
package/libertas/src/if_cs.c
package/libertas/src/if_sdio.c
package/libertas/src/if_usb.c
package/libertas/src/if_usb.h
package/libertas/src/ioctl.c [new file with mode: 0644]
package/libertas/src/ioctl.h [new file with mode: 0644]
package/libertas/src/main.c
package/libertas/src/rx.c
package/libertas/src/scan.c
package/libertas/src/scan.h
package/libertas/src/tx.c
package/libertas/src/types.h
package/libertas/src/wext.c
package/libertas/src/wext.h

index ac241cb..decf8c4 100644 (file)
@@ -16,7 +16,7 @@ include $(INCLUDE_DIR)/package.mk
 
 define KernelPackage/libertas
   SUBMENU:=Other modules
-  DEPENDS:=@TARGET_olpc +kmod-ieee80211
+  DEPENDS:=+kmod-ieee80211
   TITLE:=Marvell 88W8015 Wireless Driver
   FILES:= \
        $(PKG_BUILD_DIR)/libertas.$(LINUX_KMOD_SUFFIX)  \
@@ -25,9 +25,9 @@ define KernelPackage/libertas
 endef
 
 define Download/firmware
-  URL:=http://dev.laptop.org/pub/firmware/libertas
-  FILE:=usb8388-5.220.11.p5.bin
-  MD5SUM=37cc814d5a475fcf8f8fbe89a9c5d546
+  URL:=http://dev.laptop.org/pub/firmware/libertas/
+  FILE:=usb8388-5.110.22.p20.bin
+  #MD5SUM=37cc814d5a475fcf8f8fbe89a9c5d546
 endef
 
 define Build/Prepare
@@ -44,13 +44,13 @@ define Build/Compile
                SUBDIRS="$(PKG_BUILD_DIR)" \
                CONFIG_LIBERTAS=m \
                CONFIG_LIBERTAS_USB=m \
-               EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -DCONFIG_LIBERTAS_DEBUG -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \
+               EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -DCONFIG_LIBERTAS_DEBUG -I$(STAGING_DIR)/usr/include/mac80211" \
                modules 
 endef
 
 define KernelPackage/libertas/install
        $(INSTALL_DIR) $(1)/lib/firmware
-       $(INSTALL_BIN) $(DL_DIR)/usb8388-5.220.11.p5.bin $(1)/lib/firmware/usb8388.bin
+       $(INSTALL_BIN) $(DL_DIR)/usb8388-5.110.22.p20.bin $(1)/lib/firmware/usb8388.bin
        $(INSTALL_DATA) ./files/LICENSE $(1)/lib/firmware/
 endef
 
diff --git a/package/libertas/patches/100-compile_fix.patch b/package/libertas/patches/100-compile_fix.patch
deleted file mode 100644 (file)
index 9834414..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-Index: kmod-libertas/ethtool.c
-===================================================================
---- kmod-libertas.orig/ethtool.c       2008-01-14 22:14:06.000000000 +0000
-+++ kmod-libertas/ethtool.c    2008-01-14 22:14:14.000000000 +0000
-@@ -144,16 +144,6 @@
-       lbs_deb_enter(LBS_DEB_ETHTOOL);
- }
--static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset)
--{
--      switch (sset) {
--      case ETH_SS_STATS:
--              return MESH_STATS_NUM;
--      default:
--              return -EOPNOTSUPP;
--      }
--}
--
- static void lbs_ethtool_get_strings(struct net_device *dev,
-                                         u32 stringset,
-                                         u8 * s)
-@@ -221,7 +211,6 @@
-       .get_drvinfo = lbs_ethtool_get_drvinfo,
-       .get_eeprom =  lbs_ethtool_get_eeprom,
-       .get_eeprom_len = lbs_ethtool_get_eeprom_len,
--      .get_sset_count = lbs_ethtool_get_sset_count,
-       .get_ethtool_stats = lbs_ethtool_get_stats,
-       .get_strings = lbs_ethtool_get_strings,
-       .get_wol = lbs_ethtool_get_wol,
-Index: kmod-libertas/if_usb.c
-===================================================================
---- kmod-libertas.orig/if_usb.c        2008-01-14 22:14:57.000000000 +0000
-+++ kmod-libertas/if_usb.c     2008-01-14 22:17:09.000000000 +0000
-@@ -188,14 +188,14 @@
-               endpoint = &iface_desc->endpoint[i].desc;
-               if (usb_endpoint_is_bulk_in(endpoint)) {
-                       cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
--                      cardp->ep_in = usb_endpoint_num(endpoint);
-+                      cardp->ep_in = endpoint->bEndpointAddress;
-                       lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
-                       lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
-               } else if (usb_endpoint_is_bulk_out(endpoint)) {
-                       cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
--                      cardp->ep_out = usb_endpoint_num(endpoint);
-+                      cardp->ep_out = endpoint->bEndpointAddress;
-                       lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
-                       lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
diff --git a/package/libertas/patches/100-wext.patch b/package/libertas/patches/100-wext.patch
new file mode 100644 (file)
index 0000000..da1d24b
--- /dev/null
@@ -0,0 +1,81 @@
+Index: kmod-libertas/scan.c
+===================================================================
+--- kmod-libertas.orig/scan.c  2008-11-30 17:44:39.000000000 +0100
++++ kmod-libertas/scan.c       2008-11-30 17:46:08.000000000 +0100
+@@ -13,6 +13,13 @@
+ #include "scan.h"
+ #include "cmd.h"
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) 
++#define IWE(func, ...) func(&iweinfo, __VA_ARGS__)
++static struct iw_request_info iweinfo = { 0, 0 };
++#else
++#define IWE(func, ...) func(__VA_ARGS__)
++#endif
++
+ //! Approximate amount of data needed to pass a scan result back to iwlist
+ #define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
+                              + IW_ESSID_MAX_SIZE        \
+@@ -807,7 +814,7 @@
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.data.flags = 1;
+       iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
+-      start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
++      start = IWE(iwe_stream_add_point, start, stop, &iwe, bss->ssid);
+       /* Mode */
+       iwe.cmd = SIOCGIWMODE;
+@@ -862,7 +869,7 @@
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       }
+       iwe.u.data.length = 0;
+-      start = iwe_stream_add_point(start, stop, &iwe, bss->ssid);
++      start = IWE(iwe_stream_add_point, start, stop, &iwe, bss->ssid);
+       current_val = start + IW_EV_LCP_LEN;
+@@ -874,7 +881,7 @@
+       for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+               /* Bit rate given in 500 kb/s units */
+               iwe.u.bitrate.value = bss->rates[j] * 500000;
+-              current_val = iwe_stream_add_value(start, current_val,
++              current_val = IWE(iwe_stream_add_value, start, current_val,
+                                        stop, &iwe, IW_EV_PARAM_LEN);
+       }
+       if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
+@@ -882,7 +889,7 @@
+                            priv->curbssparams.ssid_len,
+                            bss->ssid, bss->ssid_len)) {
+               iwe.u.bitrate.value = 22 * 500000;
+-              current_val = iwe_stream_add_value(start, current_val,
++              current_val = IWE(iwe_stream_add_value, start, current_val,
+                                                  stop, &iwe, IW_EV_PARAM_LEN);
+       }
+       /* Check if we added any event */
+@@ -895,7 +902,7 @@
+               memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = bss->wpa_ie_len;
+-              start = iwe_stream_add_point(start, stop, &iwe, buf);
++              start = IWE(iwe_stream_add_point, start, stop, &iwe, buf);
+       }
+       memset(&iwe, 0, sizeof(iwe));
+@@ -904,7 +911,7 @@
+               memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = bss->rsn_ie_len;
+-              start = iwe_stream_add_point(start, stop, &iwe, buf);
++              start = IWE(iwe_stream_add_point, start, stop, &iwe, buf);
+       }
+       if (bss->mesh) {
+@@ -915,7 +922,7 @@
+               p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
+               iwe.u.data.length = p - custom;
+               if (iwe.u.data.length)
+-                      start = iwe_stream_add_point(start, stop, &iwe, custom);
++                      start = IWE(iwe_stream_add_point, start, stop, &iwe, custom);
+       }
+ out:
index 40f1daa..4bc46a6 100644 (file)
@@ -46,13 +46,11 @@ static struct chan_freq_power channel_freq_power_UN_BG[] = {
 static u8 lbs_region_2_code(u8 *region)
 {
        u8 i;
-       u8 size = sizeof(region_code_mapping)/
-                 sizeof(struct region_code_mapping);
 
        for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
                region[i] = toupper(region[i]);
 
-       for (i = 0; i < size; i++) {
+       for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
                if (!memcmp(region, region_code_mapping[i].region,
                            COUNTRY_CODE_LEN))
                        return (region_code_mapping[i].code);
@@ -65,9 +63,8 @@ static u8 lbs_region_2_code(u8 *region)
 static u8 *lbs_code_2_region(u8 code)
 {
        u8 i;
-       u8 size = sizeof(region_code_mapping)
-                 / sizeof(struct region_code_mapping);
-       for (i = 0; i < size; i++) {
+
+       for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
                if (region_code_mapping[i].code == code)
                        return (region_code_mapping[i].region);
        }
@@ -82,7 +79,7 @@ static u8 *lbs_code_2_region(u8 code)
  *  @param nrchan   number of channels
  *  @return          the nrchan-th chan number
 */
-static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan)
+static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
 /*find the nrchan-th chan after the firstchan*/
 {
        u8 i;
@@ -90,8 +87,7 @@ static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan)
        u8 cfp_no;
 
        cfp = channel_freq_power_UN_BG;
-       cfp_no = sizeof(channel_freq_power_UN_BG) /
-           sizeof(struct chan_freq_power);
+       cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
 
        for (i = 0; i < cfp_no; i++) {
                if ((cfp + i)->channel == firstchan) {
@@ -138,19 +134,15 @@ static u8 lbs_channel_known_11d(u8 chan,
        return 0;
 }
 
-u32 lbs_chan_2_freq(u8 chan, u8 band)
+u32 lbs_chan_2_freq(u8 chan)
 {
        struct chan_freq_power *cf;
-       u16 cnt;
        u16 i;
        u32 freq = 0;
 
        cf = channel_freq_power_UN_BG;
-       cnt =
-           sizeof(channel_freq_power_UN_BG) /
-           sizeof(struct chan_freq_power);
 
-       for (i = 0; i < cnt; i++) {
+       for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
                if (chan == cf[i].channel)
                        freq = cf[i].freq;
        }
@@ -272,7 +264,7 @@ static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_ch
  *  @param chan                 chan
  *  @return                    TRUE;FALSE
 */
-static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
 {
        struct chan_freq_power *cfp;
        int cfp_no;
@@ -281,7 +273,7 @@ static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan)
 
        lbs_deb_enter(LBS_DEB_11D);
 
-       cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
+       cfp = lbs_get_region_cfp_table(region, &cfp_no);
        if (cfp == NULL)
                return 0;
 
@@ -375,7 +367,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
                for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
                        /*step4: channel is supported? */
 
-                       if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) {
+                       if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
                                /* Chan is not found in UN table */
                                lbs_deb_11d("chan is not supported: %d \n", i);
                                break;
@@ -383,8 +375,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
 
                        lastchan = curchan;
 
-                       if (lbs_region_chan_supported_11d
-                           (region, band, curchan)) {
+                       if (lbs_region_chan_supported_11d(region, curchan)) {
                                /*step5: Check if curchan is supported by mrvl in region */
                                parsed_region_chan->chanpwr[idx].chan = curchan;
                                parsed_region_chan->chanpwr[idx].pwr =
@@ -562,8 +553,7 @@ done:
  *  @param resp    pointer to command response buffer
  *  @return       0; -1
  */
-int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
-                                struct cmd_ds_command *resp)
+int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
 {
        struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
        struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
index 811eea2..4f4f47f 100644 (file)
@@ -83,7 +83,7 @@ struct lbs_private;
 u8 lbs_get_scan_type_11d(u8 chan,
                          struct parsed_region_chan_11d *parsed_region_chan);
 
-u32 lbs_chan_2_freq(u8 chan, u8 band);
+u32 lbs_chan_2_freq(u8 chan);
 
 void lbs_init_11d(struct lbs_private *priv);
 
@@ -93,8 +93,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
                                 struct cmd_ds_command *cmd, u16 cmdno,
                                 u16 cmdOption);
 
-int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
-                                struct cmd_ds_command *resp);
+int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
 
 struct bss_descriptor;
 int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
index 0e27876..b7a136f 100644 (file)
@@ -1,9 +1,9 @@
 libertas-objs := main.o wext.o \
                rx.o tx.o cmd.o           \
                cmdresp.o scan.o          \
-               join.o 11d.o              \
+               11d.o             \
                debugfs.o         \
-               ethtool.o assoc.o
+               ethtool.o assoc.o ioctl.o
 
 usb8xxx-objs += if_usb.o
 libertas_cs-objs += if_cs.o
index d860fc3..2706a42 100644 (file)
@@ -28,6 +28,423 @@ DRIVER LOADING
 
                insmod usb8388.ko [fw_name=usb8388.bin]
 
+=====================
+IWPRIV COMMAND
+=====================
+
+NAME
+       This manual describes the usage of private commands used in Marvell WLAN
+       Linux Driver. All the commands available in Wlanconfig will not be available
+       in the iwpriv.
+
+SYNOPSIS
+       iwpriv <ethX> <command> [sub-command] ...
+
+       iwpriv ethX setregioncode <n>
+       iwpriv ethX getregioncode
+
+Version 5 Command:
+       iwpriv ethX ledgpio <n>
+
+BT Commands:
+       The blinding table (BT) contains a list of mac addresses that will be,
+       by default, ignored by the firmware. It is also possible to invert this
+       behavior so that we will ignore all traffic except for the portion
+       coming from mac addresess in the list. It is primarily used for
+       debugging and testing networks.  It can be edited and inspected with
+       the following commands:
+
+       iwpriv ethX bt_reset
+       iwpriv ethX bt_add <mac_address>
+       iwpriv ethX bt_del <mac_address>
+       iwpriv ethX bt_list <id>
+       iwpriv ethX bt_get_invert <n>
+       iwpriv ethX bt_set_invert <n>
+
+FWT Commands:
+       The forwarding table (FWT) is a feature used to manage mesh network
+       routing in the firmware.  The FWT is essentially a routing table that
+       associates a destination mac address (da) with a next hop receiver
+       address (ra).  The FWT can be inspected and edited with the following
+       iwpriv commands, which are described in greater detail below.
+       Eventually, the table will be automatically maintained by a custom
+       routing protocol.
+
+       NOTE: FWT commands replace the previous DFT commands.  What were the DFT
+       commands?, you might ask.  They were an earlier API to the firmware that
+       implemented a simple MAC-layer forwarding mechanism.  In the unlikely
+       event that you were using these commands, you must migrate to the new
+       FWT commands which can be used to achieve the same functionality.
+
+       iwpriv ethX fwt_add [parameters]
+       iwpriv ethX fwt_del [parameters]
+       iwpriv ethX fwt_lookup [parameters]
+       iwpriv ethX fwt_list [parameters]
+       iwpriv ethX fwt_list_route [parameters]
+       iwpriv ethX fwt_list_neigh [parameters]
+       iwpriv ethX fwt_reset [parameters]
+       iwpriv ethX fwt_cleanup
+       iwpriv ethX fwt_time
+
+MESH Commands:
+
+       The MESH commands are used to configure various features of the mesh
+       routing protocol.  The following commands are supported:
+
+       iwpriv ethX mesh_get_ttl
+       iwpriv ethX mesh_set_ttl ttl
+       iwpriv ethX mesh_get_bcastr rate
+       iwpriv ethX mesh_set_bcastr rate
+       iwpriv ethX get_rreq_delay
+       iwpriv ethX set_rreq_delay delay
+       iwpriv ethX get_route_exp
+       iwpriv ethX set_route_exp time
+       iwpriv ethX get_link_costs
+       iwpriv ethX set_link_costs "cost54 cost36 cost11 cost1"
+
+DESCRIPTION
+       Those commands are used to send additional commands to the Marvell WLAN
+       card via the Linux device driver.
+
+       The ethX parameter specifies the network device that is to be used to
+               perform this command on. it could be eth0, eth1 etc.
+
+setregioncode
+       This command is used to set the region code in the station.
+       where value is 'region code' for various regions like
+       USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ...
+
+       Usage:
+               iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
+
+getregioncode
+       This command is used to get the region code information set in the
+       station.
+
+ledgpio
+       This command is used to set/get LEDs.
+
+       iwpriv ethX ledgpio <LEDs>
+               will set the corresponding LED for the GPIO Line.
+
+       iwpriv ethX ledgpio
+               will give u which LEDs are Enabled.
+
+       Usage:
+               iwpriv eth1 ledgpio 1 0 2 1 3 4
+                       will enable
+                       LED 1 -> GPIO 0
+                       LED 2 -> GPIO 1
+                       LED 3 -> GPIO 4
+
+               iwpriv eth1 ledgpio
+                       shows LED information in the format as mentioned above.
+
+       Note: LED0 is invalid
+       Note: Maximum Number of LEDs are 16.
+
+bcn_control
+       This command is used to enable disable beacons. This can also be used
+       to set beacon interval.
+
+       Usage:
+               iwpriv ethX bcn_control [enable] [beacon_interval]
+
+               enable: 0 to disable beacon. 1 to enable beacon.
+               beacon_interval: 20 - 1000ms.
+
+       Examples:
+               1. iwpriv ethX bcn_control
+                  Returns (x, y), where x if 1, indicates beacon is enabled, y 
+                  beacon period.
+               2. iwpriv ethX bcn_control 0
+                  Turns off beacon transmission.
+               3. iwpriv ethX bcn_control 1 500
+                  Enable beacon with beacon interval 500ms.
+               
+
+ledbhv
+      Command iwpriv mshX ledbhv can be used to change default LEDs behaviors.
+      A given LED behavior can be on, off or blinking. The duty/cycle can be set
+      when behavior is programmed as blinking.
+
+      Usage:
+
+        1. To get default LED behavior
+           iwpriv mshX ledbhv <firmware state>
+
+        2. To set or change default LED behavior
+           iwpriv mshX ledbhv <firmware state> <lednum> <behavior> <arg>
+
+        firmware state: The following are some of the relevant states.
+          00: disconnected 
+          01: firmware is scanning
+          02: firmware is connected and awake
+          03: firmware is sleeping
+          04: connected deep sleep
+          06: firmware disconnected link lost 
+          07: firmware disconnected disassociated
+          09: data transfer while firmware is associated and not scanning. 
+              If firmware is already in this state, LED behavior does not change 
+              on this data transfer.
+          10: firmware idle, not scanning, not disconnected or disassociated.
+
+        lednum: 1 or 2 for first and second LED.
+  
+        behavior: 0 for steady ON, 1 - steady off and 2- blinking.
+
+        arg: It is used when behavior is 2 to set duty and cycle. It is defined as 
+             (duty << 4 | cycle). Here duty could be 0..4 and cycle 0..5 for 34, 
+             74, 149, 298, 596, 1192 ms respectively.
+
+      Examples:
+
+       1. To get default behavior for scan
+          iwpriv mshX ledbhv 1
+
+       2. To get default behavior while data transfer
+          iwpriv mshX ledbhv 9      
+       3. To turn off LED 2
+          iwpriv mshX ledbhv 2 2 1 0
+          iwpriv mshX ledbhv 10 2 1 0
+
+       4. To enable LED 2 and blink LED 1 while data transfer.
+          iwpriv mshX ledbhv 9 2 0 0
+          iwpriv mshX ledbhv 9 1 2 4
+
+       5. To change duty cycle of LED 2 during data transfer
+          iwpriv mshX ledbhv 9 2 2 36
+
+       6. To turn ON LED 2 when firmware is disassociated/disconnected.
+          iwpriv mshX ledbhv 0 2 0 0
+       
+
+fwt_add
+       This command is used to insert an entry into the FWT table. The list of
+       parameters must follow the following structure:
+
+       iwpriv ethX fwt_add da ra [metric dir rate ssn dsn hopcount ttl expiration sleepmode snr]
+
+       The parameters between brackets are optional, but they must appear in
+       the order specified.  For example, if you want to specify the metric,
+       you must also specify the dir, ssn, and dsn but you need not specify the
+       hopcount, expiration, sleepmode, or snr.  Any unspecified parameters
+       will be assigned the defaults specified below.
+
+       The different parameters are:-
+               da              -- DA MAC address in the form 00:11:22:33:44:55
+               ra              -- RA MAC address in the form 00:11:22:33:44:55
+               metric          -- route metric (cost: smaller-metric routes are
+                                  preferred, default is 0)
+               dir             -- direction (1 for direct, 0 for reverse,
+                                  default is 1)
+               rate            -- data rate used for transmission to the RA,
+                                  as specified for the rateadapt command,
+                                  default is 3 (11Mbps)
+               ssn             -- Source Sequence Number (time at the RA for
+                                  reverse routes.  Default is 0)
+               dsn             -- Destination Sequence Number (time at the DA
+                                  for direct routes.  Default is 0)
+               hopcount        -- hop count (currently unused, default is 0)
+               ttl             -- TTL (Only used in reverse entries)
+               expiration      -- entry expiration (in ticks, where a tick is
+                                  1024us, or ~ 1ms. Use 0 for an indefinite
+                                  entry, default is 0)
+               sleepmode       -- RA's sleep mode (currently unused, default is
+                                  0)
+               snr             -- SNR in the link to RA (currently unused,
+                                  default is 0)
+
+       The command does not return anything.
+
+fwt_del
+       This command is used to remove an entry to the FWT table. The list of
+       parameters must follow the following structure:
+
+               iwpriv ethX fwt_del da ra [dir]
+
+       where the different parameters are:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+               ra              -- RA MAC address (in the form "00:11:22:33:44:55")
+               dir             -- direction (1 for direct, 0 for reverse,
+                                  default is 1)
+
+       The command does not return anything.
+
+fwt_lookup
+       This command is used to get the best route in the FWT table to a given
+       host. The only parameter is the MAC address of the host that is being
+       looked for.
+
+               iwpriv ethX fwt_lookup da
+
+       where:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+
+       The command returns an output string identical to the one returned by
+       fwt_list described below.
+
+
+fwt_list
+       This command is used to list a route from the FWT table. The only
+       parameter is the index into the table. If you want to list all the
+       routes in a table, start with index=0, and keep listing until you get a
+       "(null)" string.  Note that the indicies may change as the fwt is
+       updated.  It is expected that most users will not use fwt_list directly,
+       but that a utility similar to the traditional route command will be used
+       to invoke fwt_list over and over.
+
+               iwpriv ethX fwt_list index
+
+       The output is a string of the following form:
+
+               da ra valid metric dir rate ssn dsn hopcount ttl expiration
+               sleepmode snr precursor
+
+       where the different fields are:-
+               da              -- DA MAC address (in the form "00:11:22:33:44:55")
+               ra              -- RA MAC address (in the form "00:11:22:33:44:55")
+               valid           -- whether the route is valid (0 if not valid)
+               metric          -- route metric (cost: smaller-metric routes are preferred)
+               dir             -- direction (1 for direct, 0 for reverse)
+               rate            -- data rate used for transmission to the RA,
+                                  as specified for the rateadapt command
+               ssn             -- Source Sequence Number (time at the RA for reverse routes)
+               dsn             -- Destination Sequence Number (time at the DA for direct routes)
+               hopcount        -- hop count (currently unused)
+               ttl             -- TTL (only used in reverse entries)
+               expiration      -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+               sleepmode       -- RA's sleep mode (currently unused)
+               snr             -- SNR in the link to RA (currently unused)
+               precursor       -- predecessor in direct routes
+
+fwt_list_route
+       This command is equivalent to fwt_list.
+
+fwt_list_neigh
+       This command is used to list a neighbor from the FWT table. The only
+       parameter is the neighbor ID. If you want to list all the neighbors in a
+       table, start with nid=0, and keep incrementing nid until you get a
+       "(null)" string.  Note that the nid from a fwt_list_route command can be
+       used as an input to this command.  Also note that this command is meant
+       mostly for debugging.  It is expected that users will use fwt_lookup.
+       One important reason for this is that the neighbor id may change as the
+       neighbor table is altered.
+
+               iwpriv ethX fwt_list_neigh nid
+
+       The output is a string of the following form:
+
+               ra sleepmode snr references
+
+       where the different fields are:-
+               ra              -- RA MAC address (in the form "00:11:22:33:44:55")
+               sleepmode       -- RA's sleep mode (currently unused)
+               snr             -- SNR in the link to RA (currently unused)
+               references      -- RA's reference counter
+
+fwt_reset
+       This command is used to reset the FWT table, getting rid of all the
+       entries. There are no input parameters.
+
+               iwpriv ethX fwt_reset
+
+       The command does not return anything.
+
+fwt_cleanup
+       This command is used to perform user-based garbage recollection. The
+       FWT table is checked, and all the entries that are expired or invalid
+       are cleaned. Note that this is exported to the driver for debugging
+       purposes, as garbage collection is also fired by the firmware when in
+       space problems. There are no input parameters.
+
+               iwpriv ethX fwt_cleanup
+
+       The command does returns the number of invalid/expired routes deleted.
+
+fwt_time
+       This command returns a card's internal time representation.  It is this
+       time that is used to represent the expiration times of FWT entries.  The
+       number is not consistent from card to card; it is simply a timer count.
+       The fwt_time command is used to inspect the timer so that expiration
+       times reported by fwt_list can be properly interpreted.
+
+               iwpriv ethX fwt_time
+
+mesh_get_ttl
+
+       The mesh ttl is the number of hops a mesh packet can traverse before it
+       is dropped.  This parameter is used to prevent infinite loops in the
+       mesh network.  The value returned by this function is the ttl assigned
+       to all mesh packets.  Currently there is no way to control the ttl on a
+       per packet or per socket basis.
+
+       iwpriv ethX mesh_get_ttl
+
+mesh_set_ttl ttl
+
+       Set the ttl.  The argument must be between 0 and 255.
+
+       iwpriv ethX mesh_set_ttl <ttl>
+
+mesh_get_bcastr
+
+       Shows the rate index used for mesh broadcast and multicast packets.
+       Rates are expressed in 2 * Mb/s, ie 11Mb/s is 22, 5.5Mb/s is 11, etc.
+
+       iwpriv ethX mesh_get_bcastr rate
+
+mesh_set_bcastr rate
+
+       Sets the rate index for mesh broadcast and muticast packets. Rates are
+       expressed in expressed in 2 * Mb/s, ie 11Mb/s is 22, 5.5Mb/s is 11, etc.
+
+       iwpriv ethX mesh_set_bcastr rate
+
+get_rreq_delay
+
+       Shows the delay to forward a RREQ frame. This delay allows the node to
+       forward just the best route in case the same RREQ arrives to the node
+       through different routes. The argument is shown in 1/100 seconds.
+
+       iwpriv ethX get_rreq_delay
+
+set_rreq_delay delay
+
+       Sets the RREQ forward delay. The delay is interpreted as 1/100 seconds.
+
+       iwpriv ethX set_rreq_delay delay
+
+get_route_exp
+
+       Shows the mesh route expiration time, in seconds.
+
+       iwpriv ethX get_route_exp
+
+set_route_exp time
+
+       Gets the mesh route, expiration time, in seconds.
+
+       iwpriv ethX set_route_exp time
+
+get_link_costs
+
+       Gets the mesh hop base cost for each used rate. The output gives us the
+       base cost for hops at 54Mbps, 36Mbps, 11Mbps and 1Mbps, in that order.
+       The base cost gets divided by a battery state factor to get the actual
+       cost. A cost of 0 means that rate is deactivated.
+
+       iwpriv ethX get_link_costs
+
+set_link_costs "cost54 cost36 cost11 cost1"
+
+       Sets the mesh hop base cost for the used speeds. The input parameter
+       will specify the cost for hops at 54Mbps, 36Mbps, 11Mbps and 1Mbps, in
+       that order. A cost of 0 will disable a specific rate.
+
+       iwpriv ethX set_link_costs "cost54 cost36 cost11 cost1"
+
 =========================
 ETHTOOL
 =========================
index c622e9b..c9c3640 100644 (file)
 /* Copyright (C) 2006, Red Hat, Inc. */
 
-#include <linux/bitops.h>
-#include <net/ieee80211.h>
 #include <linux/etherdevice.h>
 
 #include "assoc.h"
-#include "join.h"
 #include "decl.h"
-#include "hostcmd.h"
 #include "host.h"
+#include "scan.h"
 #include "cmd.h"
 
 
-static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
+       { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN]  __attribute__ ((aligned (2))) =
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
+/* The firmware needs certain bits masked out of the beacon-derviced capability
+ * field when associating/joining to BSSs.
+ */
+#define CAPINFO_MASK   (~(0xda00))
+
+
+
+/**
+ *  @brief Associate to a specific BSS discovered in a scan
+ *
+ *  @param priv      A pointer to struct lbs_private structure
+ *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
+ *
+ *  @return          0-success, otherwise fail
+ */
+static int lbs_associate(struct lbs_private *priv,
+       struct assoc_request *assoc_req)
+{
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
+                                   0, CMD_OPTION_WAITFORRSP,
+                                   0, assoc_req->bss.bssid);
+
+       if (ret)
+               goto done;
+
+       /* set preamble to firmware */
+       if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+           (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+               priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+       else
+               priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+
+       lbs_set_radio_control(priv);
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
+                                   0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  @brief Join an adhoc network found in a previous scan
+ *
+ *  @param priv         A pointer to struct lbs_private structure
+ *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
+ *                      to attempt to join
+ *
+ *  @return             0--success, -1--fail
+ */
+static int lbs_join_adhoc_network(struct lbs_private *priv,
+       struct assoc_request *assoc_req)
+{
+       struct bss_descriptor *bss = &assoc_req->bss;
+       int ret = 0;
+
+       lbs_deb_join("current SSID '%s', ssid length %u\n",
+               escape_essid(priv->curbssparams.ssid,
+               priv->curbssparams.ssid_len),
+               priv->curbssparams.ssid_len);
+       lbs_deb_join("requested ssid '%s', ssid length %u\n",
+               escape_essid(bss->ssid, bss->ssid_len),
+               bss->ssid_len);
+
+       /* check if the requested SSID is already joined */
+       if (priv->curbssparams.ssid_len &&
+           !lbs_ssid_cmp(priv->curbssparams.ssid,
+                       priv->curbssparams.ssid_len,
+                       bss->ssid, bss->ssid_len) &&
+           (priv->mode == IW_MODE_ADHOC) &&
+           (priv->connect_status == LBS_CONNECTED)) {
+               union iwreq_data wrqu;
+
+               lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
+                       "current, not attempting to re-join");
+
+               /* Send the re-association event though, because the association
+                * request really was successful, even if just a null-op.
+                */
+               memset(&wrqu, 0, sizeof(wrqu));
+               memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
+                      ETH_ALEN);
+               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+               wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+               goto out;
+       }
+
+       /* Use shortpreamble only when both creator and card supports
+          short preamble */
+       if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ||
+           !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+               lbs_deb_join("AdhocJoin: Long preamble\n");
+               priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+       } else {
+               lbs_deb_join("AdhocJoin: Short preamble\n");
+               priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+       }
+
+       lbs_set_radio_control(priv);
+
+       lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
+       lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
+
+       priv->adhoccreate = 0;
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
+                                   0, CMD_OPTION_WAITFORRSP,
+                                   OID_802_11_SSID, assoc_req);
+
+out:
+       return ret;
+}
+
+/**
+ *  @brief Start an Adhoc Network
+ *
+ *  @param priv         A pointer to struct lbs_private structure
+ *  @param adhocssid    The ssid of the Adhoc Network
+ *  @return             0--success, -1--fail
+ */
+static int lbs_start_adhoc_network(struct lbs_private *priv,
+       struct assoc_request *assoc_req)
+{
+       int ret = 0;
+
+       priv->adhoccreate = 1;
+
+       if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
+               lbs_deb_join("AdhocStart: Short preamble\n");
+               priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
+       } else {
+               lbs_deb_join("AdhocStart: Long preamble\n");
+               priv->preamble = CMD_TYPE_LONG_PREAMBLE;
+       }
+
+       lbs_set_radio_control(priv);
+
+       lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
+       lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
+                                   0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
+
+       return ret;
+}
+
+int lbs_stop_adhoc_network(struct lbs_private *priv)
+{
+       return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
+                                    0, CMD_OPTION_WAITFORRSP, 0, NULL);
+}
+
+static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
+                                       struct bss_descriptor *match_bss)
+{
+       if (!secinfo->wep_enabled  && !secinfo->WPAenabled
+           && !secinfo->WPA2enabled
+           && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
+           && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+           && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+               return 1;
+       else
+               return 0;
+}
+
+static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
+                                      struct bss_descriptor *match_bss)
+{
+       if (secinfo->wep_enabled && !secinfo->WPAenabled
+           && !secinfo->WPA2enabled
+           && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+               return 1;
+       else
+               return 0;
+}
+
+static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
+                               struct bss_descriptor *match_bss)
+{
+       if (!secinfo->wep_enabled && secinfo->WPAenabled
+           && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+           /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+           && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
+          )
+               return 1;
+       else
+               return 0;
+}
+
+static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
+                                struct bss_descriptor *match_bss)
+{
+       if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
+           (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+           /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+           (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
+          )
+               return 1;
+       else
+               return 0;
+}
+
+static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
+                                       struct bss_descriptor *match_bss)
+{
+       if (!secinfo->wep_enabled && !secinfo->WPAenabled
+           && !secinfo->WPA2enabled
+           && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
+           && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+           && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ *  @brief Check if a scanned network compatible with the driver settings
+ *
+ *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
+ * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
+ *    0       0        0       0      NONE      0      0    0   yes No security
+ *    1       0        0       0      NONE      1      0    0   yes Static WEP
+ *    0       1        0       0       x        1x     1    x   yes WPA
+ *    0       0        1       0       x        1x     x    1   yes WPA2
+ *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
+ *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
+ *
+ *
+ *  @param priv A pointer to struct lbs_private
+ *  @param index   Index in scantable to check against current driver settings
+ *  @param mode    Network mode: Infrastructure or IBSS
+ *
+ *  @return        Index in scantable, or error code if negative
+ */
+static int is_network_compatible(struct lbs_private *priv,
+                                struct bss_descriptor *bss, uint8_t mode)
+{
+       int matched = 0;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       if (bss->mode != mode)
+               goto done;
+
+       matched = match_bss_no_security(&priv->secinfo, bss);
+       if (matched)
+               goto done;
+       matched = match_bss_static_wep(&priv->secinfo, bss);
+       if (matched)
+               goto done;
+       matched = match_bss_wpa(&priv->secinfo, bss);
+       if (matched) {
+               lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
+                            "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+                            "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+                            priv->secinfo.wep_enabled ? "e" : "d",
+                            priv->secinfo.WPAenabled ? "e" : "d",
+                            priv->secinfo.WPA2enabled ? "e" : "d",
+                            (bss->capability & WLAN_CAPABILITY_PRIVACY));
+               goto done;
+       }
+       matched = match_bss_wpa2(&priv->secinfo, bss);
+       if (matched) {
+               lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
+                            "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+                            "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+                            priv->secinfo.wep_enabled ? "e" : "d",
+                            priv->secinfo.WPAenabled ? "e" : "d",
+                            priv->secinfo.WPA2enabled ? "e" : "d",
+                            (bss->capability & WLAN_CAPABILITY_PRIVACY));
+               goto done;
+       }
+       matched = match_bss_dynamic_wep(&priv->secinfo, bss);
+       if (matched) {
+               lbs_deb_scan("is_network_compatible() dynamic WEP: "
+                            "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
+                            bss->wpa_ie[0], bss->rsn_ie[0],
+                            (bss->capability & WLAN_CAPABILITY_PRIVACY));
+               goto done;
+       }
+
+       /* bss security settings don't match those configured on card */
+       lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
+                    "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
+                    bss->wpa_ie[0], bss->rsn_ie[0],
+                    priv->secinfo.wep_enabled ? "e" : "d",
+                    priv->secinfo.WPAenabled ? "e" : "d",
+                    priv->secinfo.WPA2enabled ? "e" : "d",
+                    (bss->capability & WLAN_CAPABILITY_PRIVACY));
+
+done:
+       lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
+       return matched;
+}
+
+/**
+ *  @brief This function finds a specific compatible BSSID in the scan list
+ *
+ *  Used in association code
+ *
+ *  @param priv  A pointer to struct lbs_private
+ *  @param bssid    BSSID to find in the scan list
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list, or error return code (< 0)
+ */
+static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
+                                             uint8_t *bssid, uint8_t mode)
+{
+       struct bss_descriptor *iter_bss;
+       struct bss_descriptor *found_bss = NULL;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       if (!bssid)
+               goto out;
+
+       lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
+
+       /* Look through the scan table for a compatible match.  The loop will
+        *   continue past a matched bssid that is not compatible in case there
+        *   is an AP with multiple SSIDs assigned to the same BSSID
+        */
+       mutex_lock(&priv->lock);
+       list_for_each_entry(iter_bss, &priv->network_list, list) {
+               if (compare_ether_addr(iter_bss->bssid, bssid))
+                       continue; /* bssid doesn't match */
+               switch (mode) {
+               case IW_MODE_INFRA:
+               case IW_MODE_ADHOC:
+                       if (!is_network_compatible(priv, iter_bss, mode))
+                               break;
+                       found_bss = iter_bss;
+                       break;
+               default:
+                       found_bss = iter_bss;
+                       break;
+               }
+       }
+       mutex_unlock(&priv->lock);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
+       return found_bss;
+}
+
+/**
+ *  @brief This function finds ssid in ssid list.
+ *
+ *  Used in association code
+ *
+ *  @param priv  A pointer to struct lbs_private
+ *  @param ssid     SSID to find in the list
+ *  @param bssid    BSSID to qualify the SSID selection (if provided)
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list
+ */
+static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
+                                            uint8_t *ssid, uint8_t ssid_len,
+                                            uint8_t *bssid, uint8_t mode,
+                                            int channel)
+{
+       u32 bestrssi = 0;
+       struct bss_descriptor *iter_bss = NULL;
+       struct bss_descriptor *found_bss = NULL;
+       struct bss_descriptor *tmp_oldest = NULL;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       mutex_lock(&priv->lock);
+
+       list_for_each_entry(iter_bss, &priv->network_list, list) {
+               if (!tmp_oldest ||
+                   (iter_bss->last_scanned < tmp_oldest->last_scanned))
+                       tmp_oldest = iter_bss;
+
+               if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
+                                ssid, ssid_len) != 0)
+                       continue; /* ssid doesn't match */
+               if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
+                       continue; /* bssid doesn't match */
+               if ((channel > 0) && (iter_bss->channel != channel))
+                       continue; /* channel doesn't match */
+
+               switch (mode) {
+               case IW_MODE_INFRA:
+               case IW_MODE_ADHOC:
+                       if (!is_network_compatible(priv, iter_bss, mode))
+                               break;
+
+                       if (bssid) {
+                               /* Found requested BSSID */
+                               found_bss = iter_bss;
+                               goto out;
+                       }
+
+                       if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
+                               bestrssi = SCAN_RSSI(iter_bss->rssi);
+                               found_bss = iter_bss;
+                       }
+                       break;
+               case IW_MODE_AUTO:
+               default:
+                       if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
+                               bestrssi = SCAN_RSSI(iter_bss->rssi);
+                               found_bss = iter_bss;
+                       }
+                       break;
+               }
+       }
+
+out:
+       mutex_unlock(&priv->lock);
+       lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
+       return found_bss;
+}
 
 static int assoc_helper_essid(struct lbs_private *priv,
                               struct assoc_request * assoc_req)
@@ -36,7 +457,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
                      escape_essid(assoc_req->ssid, assoc_req->ssid_len));
        if (assoc_req->mode == IW_MODE_INFRA) {
                lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
-                       assoc_req->ssid_len, 0);
+                       assoc_req->ssid_len);
 
                bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
                                assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
@@ -51,7 +472,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
                 *   scan data will cause us to join a non-existant adhoc network
                 */
                lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
-                       assoc_req->ssid_len, 1);
+                       assoc_req->ssid_len);
 
                /* Search for the requested SSID in the scan table */
                bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
@@ -162,34 +583,6 @@ done:
        return ret;
 }
 
-
-int lbs_update_channel(struct lbs_private *priv)
-{
-       int ret;
-
-       /* the channel in f/w could be out of sync; get the current channel */
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       ret = lbs_get_channel(priv);
-       if (ret > 0) {
-               priv->curbssparams.channel = ret;
-               ret = 0;
-       }
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-void lbs_sync_channel(struct work_struct *work)
-{
-       struct lbs_private *priv = container_of(work, struct lbs_private,
-               sync_channel);
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-       if (lbs_update_channel(priv))
-               lbs_pr_info("Channel synchronization failed.");
-       lbs_deb_leave(LBS_DEB_ASSOC);
-}
-
 static int assoc_helper_channel(struct lbs_private *priv,
                                 struct assoc_request * assoc_req)
 {
@@ -277,13 +670,11 @@ static int assoc_helper_wep_keys(struct lbs_private *priv,
 
        /* enable/disable the MAC's WEP packet filter */
        if (assoc_req->secinfo.wep_enabled)
-               priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
+               priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
        else
-               priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
+               priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
 
-       ret = lbs_set_mac_packet_filter(priv);
-       if (ret)
-               goto out;
+       lbs_set_mac_control(priv);
 
        mutex_lock(&priv->lock);
 
@@ -313,9 +704,7 @@ static int assoc_helper_secinfo(struct lbs_private *priv,
        memcpy(&priv->secinfo, &assoc_req->secinfo,
                sizeof(struct lbs_802_11_security));
 
-       ret = lbs_set_mac_packet_filter(priv);
-       if (ret)
-               goto out;
+       lbs_set_mac_control(priv);
 
        /* If RSN is already enabled, don't try to enable it again, since
         * ENABLE_RSN resets internal state machines and will clobber the
@@ -358,11 +747,7 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
 
        if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
                clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-               ret = lbs_prepare_and_send_command(priv,
-                                       CMD_802_11_KEY_MATERIAL,
-                                       CMD_ACT_SET,
-                                       CMD_OPTION_WAITFORRSP,
-                                       0, assoc_req);
+               ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
                assoc_req->flags = flags;
        }
 
@@ -372,11 +757,7 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
        if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
                clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
 
-               ret = lbs_prepare_and_send_command(priv,
-                                       CMD_802_11_KEY_MATERIAL,
-                                       CMD_ACT_SET,
-                                       CMD_OPTION_WAITFORRSP,
-                                       0, assoc_req);
+               ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
                assoc_req->flags = flags;
        }
 
@@ -411,11 +792,10 @@ static int should_deauth_infrastructure(struct lbs_private *priv,
 {
        int ret = 0;
 
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
        if (priv->connect_status != LBS_CONNECTED)
                return 0;
 
+       lbs_deb_enter(LBS_DEB_ASSOC);
        if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
                lbs_deb_assoc("Deauthenticating due to new SSID\n");
                ret = 1;
@@ -454,7 +834,7 @@ static int should_deauth_infrastructure(struct lbs_private *priv,
 
 out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return 0;
+       return ret;
 }
 
 
@@ -487,6 +867,91 @@ static int should_stop_adhoc(struct lbs_private *priv,
 }
 
 
+/**
+ *  @brief This function finds the best SSID in the Scan List
+ *
+ *  Search the scan table for the best SSID that also matches the current
+ *   adapter network preference (infrastructure or adhoc)
+ *
+ *  @param priv  A pointer to struct lbs_private
+ *
+ *  @return         index in BSSID list
+ */
+static struct bss_descriptor *lbs_find_best_ssid_in_list(
+       struct lbs_private *priv, uint8_t mode)
+{
+       uint8_t bestrssi = 0;
+       struct bss_descriptor *iter_bss;
+       struct bss_descriptor *best_bss = NULL;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       mutex_lock(&priv->lock);
+
+       list_for_each_entry(iter_bss, &priv->network_list, list) {
+               switch (mode) {
+               case IW_MODE_INFRA:
+               case IW_MODE_ADHOC:
+                       if (!is_network_compatible(priv, iter_bss, mode))
+                               break;
+                       if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
+                               break;
+                       bestrssi = SCAN_RSSI(iter_bss->rssi);
+                       best_bss = iter_bss;
+                       break;
+               case IW_MODE_AUTO:
+               default:
+                       if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
+                               break;
+                       bestrssi = SCAN_RSSI(iter_bss->rssi);
+                       best_bss = iter_bss;
+                       break;
+               }
+       }
+
+       mutex_unlock(&priv->lock);
+       lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
+       return best_bss;
+}
+
+/**
+ *  @brief Find the best AP
+ *
+ *  Used from association worker.
+ *
+ *  @param priv         A pointer to struct lbs_private structure
+ *  @param pSSID        A pointer to AP's ssid
+ *
+ *  @return             0--success, otherwise--fail
+ */
+static int lbs_find_best_network_ssid(struct lbs_private *priv,
+       uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
+       uint8_t *out_mode)
+{
+       int ret = -1;
+       struct bss_descriptor *found;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       priv->scan_ssid_len = 0;
+       lbs_scan_networks(priv, 1);
+       if (priv->surpriseremoved)
+               goto out;
+
+       found = lbs_find_best_ssid_in_list(priv, preferred_mode);
+       if (found && (found->ssid_len > 0)) {
+               memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
+               *out_ssid_len = found->ssid_len;
+               *out_mode = found->mode;
+               ret = 0;
+       }
+
+out:
+       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+       return ret;
+}
+
+
 void lbs_association_worker(struct work_struct *work)
 {
        struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -539,7 +1004,7 @@ void lbs_association_worker(struct work_struct *work)
        }
 
        if (find_any_ssid) {
-               u8 new_mode;
+               u8 new_mode = assoc_req->mode;
 
                ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
                                &assoc_req->ssid_len, assoc_req->mode, &new_mode);
@@ -641,17 +1106,11 @@ void lbs_association_worker(struct work_struct *work)
                }
 
                if (success) {
-                       lbs_deb_assoc("ASSOC: associated to '%s', %s\n",
-                               escape_essid(priv->curbssparams.ssid,
-                                            priv->curbssparams.ssid_len),
+                       lbs_deb_assoc("associated to %s\n",
                                print_mac(mac, priv->curbssparams.bssid));
                        lbs_prepare_and_send_command(priv,
                                CMD_802_11_RSSI,
                                0, CMD_OPTION_WAITFORRSP, 0, NULL);
-
-                       lbs_prepare_and_send_command(priv,
-                               CMD_802_11_GET_LOG,
-                               0, CMD_OPTION_WAITFORRSP, 0, NULL);
                } else {
                        ret = -1;
                }
@@ -750,3 +1209,705 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
        lbs_deb_leave(LBS_DEB_ASSOC);
        return assoc_req;
 }
+
+
+/**
+ *  @brief This function finds common rates between rate1 and card rates.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ *   care, either before or after calling this function
+ *
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param rate1       the buffer which keeps input and output
+ *  @param rate1_size  the size of rate1 buffer; new size of buffer on return
+ *
+ *  @return            0 or -1
+ */
+static int get_common_rates(struct lbs_private *priv,
+       u8 *rates,
+       u16 *rates_size)
+{
+       u8 *card_rates = lbs_bg_rates;
+       size_t num_card_rates = sizeof(lbs_bg_rates);
+       int ret = 0, i, j;
+       u8 tmp[30];
+       size_t tmp_size = 0;
+
+       /* For each rate in card_rates that exists in rate1, copy to tmp */
+       for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
+               for (j = 0; rates[j] && (j < *rates_size); j++) {
+                       if (rates[j] == card_rates[i])
+                               tmp[tmp_size++] = card_rates[i];
+               }
+       }
+
+       lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
+       lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates, num_card_rates);
+       lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+       lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
+
+       if (!priv->auto_rate) {
+               for (i = 0; i < tmp_size; i++) {
+                       if (tmp[i] == priv->cur_rate)
+                               goto done;
+               }
+               lbs_pr_alert("Previously set fixed data rate %#x isn't "
+                      "compatible with the network.\n", priv->cur_rate);
+               ret = -1;
+               goto done;
+       }
+       ret = 0;
+
+done:
+       memset(rates, 0, *rates_size);
+       *rates_size = min_t(int, tmp_size, *rates_size);
+       memcpy(rates, tmp, *rates_size);
+       return ret;
+}
+
+
+/**
+ *  @brief Sets the MSB on basic rates as the firmware requires
+ *
+ * Scan through an array and set the MSB for basic data rates.
+ *
+ *  @param rates     buffer of data rates
+ *  @param len       size of buffer
+ */
+static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               if (rates[i] == 0x02 || rates[i] == 0x04 ||
+                   rates[i] == 0x0b || rates[i] == 0x16)
+                       rates[i] |= 0x80;
+       }
+}
+
+/**
+ *  @brief Send Deauthentication Request
+ *
+ *  @param priv      A pointer to struct lbs_private structure
+ *  @return          0--success, -1--fail
+ */
+int lbs_send_deauthentication(struct lbs_private *priv)
+{
+       return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
+                                    0, CMD_OPTION_WAITFORRSP, 0, NULL);
+}
+
+/**
+ *  @brief This function prepares command of authenticate.
+ *
+ *  @param priv      A pointer to struct lbs_private structure
+ *  @param cmd       A pointer to cmd_ds_command structure
+ *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ *  @return         0 or -1
+ */
+int lbs_cmd_80211_authenticate(struct lbs_private *priv,
+                                struct cmd_ds_command *cmd,
+                                void *pdata_buf)
+{
+       struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
+       int ret = -1;
+       u8 *bssid = pdata_buf;
+       DECLARE_MAC_BUF(mac);
+
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+                       + S_DS_GEN);
+
+       /* translate auth mode to 802.11 defined wire value */
+       switch (priv->secinfo.auth_mode) {
+       case IW_AUTH_ALG_OPEN_SYSTEM:
+               pauthenticate->authtype = 0x00;
+               break;
+       case IW_AUTH_ALG_SHARED_KEY:
+               pauthenticate->authtype = 0x01;
+               break;
+       case IW_AUTH_ALG_LEAP:
+               pauthenticate->authtype = 0x80;
+               break;
+       default:
+               lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
+                       priv->secinfo.auth_mode);
+               goto out;
+       }
+
+       memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+       lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
+               print_mac(mac, bssid), pauthenticate->authtype);
+       ret = 0;
+
+out:
+       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+       return ret;
+}
+
+int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
+                                  struct cmd_ds_command *cmd)
+{
+       struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
+                            S_DS_GEN);
+
+       /* set AP MAC address */
+       memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
+
+       /* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+       dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+       lbs_deb_leave(LBS_DEB_JOIN);
+       return 0;
+}
+
+int lbs_cmd_80211_associate(struct lbs_private *priv,
+                             struct cmd_ds_command *cmd, void *pdata_buf)
+{
+       struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+       int ret = 0;
+       struct assoc_request *assoc_req = pdata_buf;
+       struct bss_descriptor *bss = &assoc_req->bss;
+       u8 *pos;
+       u16 tmpcap, tmplen;
+       struct mrvlietypes_ssidparamset *ssid;
+       struct mrvlietypes_phyparamset *phy;
+       struct mrvlietypes_ssparamset *ss;
+       struct mrvlietypes_ratesparamset *rates;
+       struct mrvlietypes_rsnparamset *rsn;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       pos = (u8 *) passo;
+
+       if (!priv) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
+
+       memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
+       pos += sizeof(passo->peerstaaddr);
+
+       /* set the listen interval */
+       passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+
+       pos += sizeof(passo->capability);
+       pos += sizeof(passo->listeninterval);
+       pos += sizeof(passo->bcnperiod);
+       pos += sizeof(passo->dtimperiod);
+
+       ssid = (struct mrvlietypes_ssidparamset *) pos;
+       ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
+       tmplen = bss->ssid_len;
+       ssid->header.len = cpu_to_le16(tmplen);
+       memcpy(ssid->ssid, bss->ssid, tmplen);
+       pos += sizeof(ssid->header) + tmplen;
+
+       phy = (struct mrvlietypes_phyparamset *) pos;
+       phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+       tmplen = sizeof(phy->fh_ds.dsparamset);
+       phy->header.len = cpu_to_le16(tmplen);
+       memcpy(&phy->fh_ds.dsparamset,
+              &bss->phyparamset.dsparamset.currentchan,
+              tmplen);
+       pos += sizeof(phy->header) + tmplen;
+
+       ss = (struct mrvlietypes_ssparamset *) pos;
+       ss->header.type = cpu_to_le16(TLV_TYPE_CF);
+       tmplen = sizeof(ss->cf_ibss.cfparamset);
+       ss->header.len = cpu_to_le16(tmplen);
+       pos += sizeof(ss->header) + tmplen;
+
+       rates = (struct mrvlietypes_ratesparamset *) pos;
+       rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+       memcpy(&rates->rates, &bss->rates, MAX_RATES);
+       tmplen = MAX_RATES;
+       if (get_common_rates(priv, rates->rates, &tmplen)) {
+               ret = -1;
+               goto done;
+       }
+       pos += sizeof(rates->header) + tmplen;
+       rates->header.len = cpu_to_le16(tmplen);
+       lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
+
+       /* Copy the infra. association rates into Current BSS state structure */
+       memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+       memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
+
+       /* Set MSB on basic rates as the firmware requires, but _after_
+        * copying to current bss rates.
+        */
+       lbs_set_basic_rate_flags(rates->rates, tmplen);
+
+       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+               rsn = (struct mrvlietypes_rsnparamset *) pos;
+               /* WPA_IE or WPA2_IE */
+               rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
+               tmplen = (u16) assoc_req->wpa_ie[1];
+               rsn->header.len = cpu_to_le16(tmplen);
+               memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
+               lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
+                       sizeof(rsn->header) + tmplen);
+               pos += sizeof(rsn->header) + tmplen;
+       }
+
+       /* update curbssparams */
+       priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
+
+       if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
+
+       /* set the capability info */
+       tmpcap = (bss->capability & CAPINFO_MASK);
+       if (bss->mode == IW_MODE_INFRA)
+               tmpcap |= WLAN_CAPABILITY_ESS;
+       passo->capability = cpu_to_le16(tmpcap);
+       lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
+int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
+                                struct cmd_ds_command *cmd, void *pdata_buf)
+{
+       struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+       int ret = 0;
+       int cmdappendsize = 0;
+       struct assoc_request *assoc_req = pdata_buf;
+       u16 tmpcap = 0;
+       size_t ratesize = 0;
+
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       if (!priv) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
+
+       /*
+        * Fill in the parameters for 2 data structures:
+        *   1. cmd_ds_802_11_ad_hoc_start command
+        *   2. priv->scantable[i]
+        *
+        * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
+        *   probe delay, and cap info.
+        *
+        * Firmware will fill up beacon period, DTIM, Basic rates
+        *   and operational rates.
+        */
+
+       memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
+       memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
+
+       lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
+               escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+               assoc_req->ssid_len);
+
+       /* set the BSS type */
+       adhs->bsstype = CMD_BSS_TYPE_IBSS;
+       priv->mode = IW_MODE_ADHOC;
+       if (priv->beacon_period == 0)
+               priv->beacon_period = MRVDRV_BEACON_INTERVAL;
+       adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
+
+       /* set Physical param set */
+#define DS_PARA_IE_ID   3
+#define DS_PARA_IE_LEN  1
+
+       adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
+       adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
+
+       WARN_ON(!assoc_req->channel);
+
+       lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
+                    assoc_req->channel);
+
+       adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
+
+       /* set IBSS param set */
+#define IBSS_PARA_IE_ID   6
+#define IBSS_PARA_IE_LEN  2
+
+       adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
+       adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
+       adhs->ssparamset.ibssparamset.atimwindow = 0;
+
+       /* set capability info */
+       tmpcap = WLAN_CAPABILITY_IBSS;
+       if (assoc_req->secinfo.wep_enabled) {
+               lbs_deb_join("ADHOC_S_CMD: WEP enabled, "
+                       "setting privacy on\n");
+               tmpcap |= WLAN_CAPABILITY_PRIVACY;
+       } else {
+               lbs_deb_join("ADHOC_S_CMD: WEP disabled, "
+                       "setting privacy off\n");
+       }
+       adhs->capability = cpu_to_le16(tmpcap);
+
+       /* probedelay */
+       adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+
+       memset(adhs->rates, 0, sizeof(adhs->rates));
+       ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
+       memcpy(adhs->rates, lbs_bg_rates, ratesize);
+
+       /* Copy the ad-hoc creating rates into Current BSS state structure */
+       memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+       memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
+
+       /* Set MSB on basic rates as the firmware requires, but _after_
+        * copying to current bss rates.
+        */
+       lbs_set_basic_rate_flags(adhs->rates, ratesize);
+
+       lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+              adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
+
+       lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+       if (lbs_create_dnld_countryinfo_11d(priv)) {
+               lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+               ret = -1;
+               goto done;
+       }
+
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
+                               S_DS_GEN + cmdappendsize);
+
+       ret = 0;
+done:
+       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+       return ret;
+}
+
+int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd)
+{
+       cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
+       cmd->size = cpu_to_le16(S_DS_GEN);
+
+       return 0;
+}
+
+int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
+                               struct cmd_ds_command *cmd, void *pdata_buf)
+{
+       struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
+       struct assoc_request *assoc_req = pdata_buf;
+       struct bss_descriptor *bss = &assoc_req->bss;
+       int cmdappendsize = 0;
+       int ret = 0;
+       u16 ratesize = 0;
+       DECLARE_MAC_BUF(mac);
+
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
+
+       join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
+       join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
+
+       memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
+       memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
+
+       memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
+              sizeof(union ieeetypes_phyparamset));
+
+       memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
+              sizeof(union IEEEtypes_ssparamset));
+
+       join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+       lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+              bss->capability, CAPINFO_MASK);
+
+       /* information on BSSID descriptor passed to FW */
+       lbs_deb_join(
+              "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
+              print_mac(mac, join_cmd->bss.bssid),
+              join_cmd->bss.ssid);
+
+       /* failtimeout */
+       join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+       /* probedelay */
+       join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+
+       priv->curbssparams.channel = bss->channel;
+
+       /* Copy Data rates from the rates recorded in scan response */
+       memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
+       ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
+       memcpy(join_cmd->bss.rates, bss->rates, ratesize);
+       if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
+               lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
+               ret = -1;
+               goto done;
+       }
+
+       /* Copy the ad-hoc creating rates into Current BSS state structure */
+       memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+       memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
+
+       /* Set MSB on basic rates as the firmware requires, but _after_
+        * copying to current bss rates.
+        */
+       lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
+
+       join_cmd->bss.ssparamset.ibssparamset.atimwindow =
+           cpu_to_le16(bss->atimwindow);
+
+       if (assoc_req->secinfo.wep_enabled) {
+               u16 tmp = le16_to_cpu(join_cmd->bss.capability);
+               tmp |= WLAN_CAPABILITY_PRIVACY;
+               join_cmd->bss.capability = cpu_to_le16(tmp);
+       }
+
+       if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
+               /* wake up first */
+               __le32 Localpsmode;
+
+               Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
+               ret = lbs_prepare_and_send_command(priv,
+                                           CMD_802_11_PS_MODE,
+                                           CMD_ACT_SET,
+                                           0, 0, &Localpsmode);
+
+               if (ret) {
+                       ret = -1;
+                       goto done;
+               }
+       }
+
+       if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
+               ret = -1;
+               goto done;
+       }
+
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
+                               S_DS_GEN + cmdappendsize);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+       return ret;
+}
+
+int lbs_ret_80211_associate(struct lbs_private *priv,
+                             struct cmd_ds_command *resp)
+{
+       int ret = 0;
+       union iwreq_data wrqu;
+       struct ieeetypes_assocrsp *passocrsp;
+       struct bss_descriptor *bss;
+       u16 status_code;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       if (!priv->in_progress_assoc_req) {
+               lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
+               ret = -1;
+               goto done;
+       }
+       bss = &priv->in_progress_assoc_req->bss;
+
+       passocrsp = (struct ieeetypes_assocrsp *) &resp->params;
+
+       /*
+        * Older FW versions map the IEEE 802.11 Status Code in the association
+        * response to the following values returned in passocrsp->statuscode:
+        *
+        *    IEEE Status Code                Marvell Status Code
+        *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
+        *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
+        *
+        * Other response codes:
+        *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+        *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+        *                                    association response from the AP)
+        */
+
+       status_code = le16_to_cpu(passocrsp->statuscode);
+       switch (status_code) {
+       case 0x00:
+               break;
+       case 0x01:
+               lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
+               break;
+       case 0x02:
+               lbs_deb_assoc("ASSOC_RESP: internal timer "
+                       "expired while waiting for the AP\n");
+               break;
+       case 0x03:
+               lbs_deb_assoc("ASSOC_RESP: association "
+                       "refused by AP\n");
+               break;
+       case 0x04:
+               lbs_deb_assoc("ASSOC_RESP: authentication "
+                       "refused by AP\n");
+               break;
+       default:
+               lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
+                       " unknown\n", status_code);
+               break;
+       }
+
+       if (status_code) {
+               lbs_mac_event_disconnected(priv);
+               ret = -1;
+               goto done;
+       }
+
+       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
+               le16_to_cpu(resp->size) - S_DS_GEN);
+
+       /* Send a Media Connected event, according to the Spec */
+       priv->connect_status = LBS_CONNECTED;
+
+       /* Update current SSID and BSSID */
+       memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+       priv->curbssparams.ssid_len = bss->ssid_len;
+       memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
+
+       priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+       priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+       memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
+       memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
+       priv->nextSNRNF = 0;
+       priv->numSNRNF = 0;
+
+       netif_carrier_on(priv->dev);
+       if (!priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
+int lbs_ret_80211_disassociate(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       lbs_mac_event_disconnected(priv);
+
+       lbs_deb_leave(LBS_DEB_JOIN);
+       return 0;
+}
+
+int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
+                                struct cmd_ds_command *resp)
+{
+       int ret = 0;
+       u16 command = le16_to_cpu(resp->command);
+       u16 result = le16_to_cpu(resp->result);
+       struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+       union iwreq_data wrqu;
+       struct bss_descriptor *bss;
+       DECLARE_MAC_BUF(mac);
+
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       padhocresult = &resp->params.result;
+
+       lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
+       lbs_deb_join("ADHOC_RESP: command = %x\n", command);
+       lbs_deb_join("ADHOC_RESP: result = %x\n", result);
+
+       if (!priv->in_progress_assoc_req) {
+               lbs_deb_join("ADHOC_RESP: no in-progress association "
+                       "request\n");
+               ret = -1;
+               goto done;
+       }
+       bss = &priv->in_progress_assoc_req->bss;
+
+       /*
+        * Join result code 0 --> SUCCESS
+        */
+       if (result) {
+               lbs_deb_join("ADHOC_RESP: failed\n");
+               if (priv->connect_status == LBS_CONNECTED)
+                       lbs_mac_event_disconnected(priv);
+               ret = -1;
+               goto done;
+       }
+
+       /*
+        * Now the join cmd should be successful
+        * If BSSID has changed use SSID to compare instead of BSSID
+        */
+       lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
+               escape_essid(bss->ssid, bss->ssid_len));
+
+       /* Send a Media Connected event, according to the Spec */
+       priv->connect_status = LBS_CONNECTED;
+
+       if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
+               /* Update the created network descriptor with the new BSSID */
+               memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
+       }
+
+       /* Set the BSSID from the joined/started descriptor */
+       memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
+
+       /* Set the new SSID to current SSID */
+       memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+       priv->curbssparams.ssid_len = bss->ssid_len;
+
+       netif_carrier_on(priv->dev);
+       if (!priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+       lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
+       lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
+       lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
+                    print_mac(mac, padhocresult->bssid));
+
+done:
+       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+       return ret;
+}
+
+int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       lbs_mac_event_disconnected(priv);
+
+       lbs_deb_leave(LBS_DEB_JOIN);
+       return 0;
+}
index 08372bb..c516fbe 100644 (file)
@@ -7,6 +7,33 @@
 
 void lbs_association_worker(struct work_struct *work);
 struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
-void lbs_sync_channel(struct work_struct *work);
+
+struct cmd_ds_command;
+int lbs_cmd_80211_authenticate(struct lbs_private *priv,
+                                       struct cmd_ds_command *cmd,
+                                       void *pdata_buf);
+int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
+                                      struct cmd_ds_command *cmd,
+                                      void *pdata_buf);
+int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd);
+int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
+                                       struct cmd_ds_command *cmd,
+                                       void *pdata_buf);
+int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
+                                         struct cmd_ds_command *cmd);
+int lbs_cmd_80211_associate(struct lbs_private *priv,
+                                    struct cmd_ds_command *cmd,
+                                    void *pdata_buf);
+
+int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
+                                       struct cmd_ds_command *resp);
+int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv);
+int lbs_ret_80211_disassociate(struct lbs_private *priv);
+int lbs_ret_80211_associate(struct lbs_private *priv,
+                                    struct cmd_ds_command *resp);
+
+int lbs_stop_adhoc_network(struct lbs_private *priv);
+
+int lbs_send_deauthentication(struct lbs_private *priv);
 
 #endif /* _LBS_ASSOC_H */
index 4d06dec..8124fd9 100644 (file)
@@ -4,19 +4,57 @@
   */
 
 #include <net/iw_handler.h>
+#include <linux/kfifo.h>
 #include "host.h"
 #include "hostcmd.h"
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
-#include "join.h"
+#include "assoc.h"
 #include "wext.h"
 #include "cmd.h"
 
 static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
-static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
-                   struct cmd_ctrl_node *ptempnode,
-                   void *pdata_buf);
+
+
+/**
+ *  @brief Simple callback that copies response back into command
+ *
+ *  @param priv        A pointer to struct lbs_private structure
+ *  @param extra       A pointer to the original command structure for which
+ *                      'resp' is a response
+ *  @param resp         A pointer to the command response
+ *
+ *  @return            0 on success, error on failure
+ */
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+                    struct cmd_header *resp)
+{
+       struct cmd_header *buf = (void *)extra;
+       uint16_t copy_len;
+
+       copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
+       memcpy(buf, resp, copy_len);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
+
+/**
+ *  @brief Simple callback that ignores the result. Use this if
+ *  you just want to send a command to the hardware, but don't
+ *  care for the result.
+ *
+ *  @param priv         ignored
+ *  @param extra        ignored
+ *  @param resp         ignored
+ *
+ *  @return            0 for success
+ */
+static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
+                    struct cmd_header *resp)
+{
+       return 0;
+}
 
 
 /**
@@ -60,13 +98,24 @@ int lbs_update_hw_spec(struct lbs_private *priv)
                goto out;
 
        priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
-       memcpy(priv->fwreleasenumber, cmd.fwreleasenumber, 4);
 
-       lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
-                   priv->fwreleasenumber[2], priv->fwreleasenumber[1],
-                   priv->fwreleasenumber[0], priv->fwreleasenumber[3]);
-       lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
-                   print_mac(mac, cmd.permanentaddr));
+       /* The firmware release is in an interesting format: the patch
+        * level is in the most significant nibble ... so fix that: */
+       priv->fwrelease = le32_to_cpu(cmd.fwrelease);
+       priv->fwrelease = (priv->fwrelease << 8) |
+               (priv->fwrelease >> 24 & 0xff);
+
+       /* Some firmware capabilities:
+        * CF card    firmware 5.0.16p0:   cap 0x00000303
+        * USB dongle firmware 5.110.17p2: cap 0x00000303
+        */
+       printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n",
+               print_mac(mac, cmd.permanentaddr),
+               priv->fwrelease >> 24 & 0xff,
+               priv->fwrelease >> 16 & 0xff,
+               priv->fwrelease >>  8 & 0xff,
+               priv->fwrelease       & 0xff,
+               priv->fwcapinfo);
        lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
                    cmd.hwifversion, cmd.version);
 
@@ -132,8 +181,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
 }
 EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
 
-static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
-                                  struct cmd_ds_command *cmd,
+static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
                                   u16 cmd_action)
 {
        struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
@@ -248,6 +296,7 @@ int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
 
        lbs_deb_enter(LBS_DEB_CMD);
 
+       memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 
@@ -311,7 +360,9 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(cmd_action);
 
-       if (cmd_action == CMD_ACT_SET) {
+       if (cmd_action == CMD_ACT_GET)
+               cmd.enable = 0;
+       else {
                if (*enable)
                        cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
                else
@@ -327,81 +378,108 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
        return ret;
 }
 
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
-                            struct enc_key * pkey)
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
+                            struct enc_key *key)
 {
        lbs_deb_enter(LBS_DEB_CMD);
 
-       if (pkey->flags & KEY_INFO_WPA_ENABLED) {
-               pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
-       }
-       if (pkey->flags & KEY_INFO_WPA_UNICAST) {
-               pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
-       }
-       if (pkey->flags & KEY_INFO_WPA_MCAST) {
-               pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-       }
+       if (key->flags & KEY_INFO_WPA_ENABLED)
+               keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
+       if (key->flags & KEY_INFO_WPA_UNICAST)
+               keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+       if (key->flags & KEY_INFO_WPA_MCAST)
+               keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+
+       keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+       keyparam->keytypeid = cpu_to_le16(key->type);
+       keyparam->keylen = cpu_to_le16(key->len);
+       memcpy(keyparam->key, key->key, key->len);
 
-       pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
-       pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
-       pkeyparamset->keylen = cpu_to_le16(pkey->len);
-       memcpy(pkeyparamset->key, pkey->key, pkey->len);
-       pkeyparamset->length = cpu_to_le16(  sizeof(pkeyparamset->keytypeid)
-                                               + sizeof(pkeyparamset->keyinfo)
-                                               + sizeof(pkeyparamset->keylen)
-                                               + sizeof(pkeyparamset->key));
+       /* Length field doesn't include the {type,length} header */
+       keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
        lbs_deb_leave(LBS_DEB_CMD);
 }
 
-static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
-                                       struct cmd_ds_command *cmd,
-                                       u16 cmd_action,
-                                       u32 cmd_oid, void *pdata_buf)
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+                               struct assoc_request *assoc)
 {
-       struct cmd_ds_802_11_key_material *pkeymaterial =
-           &cmd->params.keymaterial;
-       struct assoc_request * assoc_req = pdata_buf;
+       struct cmd_ds_802_11_key_material cmd;
        int ret = 0;
        int index = 0;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
-       cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
-       pkeymaterial->action = cpu_to_le16(cmd_action);
+       cmd.action = cpu_to_le16(cmd_action);
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 
        if (cmd_action == CMD_ACT_GET) {
-               cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
-               ret = 0;
-               goto done;
-       }
+               cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
+       } else {
+               memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
 
-       memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+               if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
+                       set_one_wpa_key(&cmd.keyParamSet[index],
+                                       &assoc->wpa_unicast_key);
+                       index++;
+               }
 
-       if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-               set_one_wpa_key(&pkeymaterial->keyParamSet[index],
-                               &assoc_req->wpa_unicast_key);
-               index++;
-       }
+               if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
+                       set_one_wpa_key(&cmd.keyParamSet[index],
+                                       &assoc->wpa_mcast_key);
+                       index++;
+               }
 
-       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
-               set_one_wpa_key(&pkeymaterial->keyParamSet[index],
-                               &assoc_req->wpa_mcast_key);
-               index++;
+               /* The common header and as many keys as we included */
+               cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
+                                                   keyParamSet[index]));
        }
+       ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+       /* Copy the returned key to driver private data */
+       if (!ret && cmd_action == CMD_ACT_GET) {
+               void *buf_ptr = cmd.keyParamSet;
+               void *resp_end = &(&cmd)[1];
+
+               while (buf_ptr < resp_end) {
+                       struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
+                       struct enc_key *key;
+                       uint16_t param_set_len = le16_to_cpu(keyparam->length);
+                       uint16_t key_len = le16_to_cpu(keyparam->keylen);
+                       uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
+                       uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
+                       void *end;
+
+                       end = (void *)keyparam + sizeof(keyparam->type)
+                               + sizeof(keyparam->length) + param_set_len;
+
+                       /* Make sure we don't access past the end of the IEs */
+                       if (end > resp_end)
+                               break;
 
-       cmd->size = cpu_to_le16(  S_DS_GEN
-                               + sizeof (pkeymaterial->action)
-                               + (index * sizeof(struct MrvlIEtype_keyParamSet)));
+                       if (key_flags & KEY_INFO_WPA_UNICAST)
+                               key = &priv->wpa_unicast_key;
+                       else if (key_flags & KEY_INFO_WPA_MCAST)
+                               key = &priv->wpa_mcast_key;
+                       else
+                               break;
 
-       ret = 0;
+                       /* Copy returned key into driver */
+                       memset(key, 0, sizeof(struct enc_key));
+                       if (key_len > sizeof(key->key))
+                               break;
+                       key->type = key_type;
+                       key->flags = key_flags;
+                       key->len = key_len;
+                       memcpy(key->key, keyparam->key, key->len);
+
+                       buf_ptr = end + 1;
+               }
+       }
 
-done:
        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
        return ret;
 }
 
-static int lbs_cmd_802_11_reset(struct lbs_private *priv,
-                                struct cmd_ds_command *cmd, int cmd_action)
+static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action)
 {
        struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
 
@@ -415,30 +493,6 @@ static int lbs_cmd_802_11_reset(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
-                                  struct cmd_ds_command *cmd)
-{
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
-       cmd->size =
-               cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
-                                   struct cmd_ds_command *cmd)
-{
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
-       cmd->size =
-           cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
                                    struct cmd_ds_command *cmd,
                                    int cmd_action,
@@ -559,8 +613,7 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
-                                      struct cmd_ds_command *cmd,
+static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd,
                                       u16 cmd_action, void *pdata_buf)
 {
 
@@ -603,8 +656,7 @@ static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
-                                     struct cmd_ds_command *cmd,
+static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
                                      u16 cmd_action, void *pdata_buf)
 {
        struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
@@ -762,6 +814,7 @@ int lbs_get_channel(struct lbs_private *priv)
 
        lbs_deb_enter(LBS_DEB_CMD);
 
+       memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
 
@@ -777,6 +830,22 @@ out:
        return ret;
 }
 
+int lbs_update_channel(struct lbs_private *priv)
+{
+       int ret;
+
+       /* the channel in f/w could be out of sync; get the current channel */
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       ret = lbs_get_channel(priv);
+       if (ret > 0) {
+               priv->curbssparams.channel = ret;
+               ret = 0;
+       }
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
 /**
  *  @brief Set the radio channel
  *
@@ -793,6 +862,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
 
        lbs_deb_enter(LBS_DEB_CMD);
 
+       memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
        cmd.channel = cpu_to_le16(channel);
@@ -831,8 +901,7 @@ static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_reg_access(struct lbs_private *priv,
-                              struct cmd_ds_command *cmdptr,
+static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
                               u8 cmd_action, void *pdata_buf)
 {
        struct lbs_offset_value *offval;
@@ -906,53 +975,7 @@ static int lbs_cmd_reg_access(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
-                                      struct cmd_ds_command *cmd,
-                                      u16 cmd_action)
-{
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
-                            S_DS_GEN);
-       cmd->result = 0;
-
-       cmd->params.macadd.action = cpu_to_le16(cmd_action);
-
-       if (cmd_action == CMD_ACT_SET) {
-               memcpy(cmd->params.macadd.macadd,
-                      priv->current_addr, ETH_ALEN);
-               lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
-       }
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
-                                        struct cmd_ds_command *cmd,
-                                        int cmd_action, void *pdata_buf)
-{
-       struct lbs_ioctl_regrdwr *ea = pdata_buf;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
-                               S_DS_GEN);
-       cmd->result = 0;
-
-       cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
-       cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
-       cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
-       cmd->params.rdeeprom.value = 0;
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-static int lbs_cmd_bt_access(struct lbs_private *priv,
-                              struct cmd_ds_command *cmd,
+static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
                               u16 cmd_action, void *pdata_buf)
 {
        struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
@@ -989,8 +1012,7 @@ static int lbs_cmd_bt_access(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_cmd_fwt_access(struct lbs_private *priv,
-                              struct cmd_ds_command *cmd,
+static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
                               u16 cmd_action, void *pdata_buf)
 {
        struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
@@ -1029,7 +1051,6 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
        lbs_deb_leave(LBS_DEB_CMD);
        return ret;
 }
-EXPORT_SYMBOL_GPL(lbs_mesh_access);
 
 int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
 {
@@ -1143,9 +1164,9 @@ static void lbs_submit_command(struct lbs_private *priv,
            command == CMD_802_11_AUTHENTICATE)
                timeo = 10 * HZ;
 
-       lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
-                    command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
-       lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+       lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
+                    command, le16_to_cpu(cmd->seqnum), cmdsize);
+       lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
 
        ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
 
@@ -1154,9 +1175,7 @@ static void lbs_submit_command(struct lbs_private *priv,
                /* Let the timer kick in and retry, and potentially reset
                   the whole thing if the condition persists */
                timeo = HZ;
-       } else
-               lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n",
-                           command, jiffies);
+       }
 
        /* Setup the timer after transmit command */
        mod_timer(&priv->command_timer, jiffies + timeo);
@@ -1164,24 +1183,6 @@ static void lbs_submit_command(struct lbs_private *priv,
        lbs_deb_leave(LBS_DEB_HOST);
 }
 
-static int lbs_cmd_mac_control(struct lbs_private *priv,
-                               struct cmd_ds_command *cmd)
-{
-       struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
-       mac->action = cpu_to_le16(priv->currentpacketfilter);
-
-       lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
-                   le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 /**
  *  This function inserts command node to cmdfreeq
  *  after cleans it. Requires priv->driver_lock held.
@@ -1224,7 +1225,7 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
        cmd->cmdwaitqwoken = 1;
        wake_up_interruptible(&cmd->cmdwait_q);
 
-       if (!cmd->callback)
+       if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
                __lbs_cleanup_and_insert_cmd(priv, cmd);
        priv->cur_cmd = NULL;
 }
@@ -1268,18 +1269,20 @@ int lbs_set_radio_control(struct lbs_private *priv)
        return ret;
 }
 
-int lbs_set_mac_packet_filter(struct lbs_private *priv)
+void lbs_set_mac_control(struct lbs_private *priv)
 {
-       int ret = 0;
+       struct cmd_ds_mac_control cmd;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
-       /* Send MAC control command to station */
-       ret = lbs_prepare_and_send_command(priv,
-                                   CMD_MAC_CONTROL, 0, 0, 0, NULL);
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(priv->mac_control);
+       cmd.reserved = 0;
 
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
+       lbs_cmd_async(priv, CMD_MAC_CONTROL,
+               &cmd.hdr, sizeof(cmd));
+
+       lbs_deb_leave(LBS_DEB_CMD);
 }
 
 /**
@@ -1328,7 +1331,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                goto done;
        }
 
-       lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
+       cmdnode->callback = NULL;
+       cmdnode->callback_arg = (unsigned long)pdata_buf;
 
        cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
 
@@ -1343,15 +1347,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
 
        switch (cmd_no) {
        case CMD_802_11_PS_MODE:
-               ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
-               break;
-
-       case CMD_802_11_SCAN:
-               ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
-               break;
-
-       case CMD_MAC_CONTROL:
-               ret = lbs_cmd_mac_control(priv, cmdptr);
+               ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
                break;
 
        case CMD_802_11_ASSOCIATE:
@@ -1366,25 +1362,15 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
        case CMD_802_11_AD_HOC_START:
                ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
                break;
-       case CMD_CODE_DNLD:
-               break;
 
        case CMD_802_11_RESET:
-               ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
-               break;
-
-       case CMD_802_11_GET_LOG:
-               ret = lbs_cmd_802_11_get_log(priv, cmdptr);
+               ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
                break;
 
        case CMD_802_11_AUTHENTICATE:
                ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
                break;
 
-       case CMD_802_11_GET_STAT:
-               ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
-               break;
-
        case CMD_802_11_SNMP_MIB:
                ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
                                               cmd_action, cmd_oid, pdata_buf);
@@ -1393,12 +1379,12 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
        case CMD_MAC_REG_ACCESS:
        case CMD_BBP_REG_ACCESS:
        case CMD_RF_REG_ACCESS:
-               ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+               ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
                break;
 
        case CMD_802_11_RF_TX_POWER:
-               ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
-                                                 cmd_action, pdata_buf);
+               ret = lbs_cmd_802_11_rf_tx_power(cmdptr,
+                                                cmd_action, pdata_buf);
                break;
 
        case CMD_802_11_RATE_ADAPT_RATESET:
@@ -1411,7 +1397,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                break;
 
        case CMD_802_11_MONITOR_MODE:
-               ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
+               ret = lbs_cmd_802_11_monitor_mode(cmdptr,
                                          cmd_action, pdata_buf);
                break;
 
@@ -1424,26 +1410,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                break;
 
        case CMD_802_11_AD_HOC_STOP:
-               ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
-               break;
-
-       case CMD_802_11_KEY_MATERIAL:
-               ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
-                               cmd_oid, pdata_buf);
-               break;
-
-       case CMD_802_11_PAIRWISE_TSC:
-               break;
-       case CMD_802_11_GROUP_TSC:
-               break;
-
-       case CMD_802_11_MAC_ADDRESS:
-               ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
-               break;
-
-       case CMD_802_11_EEPROM_ACCESS:
-               ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
-                                                   cmd_action, pdata_buf);
+               ret = lbs_cmd_80211_ad_hoc_stop(cmdptr);
                break;
 
        case CMD_802_11_SET_AFC:
@@ -1499,22 +1466,12 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                        break;
                }
 
-       case CMD_802_11_PWR_CFG:
-               cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
-               cmdptr->size =
-                   cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
-                                    S_DS_GEN);
-               memmove(&cmdptr->params.pwrcfg, pdata_buf,
-                       sizeof(struct cmd_ds_802_11_pwr_cfg));
-
-               ret = 0;
-               break;
        case CMD_BT_ACCESS:
-               ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+               ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
                break;
 
        case CMD_FWT_ACCESS:
-               ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+               ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
                break;
 
        case CMD_GET_TSF:
@@ -1565,7 +1522,6 @@ done:
        lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
        return ret;
 }
-EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
 
 /**
  *  @brief This function allocates the command buffer and link
@@ -1687,36 +1643,6 @@ static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
        return tempnode;
 }
 
-/**
- *  @brief This function cleans command node.
- *
- *  @param ptempnode   A pointer to cmdCtrlNode structure
- *  @return            n/a
- */
-
-/**
- *  @brief This function initializes the command node.
- *
- *  @param priv                A pointer to struct lbs_private structure
- *  @param ptempnode   A pointer to cmd_ctrl_node structure
- *  @param pdata_buf   A pointer to informaion buffer
- *  @return            0 or -1
- */
-static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
-                                 struct cmd_ctrl_node *ptempnode,
-                                 void *pdata_buf)
-{
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       if (!ptempnode)
-               return;
-
-       ptempnode->callback = NULL;
-       ptempnode->callback_arg = (unsigned long)pdata_buf;
-
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
 /**
  *  @brief This function executes next command in command
  *  pending queue. It will put fimware back to PS mode
@@ -1732,9 +1658,9 @@ int lbs_execute_next_command(struct lbs_private *priv)
        unsigned long flags;
        int ret = 0;
 
-       // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
-       // only caller to us is lbs_thread() and we get even when a
-       // data packet is received
+       /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+        * only caller to us is lbs_thread() and we get even when a
+        * data packet is received */
        lbs_deb_enter(LBS_DEB_THREAD);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
@@ -1898,44 +1824,35 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
        lbs_deb_leave(LBS_DEB_WEXT);
 }
 
-static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
+static void lbs_send_confirmsleep(struct lbs_private *priv)
 {
        unsigned long flags;
-       int ret = 0;
+       int ret;
 
        lbs_deb_enter(LBS_DEB_HOST);
+       lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
+               sizeof(confirm_sleep));
 
-       lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
-              size);
-
-       lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
-
-       ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
+       ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
+               sizeof(confirm_sleep));
+       if (ret) {
+               lbs_pr_alert("confirm_sleep failed\n");
+               goto out;
+       }
 
        spin_lock_irqsave(&priv->driver_lock, flags);
-       if (priv->intcounter || priv->currenttxskb)
-               lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
-                      priv->intcounter, priv->currenttxskb);
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-       if (ret) {
-               lbs_pr_alert(
-                      "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
-       } else {
-               spin_lock_irqsave(&priv->driver_lock, flags);
-               if (!priv->intcounter) {
-                       priv->psstate = PS_STATE_SLEEP;
-               } else {
-                       lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
-                              priv->intcounter);
-               }
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
+       /* We don't get a response on the sleep-confirmation */
+       priv->dnld_sent = DNLD_RES_RECEIVED;
 
-               lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
-       }
+       /* If nothing to do, go back to sleep (?) */
+       if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
+               priv->psstate = PS_STATE_SLEEP;
 
-       lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-       return ret;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+out:
+       lbs_deb_leave(LBS_DEB_HOST);
 }
 
 void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
@@ -1983,33 +1900,35 @@ void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
  *  @param psmode      Power Saving mode
  *  @return            n/a
  */
-void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
+void lbs_ps_confirm_sleep(struct lbs_private *priv)
 {
        unsigned long flags =0;
-       u8 allowed = 1;
+       int allowed = 1;
 
        lbs_deb_enter(LBS_DEB_HOST);
 
+       spin_lock_irqsave(&priv->driver_lock, flags);
        if (priv->dnld_sent) {
                allowed = 0;
                lbs_deb_host("dnld_sent was set\n");
        }
 
-       spin_lock_irqsave(&priv->driver_lock, flags);
+       /* In-progress command? */
        if (priv->cur_cmd) {
                allowed = 0;
                lbs_deb_host("cur_cmd was set\n");
        }
-       if (priv->intcounter > 0) {
+
+       /* Pending events or command responses? */
+       if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
                allowed = 0;
-               lbs_deb_host("intcounter %d\n", priv->intcounter);
+               lbs_deb_host("pending events or command responses\n");
        }
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
        if (allowed) {
                lbs_deb_host("sending lbs_ps_confirm_sleep\n");
-               sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
-                                sizeof(struct PS_CMD_ConfirmSleep));
+               lbs_send_confirmsleep(priv);
        } else {
                lbs_deb_host("sleep confirm has been delayed\n");
        }
@@ -2018,39 +1937,10 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
 }
 
 
-/**
- *  @brief Simple callback that copies response back into command
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param extra       A pointer to the original command structure for which
- *                      'resp' is a response
- *  @param resp         A pointer to the command response
- *
- *  @return            0 on success, error on failure
- */
-int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
-                    struct cmd_header *resp)
-{
-       struct cmd_header *buf = (void *)extra;
-       uint16_t copy_len;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
-       lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, "
-                   "copy back buffer was %u bytes\n", copy_len,
-                   le16_to_cpu(resp->size), le16_to_cpu(buf->size));
-       memcpy(buf, resp, copy_len);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
-
-struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command,
-                                     struct cmd_header *in_cmd, int in_cmd_size,
-                                     int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
-                                     unsigned long callback_arg)
+static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+       uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+       int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+       unsigned long callback_arg)
 {
        struct cmd_ctrl_node *cmdnode;
 
@@ -2087,9 +1977,6 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command
 
        lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
 
-       /* here was the big old switch() statement, which is now obsolete,
-        * because the caller of lbs_cmd() sets up all of *cmd for us. */
-
        cmdnode->cmdwaitqwoken = 0;
        lbs_queue_cmd(priv, cmdnode);
        wake_up_interruptible(&priv->waitq);
@@ -2099,6 +1986,15 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command
        return cmdnode;
 }
 
+void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
+       struct cmd_header *in_cmd, int in_cmd_size)
+{
+       lbs_deb_enter(LBS_DEB_CMD);
+       __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
+               lbs_cmd_async_callback, 0);
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
 int __lbs_cmd(struct lbs_private *priv, uint16_t command,
              struct cmd_header *in_cmd, int in_cmd_size,
              int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
index b9ab85c..3dfc2d4 100644 (file)
 #define lbs_cmd_with_response(priv, cmdnr, cmd)        \
        lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
 
-/* __lbs_cmd() will free the cmdnode and return success/failure.
-   __lbs_cmd_async() requires that the callback free the cmdnode */
-struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command,
-                                     struct cmd_header *in_cmd, int in_cmd_size,
-                                     int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
-                                     unsigned long callback_arg);
+void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
+       struct cmd_header *in_cmd, int in_cmd_size);
+
 int __lbs_cmd(struct lbs_private *priv, uint16_t command,
              struct cmd_header *in_cmd, int in_cmd_size,
              int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
@@ -57,5 +54,7 @@ int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
                           struct assoc_request *assoc);
 int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
                              uint16_t *enable);
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+                               struct assoc_request *assoc);
 
 #endif /* _LBS_CMD_H */
index 159216a..5abecb7 100644 (file)
@@ -12,7 +12,7 @@
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
-#include "join.h"
+#include "assoc.h"
 #include "wext.h"
 
 /**
@@ -74,7 +74,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
                lbs_deb_cmd("disconnected, so exit PS mode\n");
                lbs_ps_wakeup(priv, 0);
        }
-       lbs_deb_leave(LBS_DEB_CMD);
+       lbs_deb_leave(LBS_DEB_ASSOC);
 }
 
 /**
@@ -146,22 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
        return ret;
 }
 
-static int lbs_ret_802_11_stat(struct lbs_private *priv,
-                               struct cmd_ds_command *resp)
-{
-       lbs_deb_enter(LBS_DEB_CMD);
-/*     currently priv->wlan802_11Stat is unused
-
-       struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
-
-       // TODO Convert it to Big endian befor copy
-       memcpy(&priv->wlan802_11Stat,
-              p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
-*/
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
                                    struct cmd_ds_command *resp)
 {
@@ -204,74 +188,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_ret_802_11_key_material(struct lbs_private *priv,
-                                       struct cmd_ds_command *resp)
-{
-       struct cmd_ds_802_11_key_material *pkeymaterial =
-           &resp->params.keymaterial;
-       u16 action = le16_to_cpu(pkeymaterial->action);
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       /* Copy the returned key to driver private data */
-       if (action == CMD_ACT_GET) {
-               u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
-               u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
-
-               while (buf_ptr < resp_end) {
-                       struct MrvlIEtype_keyParamSet * pkeyparamset =
-                           (struct MrvlIEtype_keyParamSet *) buf_ptr;
-                       struct enc_key * pkey;
-                       u16 param_set_len = le16_to_cpu(pkeyparamset->length);
-                       u16 key_len = le16_to_cpu(pkeyparamset->keylen);
-                       u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
-                       u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
-                       u8 * end;
-
-                       end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
-                                                 + sizeof (pkeyparamset->length)
-                                                 + param_set_len;
-                       /* Make sure we don't access past the end of the IEs */
-                       if (end > resp_end)
-                               break;
-
-                       if (key_flags & KEY_INFO_WPA_UNICAST)
-                               pkey = &priv->wpa_unicast_key;
-                       else if (key_flags & KEY_INFO_WPA_MCAST)
-                               pkey = &priv->wpa_mcast_key;
-                       else
-                               break;
-
-                       /* Copy returned key into driver */
-                       memset(pkey, 0, sizeof(struct enc_key));
-                       if (key_len > sizeof(pkey->key))
-                               break;
-                       pkey->type = key_type;
-                       pkey->flags = key_flags;
-                       pkey->len = key_len;
-                       memcpy(pkey->key, pkeyparamset->key, pkey->len);
-
-                       buf_ptr = end + 1;
-               }
-       }
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       return 0;
-}
-
-static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
-                                      struct cmd_ds_command *resp)
-{
-       struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       return 0;
-}
-
 static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
                                       struct cmd_ds_command *resp)
 {
@@ -333,45 +249,6 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
-                                 struct cmd_ds_command *resp)
-{
-       struct lbs_ioctl_regrdwr *pbuf;
-       pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
-
-       lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
-              le16_to_cpu(resp->params.rdeeprom.bytecount));
-       if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
-               pbuf->NOB = 0;
-               lbs_deb_cmd("EEPROM read length too big\n");
-               return -1;
-       }
-       pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
-       if (pbuf->NOB > 0) {
-
-               memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
-                      le16_to_cpu(resp->params.rdeeprom.bytecount));
-               lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
-                       le16_to_cpu(resp->params.rdeeprom.bytecount));
-       }
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-static int lbs_ret_get_log(struct lbs_private *priv,
-                           struct cmd_ds_command *resp)
-{
-       struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       /* Stored little-endian */
-       memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
                                        struct cmd_ds_command *resp)
 {
@@ -390,7 +267,6 @@ static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
 }
 
 static inline int handle_cmd_response(struct lbs_private *priv,
-                                     unsigned long dummy,
                                      struct cmd_header *cmd_response)
 {
        struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
@@ -407,14 +283,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                ret = lbs_ret_reg_access(priv, respcmd, resp);
                break;
 
-       case CMD_RET(CMD_802_11_SCAN):
-               ret = lbs_ret_80211_scan(priv, resp);
-               break;
-
-       case CMD_RET(CMD_802_11_GET_LOG):
-               ret = lbs_ret_get_log(priv, resp);
-               break;
-
        case CMD_RET_802_11_ASSOCIATE:
        case CMD_RET(CMD_802_11_ASSOCIATE):
        case CMD_RET(CMD_802_11_REASSOCIATE):
@@ -423,7 +291,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
 
        case CMD_RET(CMD_802_11_DISASSOCIATE):
        case CMD_RET(CMD_802_11_DEAUTHENTICATE):
-               ret = lbs_ret_80211_disassociate(priv, resp);
+               ret = lbs_ret_80211_disassociate(priv);
                break;
 
        case CMD_RET(CMD_802_11_AD_HOC_START):
@@ -431,10 +299,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                ret = lbs_ret_80211_ad_hoc_start(priv, resp);
                break;
 
-       case CMD_RET(CMD_802_11_GET_STAT):
-               ret = lbs_ret_802_11_stat(priv, resp);
-               break;
-
        case CMD_RET(CMD_802_11_SNMP_MIB):
                ret = lbs_ret_802_11_snmp_mib(priv, resp);
                break;
@@ -453,7 +317,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                break;
 
        case CMD_RET(CMD_MAC_MULTICAST_ADR):
-       case CMD_RET(CMD_MAC_CONTROL):
        case CMD_RET(CMD_802_11_RESET):
        case CMD_RET(CMD_802_11_AUTHENTICATE):
        case CMD_RET(CMD_802_11_BEACON_STOP):
@@ -467,24 +330,12 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                ret = lbs_ret_802_11_rssi(priv, resp);
                break;
 
-       case CMD_RET(CMD_802_11_MAC_ADDRESS):
-               ret = lbs_ret_802_11_mac_address(priv, resp);
-               break;
-
        case CMD_RET(CMD_802_11_AD_HOC_STOP):
-               ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
-               break;
-
-       case CMD_RET(CMD_802_11_KEY_MATERIAL):
-               ret = lbs_ret_802_11_key_material(priv, resp);
-               break;
-
-       case CMD_RET(CMD_802_11_EEPROM_ACCESS):
-               ret = lbs_ret_802_11_eeprom_access(priv, resp);
+               ret = lbs_ret_80211_ad_hoc_stop(priv);
                break;
 
        case CMD_RET(CMD_802_11D_DOMAIN_INFO):
-               ret = lbs_ret_802_11d_domain_info(priv, resp);
+               ret = lbs_ret_802_11d_domain_info(resp);
                break;
 
        case CMD_RET(CMD_802_11_TPC_CFG):
@@ -500,14 +351,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                break;
 
-       case CMD_RET(CMD_802_11_PWR_CFG):
-               spin_lock_irqsave(&priv->driver_lock, flags);
-               memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg,
-                       sizeof(struct cmd_ds_802_11_pwr_cfg));
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-               break;
-
        case CMD_RET(CMD_GET_TSF):
                spin_lock_irqsave(&priv->driver_lock, flags);
                memcpy((void *)priv->cur_cmd->callback_arg,
@@ -541,7 +384,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
        return ret;
 }
 
-int lbs_process_rx_command(struct lbs_private *priv)
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
 {
        uint16_t respcmd, curcmd;
        struct cmd_header *resp;
@@ -561,26 +404,24 @@ int lbs_process_rx_command(struct lbs_private *priv)
                goto done;
        }
 
-       resp = (void *)priv->upld_buf;
-
-       curcmd = le16_to_cpu(resp->command);
-
+       resp = (void *)data;
+       curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
        respcmd = le16_to_cpu(resp->command);
        result = le16_to_cpu(resp->result);
 
-       lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
-                    respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
-       lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
+       lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
+                    respcmd, le16_to_cpu(resp->seqnum), len);
+       lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
 
-       if (resp->seqnum != resp->seqnum) {
+       if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
                lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
-                           le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum));
+                           le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                ret = -1;
                goto done;
        }
        if (respcmd != CMD_RET(curcmd) &&
-           respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) {
+           respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
                lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                ret = -1;
@@ -689,7 +530,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
                ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
                                resp);
        } else
-               ret = handle_cmd_response(priv, 0, resp);
+               ret = handle_cmd_response(priv, resp);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -707,21 +548,20 @@ done:
 
 static int lbs_send_confirmwake(struct lbs_private *priv)
 {
-       struct cmd_header *cmd = &priv->lbs_ps_confirm_wake;
+       struct cmd_header cmd;
        int ret = 0;
 
        lbs_deb_enter(LBS_DEB_HOST);
 
-       cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
-       cmd->size = cpu_to_le16(sizeof(*cmd));
-       cmd->seqnum = cpu_to_le16(++priv->seqnum);
-       cmd->result = 0;
-
-       lbs_deb_host("SEND_WAKEC_CMD: before download\n");
+       cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
+       cmd.size = cpu_to_le16(sizeof(cmd));
+       cmd.seqnum = cpu_to_le16(++priv->seqnum);
+       cmd.result = 0;
 
-       lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd));
+       lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
+               sizeof(cmd));
 
-       ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd));
+       ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
        if (ret)
                lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
 
@@ -729,22 +569,15 @@ static int lbs_send_confirmwake(struct lbs_private *priv)
        return ret;
 }
 
-int lbs_process_event(struct lbs_private *priv)
+int lbs_process_event(struct lbs_private *priv, u32 event)
 {
        int ret = 0;
-       u32 eventcause;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
-       spin_lock_irq(&priv->driver_lock);
-       eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
-       spin_unlock_irq(&priv->driver_lock);
-
-       lbs_deb_cmd("event cause %d\n", eventcause);
-
-       switch (eventcause) {
+       switch (event) {
        case MACREG_INT_CODE_LINK_SENSED:
-               lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+               lbs_deb_cmd("EVENT: link sensed\n");
                break;
 
        case MACREG_INT_CODE_DEAUTHENTICATED:
@@ -763,7 +596,7 @@ int lbs_process_event(struct lbs_private *priv)
                break;
 
        case MACREG_INT_CODE_PS_SLEEP:
-               lbs_deb_cmd("EVENT: sleep\n");
+               lbs_deb_cmd("EVENT: ps sleep\n");
 
                /* handle unexpected PS SLEEP event */
                if (priv->psstate == PS_STATE_FULL_POWER) {
@@ -773,17 +606,17 @@ int lbs_process_event(struct lbs_private *priv)
                }
                priv->psstate = PS_STATE_PRE_SLEEP;
 
-               lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
+               lbs_ps_confirm_sleep(priv);
 
                break;
 
        case MACREG_INT_CODE_HOST_AWAKE:
-               lbs_deb_cmd("EVENT: HOST_AWAKE\n");
+               lbs_deb_cmd("EVENT: host awake\n");
                lbs_send_confirmwake(priv);
                break;
 
        case MACREG_INT_CODE_PS_AWAKE:
-               lbs_deb_cmd("EVENT: awake\n");
+               lbs_deb_cmd("EVENT: ps awake\n");
                /* handle unexpected PS AWAKE event */
                if (priv->psstate == PS_STATE_FULL_POWER) {
                        lbs_deb_cmd(
@@ -814,14 +647,16 @@ int lbs_process_event(struct lbs_private *priv)
                lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
                handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
                break;
+
        case MACREG_INT_CODE_MIB_CHANGED:
+               lbs_deb_cmd("EVENT: MIB CHANGED\n");
+               break;
        case MACREG_INT_CODE_INIT_DONE:
+               lbs_deb_cmd("EVENT: INIT DONE\n");
                break;
-
        case MACREG_INT_CODE_ADHOC_BCN_LOST:
                lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
                break;
-
        case MACREG_INT_CODE_RSSI_LOW:
                lbs_pr_alert("EVENT: rssi low\n");
                break;
@@ -856,14 +691,10 @@ int lbs_process_event(struct lbs_private *priv)
                break;
 
        default:
-               lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
+               lbs_pr_alert("EVENT: unknown event id %d\n", event);
                break;
        }
 
-       spin_lock_irq(&priv->driver_lock);
-       priv->eventcause = 0;
-       spin_unlock_irq(&priv->driver_lock);
-
        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
        return ret;
 }
index 2174717..0aa0ce3 100644 (file)
@@ -19,7 +19,7 @@ static char *szStates[] = {
 };
 
 #ifdef PROC_DEBUG
-static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev);
+static void lbs_debug_init(struct lbs_private *priv);
 #endif
 
 static int open_file_generic(struct inode *inode, struct file *file)
@@ -78,7 +78,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
                u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
 
                pos += snprintf(buf+pos, len-pos,
-                       "%02u| %03d | %04ld | %s |",
+                       "%02u| %03d | %04d | %s |",
                        numscansdone, iter_bss->channel, iter_bss->rssi,
                        print_mac(mac, iter_bss->bssid));
                pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
@@ -164,172 +164,6 @@ out_unlock:
        return ret;
 }
 
-static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       union iwreq_data wrqu;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_unlock;
-       }
-
-       lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
-
-       memset(&wrqu, 0, sizeof(union iwreq_data));
-       wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
-out_unlock:
-       free_page(addr);
-       return count;
-}
-
-static void lbs_parse_bssid(char *buf, size_t count,
-       struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
-       char *hold;
-       unsigned int mac[ETH_ALEN];
-
-       hold = strstr(buf, "bssid=");
-       if (!hold)
-               return;
-       hold += 6;
-       sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
-       memcpy(scan_cfg->bssid, mac, ETH_ALEN);
-}
-
-static void lbs_parse_ssid(char *buf, size_t count,
-       struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
-       char *hold, *end;
-       ssize_t size;
-
-       hold = strstr(buf, "ssid=");
-       if (!hold)
-               return;
-       hold += 5;
-       end = strchr(hold, ' ');
-       if (!end)
-               end = buf + count - 1;
-
-       size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
-       strncpy(scan_cfg->ssid, hold, size);
-
-       return;
-}
-
-static int lbs_parse_clear(char *buf, size_t count, const char *tag)
-{
-       char *hold;
-       int val;
-
-       hold = strstr(buf, tag);
-       if (!hold)
-               return 0;
-       hold += strlen(tag);
-       sscanf(hold, "%d", &val);
-
-       if (val != 0)
-               val = 1;
-
-       return val;
-}
-
-static int lbs_parse_dur(char *buf, size_t count,
-       struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
-       char *hold;
-       int val;
-
-       hold = strstr(buf, "dur=");
-       if (!hold)
-               return 0;
-       hold += 4;
-       sscanf(hold, "%d", &val);
-
-       return val;
-}
-
-static void lbs_parse_type(char *buf, size_t count,
-       struct lbs_ioctl_user_scan_cfg *scan_cfg)
-{
-       char *hold;
-       int val;
-
-       hold = strstr(buf, "type=");
-       if (!hold)
-               return;
-       hold += 5;
-       sscanf(hold, "%d", &val);
-
-       /* type=1,2 or 3 */
-       if (val < 1 || val > 3)
-               return;
-
-       scan_cfg->bsstype = val;
-
-       return;
-}
-
-static ssize_t lbs_setuserscan(struct file *file,
-                                   const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       ssize_t res, buf_size;
-       struct lbs_ioctl_user_scan_cfg *scan_cfg;
-       union iwreq_data wrqu;
-       int dur;
-       char *buf = (char *)get_zeroed_page(GFP_KERNEL);
-
-       if (!buf)
-               return -ENOMEM;
-
-       buf_size = min(count, len - 1);
-       if (copy_from_user(buf, userbuf, buf_size)) {
-               res = -EFAULT;
-               goto out_buf;
-       }
-
-       scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL);
-       if (!scan_cfg) {
-               res = -ENOMEM;
-               goto out_buf;
-       }
-       res = count;
-
-       scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY;
-
-       dur = lbs_parse_dur(buf, count, scan_cfg);
-       lbs_parse_bssid(buf, count, scan_cfg);
-       scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid=");
-       lbs_parse_ssid(buf, count, scan_cfg);
-       scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid=");
-       lbs_parse_type(buf, count, scan_cfg);
-
-       lbs_scan_networks(priv, scan_cfg, 1);
-       wait_event_interruptible(priv->cmd_pending,
-                                priv->surpriseremoved || !priv->last_scanned_channel);
-
-       if (priv->surpriseremoved)
-               goto out_scan_cfg;
-
-       memset(&wrqu, 0x00, sizeof(union iwreq_data));
-       wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
- out_scan_cfg:
-       kfree(scan_cfg);
- out_buf:
-       free_page((unsigned long)buf);
-       return res;
-}
-
-
 /*
  * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
  * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
@@ -478,8 +312,8 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
        if (tlv_type != TLV_TYPE_BCNMISS)
                tlv->freq = freq;
 
-       /* The command header, the event mask, and the one TLV */
-       events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv));
+       /* The command header, the action, the event mask, and one TLV */
+       events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
 
        ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
 
@@ -856,8 +690,6 @@ static struct lbs_debugfs_files debugfs_files[] = {
                                        write_file_dummy), },
        { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
                                lbs_sleepparams_write), },
-       { "extscan", 0600, FOPS(NULL, lbs_extscan), },
-       { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
 };
 
 static struct lbs_debugfs_files debugfs_events_files[] = {
@@ -946,7 +778,7 @@ void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
        }
 
 #ifdef PROC_DEBUG
-       lbs_debug_init(priv, dev);
+       lbs_debug_init(priv);
 #endif
 exit:
        return;
@@ -992,7 +824,6 @@ struct debug_data {
 /* To debug any member of struct lbs_private, simply add one line here.
  */
 static struct debug_data items[] = {
-       {"intcounter", item_size(intcounter), item_addr(intcounter)},
        {"psmode", item_size(psmode), item_addr(psmode)},
        {"psstate", item_size(psstate), item_addr(psstate)},
 };
@@ -1120,7 +951,7 @@ static struct file_operations lbs_debug_fops = {
  *  @param dev     pointer net_device
  *  @return       N/A
  */
-static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
+static void lbs_debug_init(struct lbs_private *priv)
 {
        int i;
 
index aaacd9b..b652fa3 100644 (file)
@@ -17,9 +17,9 @@ struct net_device;
 struct cmd_ctrl_node;
 struct cmd_ds_command;
 
-int lbs_set_mac_packet_filter(struct lbs_private *priv);
+void lbs_set_mac_control(struct lbs_private *priv);
 
-void lbs_send_tx_feedback(struct lbs_private *priv);
+void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
 
 int lbs_free_cmd_buffer(struct lbs_private *priv);
 
@@ -30,17 +30,16 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
 
 int lbs_allocate_cmd_buffer(struct lbs_private *priv);
 int lbs_execute_next_command(struct lbs_private *priv);
-int lbs_process_event(struct lbs_private *priv);
-void lbs_interrupt(struct lbs_private *priv);
+int lbs_process_event(struct lbs_private *priv, u32 event);
+void lbs_queue_event(struct lbs_private *priv, u32 event);
+void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+
 int lbs_set_radio_control(struct lbs_private *priv);
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
-void lbs_get_fwversion(struct lbs_private *priv,
-       char *fwversion,
-       int maxlen);
 
 /** The proc fs interface */
-int lbs_process_rx_command(struct lbs_private *priv);
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
 void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
                          int result);
 int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -49,7 +48,7 @@ int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
 int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
 
 void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
-void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode);
+void lbs_ps_confirm_sleep(struct lbs_private *priv);
 void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
 
 struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
@@ -63,14 +62,17 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
 
 /* main.c */
 struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
-       u8 band,
        int *cfp_no);
 struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
 int lbs_remove_card(struct lbs_private *priv);
 int lbs_start_card(struct lbs_private *priv);
 int lbs_stop_card(struct lbs_private *priv);
-int lbs_reset_device(struct lbs_private *priv);
 void lbs_host_to_card_done(struct lbs_private *priv);
 
 int lbs_update_channel(struct lbs_private *priv);
+
+#ifndef CONFIG_IEEE80211
+const char *escape_essid(const char *essid, u8 essid_len);
+#endif
+
 #endif
index 3053cc2..db9cc21 100644 (file)
@@ -53,14 +53,14 @@ do { if ((lbs_debug & (grp)) == (grp)) \
 #endif
 
 #define lbs_deb_enter(grp) \
-  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__);
+  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__);
 #define lbs_deb_enter_args(grp, fmt, args...) \
-  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
+  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
 #define lbs_deb_leave(grp) \
-  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__);
+  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__);
 #define lbs_deb_leave_args(grp, fmt, args...) \
-  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \
-  __FUNCTION__, __LINE__, ##args);
+  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
+  __func__, ##args);
 #define lbs_deb_main(fmt, args...)      LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
 #define lbs_deb_net(fmt, args...)       LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
 #define lbs_deb_mesh(fmt, args...)      LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
@@ -165,7 +165,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 #define        MRVDRV_MAX_CHANNELS_PER_SCAN            14
 
 #define MRVDRV_MIN_BEACON_INTERVAL             20
-#define MRVDRV_MAX_BEACON_INTERVAL             1000
+#define MRVDRV_MAX_BEACON_INTERVAL             10000
 #define MRVDRV_BEACON_INTERVAL                 100
 
 #define MARVELL_MESH_IE_LENGTH         9
@@ -177,8 +177,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 #define MRVDRV_CMD_UPLD_RDY            0x0008
 #define MRVDRV_CARDEVENT               0x0010
 
-#define SBI_EVENT_CAUSE_SHIFT          3
-
 /** TxPD status */
 
 /*     Station firmware use TxPD status field to report final Tx transmit
index 3629751..0d9edb9 100644 (file)
 #include <linux/wireless.h>
 #include <linux/ethtool.h>
 #include <linux/debugfs.h>
+#include <net/ieee80211.h>
 
 #include "defs.h"
-#include "scan.h"
+#include "hostcmd.h"
 
 extern struct ethtool_ops lbs_ethtool_ops;
 
@@ -102,7 +103,6 @@ struct lbs_private {
        int mesh_open;
        int infra_open;
        int mesh_autostart_enabled;
-       __le16 boot2_version;
 
        char name[DEV_NAME_LEN];
 
@@ -129,10 +129,6 @@ struct lbs_private {
        u32 bbp_offset;
        u32 rf_offset;
 
-       /** Upload length */
-       u32 upld_len;
-       /* Upload buffer */
-       u8 upld_buf[LBS_UPLD_SIZE];
        /* Download sent:
           bit0 1/0=data_sent/data_tx_done,
           bit1 1/0=cmd_sent/cmd_tx_done,
@@ -144,27 +140,27 @@ struct lbs_private {
        wait_queue_head_t waitq;
        struct workqueue_struct *work_thread;
 
+       /** Scanning */
        struct delayed_work scan_work;
        struct delayed_work assoc_work;
        struct work_struct sync_channel;
+       /* remember which channel was scanned last, != 0 if currently scanning */
+       int scan_channel;
+       u8 scan_ssid[IW_ESSID_MAX_SIZE + 1];
+       u8 scan_ssid_len;
 
        /** Hardware access */
        int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
-       int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
-       int (*hw_read_event_cause) (struct lbs_private *);
 
        /* Wake On LAN */
        uint32_t wol_criteria;
        uint8_t wol_gpio;
        uint8_t wol_gap;
 
-       /* was struct lbs_adapter from here... */
-
        /** Wlan adapter data structure*/
        /** STATUS variables */
-       u8 fwreleasenumber[4];
+       u32 fwrelease;
        u32 fwcapinfo;
-       /* protected with big lock */
 
        struct mutex lock;
 
@@ -176,7 +172,6 @@ struct lbs_private {
 
        /** command-related variables */
        u16 seqnum;
-       /* protected by big lock */
 
        struct cmd_ctrl_node *cmd_array;
        /** Current command */
@@ -189,12 +184,17 @@ struct lbs_private {
        struct list_head cmdpendingq;
 
        wait_queue_head_t cmd_pending;
-       /* command related variables protected by priv->driver_lock */
 
-       /** Async and Sync Event variables */
-       u32 intcounter;
-       u32 eventcause;
-       u8 nodename[16];        /* nickname */
+       /* Command responses sent from the hardware to the driver */
+       u8 resp_idx;
+       u8 resp_buf[2][LBS_UPLD_SIZE];
+       u32 resp_len[2];
+
+       /* Events sent from hardware to driver */
+       struct kfifo *event_fifo;
+
+       /* nickname */
+       u8 nodename[16];
 
        /** spin locks */
        spinlock_t driver_lock;
@@ -204,8 +204,6 @@ struct lbs_private {
        int nr_retries;
        int cmd_timed_out;
 
-       u8 hisregcpy;
-
        /** current ssid/bssid related parameters*/
        struct current_bss_params curbssparams;
 
@@ -248,7 +246,7 @@ struct lbs_private {
        struct sk_buff *currenttxskb;
 
        /** NIC Operation characteristics */
-       u16 currentpacketfilter;
+       u16 mac_control;
        u32 connect_status;
        u32 mesh_connect_status;
        u16 regioncode;
@@ -263,9 +261,6 @@ struct lbs_private {
        char ps_supported;
        u8 needtowakeup;
 
-       struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep;
-       struct cmd_header lbs_ps_confirm_wake;
-
        struct assoc_request * pending_assoc_req;
        struct assoc_request * in_progress_assoc_req;
 
@@ -316,16 +311,52 @@ struct lbs_private {
        u32 enable11d;
 
        /**     MISCELLANEOUS */
-       u8 *prdeeprom;
        struct lbs_offset_value offsetvalue;
 
-       struct cmd_ds_802_11_get_log logmsg;
-
        u32 monitormode;
-       int last_scanned_channel;
        u8 fw_ready;
 };
 
+extern struct cmd_confirm_sleep confirm_sleep;
+
+/**
+ *  @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+       u8 bssid[ETH_ALEN];
+
+       u8 ssid[IW_ESSID_MAX_SIZE + 1];
+       u8 ssid_len;
+
+       u16 capability;
+       u32 rssi;
+       u32 channel;
+       u16 beaconperiod;
+       u32 atimwindow;
+
+       /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
+       u8 mode;
+
+       /* zero-terminated array of supported data rates */
+       u8 rates[MAX_RATES + 1];
+
+       unsigned long last_scanned;
+
+       union ieeetypes_phyparamset phyparamset;
+       union IEEEtypes_ssparamset ssparamset;
+
+       struct ieeetypes_countryinfofullset countryinfo;
+
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       size_t wpa_ie_len;
+       u8 rsn_ie[MAX_WPA_IE_LEN];
+       size_t rsn_ie_len;
+
+       u8 mesh;
+
+       struct list_head list;
+};
+
 /** Association request
  *
  * Encapsulates all the options that describe a specific assocation request
@@ -350,7 +381,7 @@ struct assoc_request {
        u8 channel;
        u8 band;
        u8 mode;
-       u8 bssid[ETH_ALEN];
+       u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
 
        /** WEP keys */
        struct enc_key wep_keys[4];
index 21e6f98..688d60d 100644 (file)
@@ -6,7 +6,6 @@
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
-#include "join.h"
 #include "wext.h"
 #include "cmd.h"
 
@@ -25,13 +24,14 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev,
                                         struct ethtool_drvinfo *info)
 {
        struct lbs_private *priv = (struct lbs_private *) dev->priv;
-       char fwver[32];
-
-       lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1);
 
+       snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
+               priv->fwrelease >> 24 & 0xff,
+               priv->fwrelease >> 16 & 0xff,
+               priv->fwrelease >>  8 & 0xff,
+               priv->fwrelease       & 0xff);
        strcpy(info->driver, "libertas");
        strcpy(info->version, lbs_driver_version);
-       strcpy(info->fw_version, fwver);
 }
 
 /* All 8388 parts have 16KiB EEPROM size at the time of writing.
@@ -48,66 +48,33 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev,
                                   struct ethtool_eeprom *eeprom, u8 * bytes)
 {
        struct lbs_private *priv = (struct lbs_private *) dev->priv;
-       struct lbs_ioctl_regrdwr regctrl;
-       char *ptr;
+       struct cmd_ds_802_11_eeprom_access cmd;
        int ret;
 
-       regctrl.action = 0;
-       regctrl.offset = eeprom->offset;
-       regctrl.NOB = eeprom->len;
-
-       if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN)
-               return -EINVAL;
-
-//      mutex_lock(&priv->mutex);
-
-       priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
-       if (!priv->prdeeprom)
-               return -ENOMEM;
-       memcpy(priv->prdeeprom, &regctrl, sizeof(regctrl));
-
-       /* +14 is for action, offset, and NOB in
-        * response */
-       lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n",
-              regctrl.action, regctrl.offset, regctrl.NOB);
-
-       ret = lbs_prepare_and_send_command(priv,
-                                   CMD_802_11_EEPROM_ACCESS,
-                                   regctrl.action,
-                                   CMD_OPTION_WAITFORRSP, 0,
-                                   &regctrl);
+       lbs_deb_enter(LBS_DEB_ETHTOOL);
 
-       if (ret) {
-               if (priv->prdeeprom)
-                       kfree(priv->prdeeprom);
-               goto done;
+       if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN ||
+           eeprom->len > LBS_EEPROM_READ_LEN) {
+               ret = -EINVAL;
+               goto out;
        }
 
-       mdelay(10);
-
-       ptr = (char *)priv->prdeeprom;
-
-       /* skip the command header, but include the "value" u32 variable */
-       ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4;
-
-       /*
-        * Return the result back to the user
-        */
-       memcpy(bytes, ptr, eeprom->len);
-
-       if (priv->prdeeprom)
-               kfree(priv->prdeeprom);
-//     mutex_unlock(&priv->mutex);
-
-       ret = 0;
-
-done:
-       lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
+       cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) -
+               LBS_EEPROM_READ_LEN + eeprom->len);
+       cmd.action = cpu_to_le16(CMD_ACT_GET);
+       cmd.offset = cpu_to_le16(eeprom->offset);
+       cmd.len    = cpu_to_le16(eeprom->len);
+       ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd);
+       if (!ret)
+               memcpy(bytes, cmd.value, eeprom->len);
+
+out:
+       lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret);
         return ret;
 }
 
-static void lbs_ethtool_get_stats(struct net_device * dev,
-                               struct ethtool_stats * stats, u64 * data)
+static void lbs_ethtool_get_stats(struct net_device *dev,
+                                 struct ethtool_stats *stats, uint64_t *data)
 {
        struct lbs_private *priv = dev->priv;
        struct cmd_ds_mesh_access mesh_access;
@@ -116,12 +83,12 @@ static void lbs_ethtool_get_stats(struct net_device * dev,
        lbs_deb_enter(LBS_DEB_ETHTOOL);
 
        /* Get Mesh Statistics */
-       ret = lbs_prepare_and_send_command(priv,
-                       CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
-                       CMD_OPTION_WAITFORRSP, 0, &mesh_access);
+       ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
 
-       if (ret)
+       if (ret) {
+               memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
                return;
+       }
 
        priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
        priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
@@ -144,19 +111,18 @@ static void lbs_ethtool_get_stats(struct net_device * dev,
        lbs_deb_enter(LBS_DEB_ETHTOOL);
 }
 
-static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset)
+static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
 {
-       switch (sset) {
-       case ETH_SS_STATS:
+       struct lbs_private *priv = dev->priv;
+
+       if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
                return MESH_STATS_NUM;
-       default:
-               return -EOPNOTSUPP;
-       }
+
+       return -EOPNOTSUPP;
 }
 
 static void lbs_ethtool_get_strings(struct net_device *dev,
-                                         u32 stringset,
-                                         u8 * s)
+                                   uint32_t stringset, uint8_t *s)
 {
        int i;
 
index 1aa0407..3915c31 100644 (file)
@@ -33,7 +33,6 @@
 #define CMD_RET_802_11_ASSOCIATE               0x8012
 
 /* Command codes */
-#define CMD_CODE_DNLD                          0x0002
 #define CMD_GET_HW_SPEC                                0x0003
 #define        CMD_EEPROM_UPDATE                       0x0004
 #define CMD_802_11_RESET                       0x0005
@@ -68,8 +67,6 @@
 #define CMD_802_11_AD_HOC_JOIN                 0x002c
 #define CMD_802_11_QUERY_TKIP_REPLY_CNTRS      0x002e
 #define CMD_802_11_ENABLE_RSN                  0x002f
-#define CMD_802_11_PAIRWISE_TSC                        0x0036
-#define CMD_802_11_GROUP_TSC                   0x0037
 #define CMD_802_11_SET_AFC                     0x003c
 #define CMD_802_11_GET_AFC                     0x003d
 #define CMD_802_11_AD_HOC_STOP                 0x0040
@@ -87,7 +84,6 @@
 #define CMD_802_11_INACTIVITY_TIMEOUT          0x0067
 #define CMD_802_11_SLEEP_PERIOD                        0x0068
 #define CMD_802_11_TPC_CFG                     0x0072
-#define CMD_802_11_PWR_CFG                     0x0073
 #define CMD_802_11_FW_WAKE_METHOD              0x0074
 #define CMD_802_11_SUBSCRIBE_EVENT             0x0075
 #define CMD_802_11_RATE_ADAPT_RATESET          0x0076
index be325ed..71d9a55 100644 (file)
@@ -136,8 +136,8 @@ struct cmd_ds_get_hw_spec {
        /* Number of antenna used */
        __le16 nr_antenna;
 
-       /* FW release number, example 1,2,3,4 = 3.2.1p4 */
-       u8 fwreleasenumber[4];
+       /* FW release number, example 0x01030304 = 2.3.4p1 */
+       __le32 fwrelease;
 
        /* Base Address of TxPD queue */
        __le32 wcb_base;
@@ -174,9 +174,11 @@ struct cmd_ds_802_11_subscribe_event {
  * Define data structure for CMD_802_11_SCAN
  */
 struct cmd_ds_802_11_scan {
-       u8 bsstype;
-       u8 bssid[ETH_ALEN];
-       u8 tlvbuffer[1];
+       struct cmd_header hdr;
+
+       uint8_t bsstype;
+       uint8_t bssid[ETH_ALEN];
+       uint8_t tlvbuffer[0];
 #if 0
        mrvlietypes_ssidparamset_t ssidParamSet;
        mrvlietypes_chanlistparamset_t ChanListParamSet;
@@ -185,12 +187,16 @@ struct cmd_ds_802_11_scan {
 };
 
 struct cmd_ds_802_11_scan_rsp {
+       struct cmd_header hdr;
+
        __le16 bssdescriptsize;
-       u8 nr_sets;
-       u8 bssdesc_and_tlvbuffer[1];
+       uint8_t nr_sets;
+       uint8_t bssdesc_and_tlvbuffer[0];
 };
 
 struct cmd_ds_802_11_get_log {
+       struct cmd_header hdr;
+
        __le32 mcasttxframe;
        __le32 failed;
        __le32 retry;
@@ -207,8 +213,9 @@ struct cmd_ds_802_11_get_log {
 };
 
 struct cmd_ds_mac_control {
+       struct cmd_header hdr;
        __le16 action;
-       __le16 reserved;
+       u16 reserved;
 };
 
 struct cmd_ds_mac_multicast_adr {
@@ -420,6 +427,8 @@ struct cmd_ds_802_11_rssi_rsp {
 };
 
 struct cmd_ds_802_11_mac_address {
+       struct cmd_header hdr;
+
        __le16 action;
        u8 macadd[ETH_ALEN];
 };
@@ -471,14 +480,11 @@ struct cmd_ds_802_11_ps_mode {
        __le16 locallisteninterval;
 };
 
-struct PS_CMD_ConfirmSleep {
-       __le16 command;
-       __le16 size;
-       __le16 seqnum;
-       __le16 result;
+struct cmd_confirm_sleep {
+       struct cmd_header hdr;
 
        __le16 action;
-       __le16 reserved1;
+       __le16 nullpktinterval;
        __le16 multipledtim;
        __le16 reserved;
        __le16 locallisteninterval;
@@ -572,17 +578,20 @@ struct cmd_ds_host_sleep {
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_key_material {
+       struct cmd_header hdr;
+
        __le16 action;
        struct MrvlIEtype_keyParamSet keyParamSet[2];
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_eeprom_access {
+       struct cmd_header hdr;
        __le16 action;
-
-       /* multiple 4 */
        __le16 offset;
-       __le16 bytecount;
-       u8 value;
+       __le16 len;
+       /* firmware says it returns a maximum of 20 bytes */
+#define LBS_EEPROM_READ_LEN 20
+       u8 value[LBS_EEPROM_READ_LEN];
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_tpc_cfg {
@@ -597,15 +606,7 @@ struct cmd_ds_802_11_tpc_cfg {
 struct cmd_ds_802_11_led_ctrl {
        __le16 action;
        __le16 numled;
-       u8 data[256];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_pwr_cfg {
-       __le16 action;
-       u8 enable;
-       s8 PA_P0;
-       s8 PA_P1;
-       s8 PA_P2;
+       u8 data[288];
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_afc {
@@ -689,15 +690,11 @@ struct cmd_ds_command {
        /* command Body */
        union {
                struct cmd_ds_802_11_ps_mode psmode;
-               struct cmd_ds_802_11_scan scan;
-               struct cmd_ds_802_11_scan_rsp scanresp;
-               struct cmd_ds_mac_control macctrl;
                struct cmd_ds_802_11_associate associate;
                struct cmd_ds_802_11_deauthenticate deauth;
                struct cmd_ds_802_11_ad_hoc_start ads;
                struct cmd_ds_802_11_reset reset;
                struct cmd_ds_802_11_ad_hoc_result result;
-               struct cmd_ds_802_11_get_log glog;
                struct cmd_ds_802_11_authenticate auth;
                struct cmd_ds_802_11_get_stat gstat;
                struct cmd_ds_802_3_get_stat gstat_8023;
@@ -711,18 +708,14 @@ struct cmd_ds_command {
                struct cmd_ds_802_11_rssi rssi;
                struct cmd_ds_802_11_rssi_rsp rssirsp;
                struct cmd_ds_802_11_disassociate dassociate;
-               struct cmd_ds_802_11_mac_address macadd;
-               struct cmd_ds_802_11_key_material keymaterial;
                struct cmd_ds_mac_reg_access macreg;
                struct cmd_ds_bbp_reg_access bbpreg;
                struct cmd_ds_rf_reg_access rfreg;
-               struct cmd_ds_802_11_eeprom_access rdeeprom;
 
                struct cmd_ds_802_11d_domain_info domaininfo;
                struct cmd_ds_802_11d_domain_info domaininforesp;
 
                struct cmd_ds_802_11_tpc_cfg tpccfg;
-               struct cmd_ds_802_11_pwr_cfg pwrcfg;
                struct cmd_ds_802_11_afc afc;
                struct cmd_ds_802_11_led_ctrl ledgpio;
 
index 030dbe2..54280e2 100644 (file)
@@ -83,14 +83,14 @@ static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
 {
        unsigned int val = ioread8(card->iobase + reg);
        if (debug_output)
-               printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
+               printk(KERN_INFO "inb %08x<%02x\n", reg, val);
        return val;
 }
 static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
 {
        unsigned int val = ioread16(card->iobase + reg);
        if (debug_output)
-               printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
+               printk(KERN_INFO "inw %08x<%04x\n", reg, val);
        return val;
 }
 static inline void if_cs_read16_rep(
@@ -100,7 +100,7 @@ static inline void if_cs_read16_rep(
        unsigned long count)
 {
        if (debug_output)
-               printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
+               printk(KERN_INFO "insw %08x<(0x%lx words)\n",
                        reg, count);
        ioread16_rep(card->iobase + reg, buf, count);
 }
@@ -108,14 +108,14 @@ static inline void if_cs_read16_rep(
 static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
 {
        if (debug_output)
-               printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
+               printk(KERN_INFO "outb %08x>%02x\n", reg, val);
        iowrite8(val, card->iobase + reg);
 }
 
 static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
 {
        if (debug_output)
-               printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
+               printk(KERN_INFO "outw %08x>%04x\n", reg, val);
        iowrite16(val, card->iobase + reg);
 }
 
@@ -126,7 +126,7 @@ static inline void if_cs_write16_rep(
        unsigned long count)
 {
        if (debug_output)
-               printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
+               printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
                        reg, count);
        iowrite16_rep(card->iobase + reg, buf, count);
 }
@@ -199,17 +199,6 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
 #define IF_CS_C_S_CARDEVENT            0x0010
 #define IF_CS_C_S_MASK                 0x001f
 #define IF_CS_C_S_STATUS_MASK          0x7f00
-/* The following definitions should be the same as the MRVDRV_ ones */
-
-#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
-#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
-#endif
-#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
-#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
-#endif
-#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
-#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
-#endif
 
 #define IF_CS_C_INT_CAUSE              0x00000022
 #define        IF_CS_C_IC_MASK                 0x001f
@@ -225,55 +214,6 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
 
 
 
-/********************************************************************/
-/* Interrupts                                                       */
-/********************************************************************/
-
-static inline void if_cs_enable_ints(struct if_cs_card *card)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       if_cs_write16(card, IF_CS_H_INT_MASK, 0);
-}
-
-static inline void if_cs_disable_ints(struct if_cs_card *card)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
-}
-
-static irqreturn_t if_cs_interrupt(int irq, void *data)
-{
-       struct if_cs_card *card = (struct if_cs_card *)data;
-       u16 int_cause;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
-       if(int_cause == 0x0) {
-               /* Not for us */
-               return IRQ_NONE;
-
-       } else if (int_cause == 0xffff) {
-               /* Read in junk, the card has probably been removed */
-               card->priv->surpriseremoved = 1;
-
-       } else {
-               if (int_cause & IF_CS_H_IC_TX_OVER)
-                       lbs_host_to_card_done(card->priv);
-
-               /* clear interrupt */
-               if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
-       }
-       spin_lock(&card->priv->driver_lock);
-       lbs_interrupt(card->priv);
-       spin_unlock(&card->priv->driver_lock);
-
-       return IRQ_HANDLED;
-}
-
-
-
-
 /********************************************************************/
 /* I/O                                                              */
 /********************************************************************/
@@ -351,6 +291,7 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
  */
 static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
 {
+       unsigned long flags;
        int ret = -1;
        u16 val;
 
@@ -378,6 +319,12 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
         * bytes */
        *len -= 8;
        ret = 0;
+
+       /* Clear this flag again */
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->dnld_sent = DNLD_RES_RECEIVED;
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
+
 out:
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
        return ret;
@@ -396,11 +343,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
        if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
                lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
                priv->stats.rx_dropped++;
-               printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
                goto dat_err;
        }
 
-       //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
        skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
        if (!skb)
                goto out;
@@ -424,6 +369,96 @@ out:
 
 
 
+/********************************************************************/
+/* Interrupts                                                       */
+/********************************************************************/
+
+static inline void if_cs_enable_ints(struct if_cs_card *card)
+{
+       lbs_deb_enter(LBS_DEB_CS);
+       if_cs_write16(card, IF_CS_H_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+       lbs_deb_enter(LBS_DEB_CS);
+       if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
+}
+
+
+static irqreturn_t if_cs_interrupt(int irq, void *data)
+{
+       struct if_cs_card *card = data;
+       struct lbs_private *priv = card->priv;
+       u16 cause;
+
+       lbs_deb_enter(LBS_DEB_CS);
+
+       cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
+       if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
+
+       lbs_deb_cs("cause 0x%04x\n", cause);
+       if (cause == 0) {
+               /* Not for us */
+               return IRQ_NONE;
+       }
+
+       if (cause == 0xffff) {
+               /* Read in junk, the card has probably been removed */
+               card->priv->surpriseremoved = 1;
+               return IRQ_HANDLED;
+       }
+
+       /* TODO: I'm not sure what the best ordering is */
+
+       cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
+
+       if (cause & IF_CS_C_S_RX_UPLD_RDY) {
+               struct sk_buff *skb;
+               lbs_deb_cs("rx packet\n");
+               skb = if_cs_receive_data(priv);
+               if (skb)
+                       lbs_process_rxed_packet(priv, skb);
+       }
+
+       if (cause & IF_CS_H_IC_TX_OVER) {
+               lbs_deb_cs("tx over\n");
+               lbs_host_to_card_done(priv);
+       }
+
+       if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
+               unsigned long flags;
+               u8 i;
+
+               lbs_deb_cs("cmd upload ready\n");
+               spin_lock_irqsave(&priv->driver_lock, flags);
+               i = (priv->resp_idx == 0) ? 1 : 0;
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+               BUG_ON(priv->resp_len[i]);
+               if_cs_receive_cmdres(priv, priv->resp_buf[i],
+                       &priv->resp_len[i]);
+
+               spin_lock_irqsave(&priv->driver_lock, flags);
+               lbs_notify_command_response(priv, i);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+       }
+
+       if (cause & IF_CS_H_IC_HOST_EVENT) {
+               u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
+                       & IF_CS_C_S_STATUS_MASK;
+               if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
+                       IF_CS_H_IC_HOST_EVENT);
+               lbs_deb_cs("eventcause 0x%04x\n", event);
+               lbs_queue_event(priv, event >> 8 & 0xff);
+       }
+
+       return IRQ_HANDLED;
+}
+
+
+
+
 /********************************************************************/
 /* Firmware                                                         */
 /********************************************************************/
@@ -476,8 +511,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
 
                if (remain < count)
                        count = remain;
-               /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
-                       __LINE__, sent, fw->size); */
 
                /* "write the number of bytes to be sent to the I/O Command
                 * write length register" */
@@ -544,18 +577,12 @@ static int if_cs_prog_real(struct if_cs_card *card)
 
        ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
        if (ret < 0) {
-               int i;
                lbs_pr_err("helper firmware doesn't answer\n");
-               for (i = 0; i < 0x50; i += 2)
-                       printk(KERN_INFO "## HS %02x: %04x\n",
-                               i, if_cs_read16(card, i));
                goto err_release;
        }
 
        for (sent = 0; sent < fw->size; sent += len) {
                len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
-               /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
-                       __LINE__, sent, fw->size); */
                if (len & 1) {
                        retry++;
                        lbs_pr_info("odd, need to retry this firmware block\n");
@@ -642,66 +669,6 @@ static int if_cs_host_to_card(struct lbs_private *priv,
 }
 
 
-static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
-{
-       struct if_cs_card *card = (struct if_cs_card *)priv->card;
-       int ret = 0;
-       u16 int_cause;
-       *ireg = 0;
-
-       lbs_deb_enter(LBS_DEB_CS);
-
-       if (priv->surpriseremoved)
-               goto out;
-
-       int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
-       if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
-
-       *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
-
-       if (!*ireg)
-               goto sbi_get_int_status_exit;
-
-sbi_get_int_status_exit:
-
-       /* is there a data packet for us? */
-       if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
-               struct sk_buff *skb = if_cs_receive_data(priv);
-               lbs_process_rxed_packet(priv, skb);
-               *ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
-       }
-
-       if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
-               priv->dnld_sent = DNLD_RES_RECEIVED;
-       }
-
-       /* Card has a command result for us */
-       if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
-               spin_lock(&priv->driver_lock);
-               ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
-               spin_unlock(&priv->driver_lock);
-               if (ret < 0)
-                       lbs_pr_err("could not receive cmd from card\n");
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
-       return ret;
-}
-
-
-static int if_cs_read_event_cause(struct lbs_private *priv)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-
-       priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
-       if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
-
-       return 0;
-}
-
-
-
 /********************************************************************/
 /* Card Services                                                    */
 /********************************************************************/
@@ -717,8 +684,8 @@ static void if_cs_release(struct pcmcia_device *p_dev)
 
        lbs_deb_enter(LBS_DEB_CS);
 
-       pcmcia_disable_device(p_dev);
        free_irq(p_dev->irq.AssignedIRQ, card);
+       pcmcia_disable_device(p_dev);
        if (card->iobase)
                ioport_unmap(card->iobase);
 
@@ -854,13 +821,10 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out2;
        }
 
-       /* Store pointers to our call-back functions */
+       /* Finish setting up fields in lbs_private */
        card->priv = priv;
        priv->card = card;
-       priv->hw_host_to_card     = if_cs_host_to_card;
-       priv->hw_get_int_status   = if_cs_get_int_status;
-       priv->hw_read_event_cause = if_cs_read_event_cause;
-
+       priv->hw_host_to_card = if_cs_host_to_card;
        priv->fw_ready = 1;
 
        /* Now actually get the IRQ */
@@ -882,6 +846,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out3;
        }
 
+       /* The firmware for the CF card supports powersave */
+       priv->ps_supported = 1;
+
        ret = 0;
        goto out;
 
index 5a828c7..51f664b 100644 (file)
@@ -91,8 +91,6 @@ struct if_sdio_card {
        const char              *firmware;
 
        u8                      buffer[65536];
-       u8                      int_cause;
-       u32                     event;
 
        spinlock_t              lock;
        struct if_sdio_packet   *packets;
@@ -129,13 +127,13 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
 static int if_sdio_handle_cmd(struct if_sdio_card *card,
                u8 *buffer, unsigned size)
 {
+       struct lbs_private *priv = card->priv;
        int ret;
        unsigned long flags;
+       u8 i;
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
-       spin_lock_irqsave(&card->priv->driver_lock, flags);
-
        if (size > LBS_CMD_BUFFER_SIZE) {
                lbs_deb_sdio("response packet too large (%d bytes)\n",
                        (int)size);
@@ -143,20 +141,20 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
                goto out;
        }
 
-       memcpy(card->priv->upld_buf, buffer, size);
-       card->priv->upld_len = size;
+       spin_lock_irqsave(&priv->driver_lock, flags);
 
-       card->int_cause |= MRVDRV_CMD_UPLD_RDY;
+       i = (priv->resp_idx == 0) ? 1 : 0;
+       BUG_ON(priv->resp_len[i]);
+       priv->resp_len[i] = size;
+       memcpy(priv->resp_buf[i], buffer, size);
+       lbs_notify_command_response(priv, i);
 
-       lbs_interrupt(card->priv);
+       spin_unlock_irqrestore(&card->priv->driver_lock, flags);
 
        ret = 0;
 
 out:
-       spin_unlock_irqrestore(&card->priv->driver_lock, flags);
-
        lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
        return ret;
 }
 
@@ -202,7 +200,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
                u8 *buffer, unsigned size)
 {
        int ret;
-       unsigned long flags;
        u32 event;
 
        lbs_deb_enter(LBS_DEB_SDIO);
@@ -222,18 +219,9 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
                event |= buffer[2] << 16;
                event |= buffer[1] << 8;
                event |= buffer[0] << 0;
-               event <<= SBI_EVENT_CAUSE_SHIFT;
        }
 
-       spin_lock_irqsave(&card->priv->driver_lock, flags);
-
-       card->event = event;
-       card->int_cause |= MRVDRV_CARDEVENT;
-
-       lbs_interrupt(card->priv);
-
-       spin_unlock_irqrestore(&card->priv->driver_lock, flags);
-
+       lbs_queue_event(card->priv, event & 0xFF);
        ret = 0;
 
 out:
@@ -770,37 +758,6 @@ out:
        return ret;
 }
 
-static int if_sdio_get_int_status(struct lbs_private *priv, u8 *ireg)
-{
-       struct if_sdio_card *card;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       card = priv->card;
-
-       *ireg = card->int_cause;
-       card->int_cause = 0;
-
-       lbs_deb_leave(LBS_DEB_SDIO);
-
-       return 0;
-}
-
-static int if_sdio_read_event_cause(struct lbs_private *priv)
-{
-       struct if_sdio_card *card;
-
-       lbs_deb_enter(LBS_DEB_SDIO);
-
-       card = priv->card;
-
-       priv->eventcause = card->event;
-
-       lbs_deb_leave(LBS_DEB_SDIO);
-
-       return 0;
-}
-
 /*******************************************************************/
 /* SDIO callbacks                                                  */
 /*******************************************************************/
@@ -863,6 +820,10 @@ static int if_sdio_probe(struct sdio_func *func,
                if (sscanf(func->card->info[i],
                                "ID: %x", &model) == 1)
                        break;
+               if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
+                       model = 4;
+                       break;
+               }
        }
 
        if (i == func->card->num_info) {
@@ -949,8 +910,6 @@ static int if_sdio_probe(struct sdio_func *func,
 
        priv->card = card;
        priv->hw_host_to_card = if_sdio_host_to_card;
-       priv->hw_get_int_status = if_sdio_get_int_status;
-       priv->hw_read_event_cause = if_sdio_read_event_cause;
 
        priv->fw_ready = 1;
 
index 7db8e6c..74ac86e 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/firmware.h>
 #include <linux/netdevice.h>
 #include <linux/usb.h>
+//#include <asm/olpc.h>
 
 #define DRV_NAME "usb8xxx"
 
@@ -38,8 +39,6 @@ static void if_usb_receive_fwload(struct urb *urb);
 static int if_usb_prog_firmware(struct if_usb_card *cardp);
 static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
                               uint8_t *payload, uint16_t nb);
-static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
-static int if_usb_read_event_cause(struct lbs_private *);
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
                        uint16_t nb);
 static void if_usb_free(struct if_usb_card *cardp);
@@ -104,12 +103,13 @@ static void if_usb_free(struct if_usb_card *cardp)
 
 static void if_usb_setup_firmware(struct lbs_private *priv)
 {
+       struct if_usb_card *cardp = priv->card;
        struct cmd_ds_set_boot2_ver b2_cmd;
        struct cmd_ds_802_11_fw_wake_method wake_method;
 
        b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
        b2_cmd.action = 0;
-       b2_cmd.version = priv->boot2_version;
+       b2_cmd.version = cardp->boot2_version;
 
        if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
                lbs_deb_usb("Setting boot2 version failed\n");
@@ -232,9 +232,7 @@ static int if_usb_probe(struct usb_interface *intf,
        cardp->priv->fw_ready = 1;
 
        priv->hw_host_to_card = if_usb_host_to_card;
-       priv->hw_get_int_status = if_usb_get_int_status;
-       priv->hw_read_event_cause = if_usb_read_event_cause;
-       priv->boot2_version = udev->descriptor.bcdDevice;
+       cardp->boot2_version = udev->descriptor.bcdDevice;
 
        if_usb_submit_rx_urb(cardp);
 
@@ -367,6 +365,13 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
        ret = usb_reset_device(cardp->udev);
        msleep(100);
 
+#ifdef CONFIG_OLPC
+       if (ret && machine_is_olpc()) {
+               printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
+               olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
+       }
+#endif
+
        lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
 
        return ret;
@@ -581,7 +586,6 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
        skb_pull(skb, MESSAGE_HEADER_LEN);
 
        lbs_process_rxed_packet(priv, skb);
-       priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
 }
 
 static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
@@ -589,6 +593,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
                                      struct if_usb_card *cardp,
                                      struct lbs_private *priv)
 {
+       u8 i;
+
        if (recvlength > LBS_CMD_BUFFER_SIZE) {
                lbs_deb_usbd(&cardp->udev->dev,
                             "The receive buffer is too large\n");
@@ -600,12 +606,15 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
                BUG();
 
        spin_lock(&priv->driver_lock);
-       cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
-       priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
-       memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
 
+       i = (priv->resp_idx == 0) ? 1 : 0;
+       BUG_ON(priv->resp_len[i]);
+       priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
+       memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
+               priv->resp_len[i]);
        kfree_skb(skb);
-       lbs_interrupt(priv);
+       lbs_notify_command_response(priv, i);
+
        spin_unlock(&priv->driver_lock);
 
        lbs_deb_usbd(&cardp->udev->dev,
@@ -628,6 +637,7 @@ static void if_usb_receive(struct urb *urb)
        uint8_t *recvbuff = NULL;
        uint32_t recvtype = 0;
        __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
+       uint32_t event;
 
        lbs_deb_enter(LBS_DEB_USB);
 
@@ -659,26 +669,20 @@ static void if_usb_receive(struct urb *urb)
                break;
 
        case CMD_TYPE_INDICATION:
-               /* Event cause handling */
-               spin_lock(&priv->driver_lock);
+               /* Event handling */
+               event = le32_to_cpu(pkt[1]);
+               lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
+               kfree_skb(skb);
 
-               cardp->usb_event_cause = le32_to_cpu(pkt[1]);
+               /* Icky undocumented magic special case */
+               if (event & 0xffff0000) {
+                       u32 trycount = (event & 0xffff0000) >> 16;
 
-               lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
-                            cardp->usb_event_cause);
+                       lbs_send_tx_feedback(priv, trycount);
+               } else
+                       lbs_queue_event(priv, event & 0xFF);
+               break;
 
-               /* Icky undocumented magic special case */
-               if (cardp->usb_event_cause & 0xffff0000) {
-                       lbs_send_tx_feedback(priv);
-                       spin_unlock(&priv->driver_lock);
-                       break;
-               }
-               cardp->usb_event_cause <<= 3;
-               cardp->usb_int_cause |= MRVDRV_CARDEVENT;
-               kfree_skb(skb);
-               lbs_interrupt(priv);
-               spin_unlock(&priv->driver_lock);
-               goto rx_exit;
        default:
                lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
                             recvtype);
@@ -721,30 +725,6 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
        return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
 }
 
-/* called with priv->driver_lock held */
-static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
-{
-       struct if_usb_card *cardp = priv->card;
-
-       *ireg = cardp->usb_int_cause;
-       cardp->usb_int_cause = 0;
-
-       lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
-
-       return 0;
-}
-
-static int if_usb_read_event_cause(struct lbs_private *priv)
-{
-       struct if_usb_card *cardp = priv->card;
-
-       priv->eventcause = cardp->usb_event_cause;
-       /* Re-submit rx urb here to avoid event lost issue */
-       if_usb_submit_rx_urb(cardp);
-
-       return 0;
-}
-
 /**
  *  @brief This function issues Boot command to the Boot2 code
  *  @param ivalue   1:Boot from FW by USB-Download
@@ -953,6 +933,7 @@ static struct usb_driver if_usb_driver = {
        .id_table = if_usb_table,
        .suspend = if_usb_suspend,
        .resume = if_usb_resume,
+       .reset_resume = if_usb_resume,
 };
 
 static int __init if_usb_init_module(void)
index 7706691..5771a83 100644 (file)
@@ -46,8 +46,6 @@ struct if_usb_card {
        struct lbs_private *priv;
 
        struct sk_buff *rx_skb;
-       uint32_t usb_event_cause;
-       uint8_t usb_int_cause;
 
        uint8_t ep_in;
        uint8_t ep_out;
@@ -70,6 +68,7 @@ struct if_usb_card {
        uint8_t fwfinalblk;
        uint8_t surprise_removed;
 
+       __le16 boot2_version;
 };
 
 /** fwheader */
diff --git a/package/libertas/src/ioctl.c b/package/libertas/src/ioctl.c
new file mode 100644 (file)
index 0000000..18aebe9
--- /dev/null
@@ -0,0 +1,1243 @@
+/**
+  * This file contains ioctl functions
+  */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "wext.h"
+#include "cmd.h"
+#include "ioctl.h"
+
+#define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
+                               IW_ESSID_MAX_SIZE + \
+                               IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+                               IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
+                               IW_EV_PARAM_LEN + 40)   /* 40 for WPAIE */
+
+#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
+
+static int lbs_set_region(struct lbs_private * priv, u16 region_code)
+{
+       int i;
+       int ret = 0;
+
+       for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+               // use the region code to search for the index
+               if (region_code == lbs_region_code_to_index[i]) {
+                       priv->regioncode = region_code;
+                       break;
+               }
+       }
+
+       // if it's unidentified region code
+       if (i >= MRVDRV_MAX_REGION_CODE) {
+               lbs_deb_ioctl("region Code not identified\n");
+               ret = -1;
+               goto done;
+       }
+
+       if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
+               ret = -EINVAL;
+       }
+
+done:
+       lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
+       return ret;
+}
+
+static inline int hex2int(char c)
+{
+       if (c >= '0' && c <= '9')
+               return (c - '0');
+       if (c >= 'a' && c <= 'f')
+               return (c - 'a' + 10);
+       if (c >= 'A' && c <= 'F')
+               return (c - 'A' + 10);
+       return -1;
+}
+
+/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
+   into binary format (6 bytes).
+
+   This function expects that each byte is represented with 2 characters
+   (e.g., 11:2:11:11:11:11 is invalid)
+
+ */
+static char *eth_str2addr(char *ethstr, u8 * addr)
+{
+       int i, val, val2;
+       char *pos = ethstr;
+
+       /* get rid of initial blanks */
+       while (*pos == ' ' || *pos == '\t')
+               ++pos;
+
+       for (i = 0; i < 6; i++) {
+               val = hex2int(*pos++);
+               if (val < 0)
+                       return NULL;
+               val2 = hex2int(*pos++);
+               if (val2 < 0)
+                       return NULL;
+               addr[i] = (val * 16 + val2) & 0xff;
+
+               if (i < 5 && *pos++ != ':')
+                       return NULL;
+       }
+       return pos;
+}
+
+/* this writes xx:xx:xx:xx:xx:xx into ethstr
+   (ethstr must have space for 18 chars) */
+static int eth_addr2str(u8 * addr, char *ethstr)
+{
+       int i;
+       char *pos = ethstr;
+
+       for (i = 0; i < 6; i++) {
+               sprintf(pos, "%02x", addr[i] & 0xff);
+               pos += 2;
+               if (i < 5)
+                       *pos++ = ':';
+       }
+       return 17;
+}
+
+/**
+ *  @brief          Add an entry to the BT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_bt_add_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char ethaddrs_str[18];
+       char *pos;
+       u8 ethaddr[ETH_ALEN];
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+                          sizeof(ethaddrs_str)))
+               return -EFAULT;
+
+       if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+               lbs_pr_info("BT_ADD: Invalid MAC address\n");
+               return -EINVAL;
+       }
+
+       lbs_deb_ioctl("BT: adding %s\n", ethaddrs_str);
+       ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
+                                     CMD_ACT_BT_ACCESS_ADD,
+                                     CMD_OPTION_WAITFORRSP, 0, ethaddr);
+       lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  @brief          Delete an entry from the BT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_bt_del_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char ethaddrs_str[18];
+       u8 ethaddr[ETH_ALEN];
+       char *pos;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+                          sizeof(ethaddrs_str)))
+               return -EFAULT;
+
+       if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+               lbs_pr_info("Invalid MAC address\n");
+               return -EINVAL;
+       }
+
+       lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str);
+
+       return (lbs_prepare_and_send_command(priv,
+                                     CMD_BT_ACCESS,
+                                     CMD_ACT_BT_ACCESS_DEL,
+                                     CMD_OPTION_WAITFORRSP, 0, ethaddr));
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the BT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_bt_reset_ioctl(struct lbs_private * priv)
+{
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       lbs_pr_alert( "BT: resetting\n");
+
+       return (lbs_prepare_and_send_command(priv,
+                                     CMD_BT_ACCESS,
+                                     CMD_ACT_BT_ACCESS_RESET,
+                                     CMD_OPTION_WAITFORRSP, 0, NULL));
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          List an entry from the BT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_bt_list_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       int pos;
+       char *addr1;
+       struct iwreq *wrq = (struct iwreq *)req;
+       /* used to pass id and store the bt entry returned by the FW */
+       union {
+               u32 id;
+               char addr1addr2[2 * ETH_ALEN];
+       } param;
+       static char outstr[64];
+       char *pbuf = outstr;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
+               lbs_deb_ioctl("Copy from user failed\n");
+               return -1;
+       }
+       param.id = simple_strtoul(outstr, NULL, 10);
+       pos = sprintf(pbuf, "%d: ", param.id);
+       pbuf += pos;
+
+       ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
+                                   CMD_ACT_BT_ACCESS_LIST,
+                                   CMD_OPTION_WAITFORRSP, 0,
+                                   (char *)&param);
+
+       if (ret == 0) {
+               addr1 = param.addr1addr2;
+
+               pos = sprintf(pbuf, "BT includes node ");
+               pbuf += pos;
+               pos = eth_addr2str(addr1, pbuf);
+               pbuf += pos;
+       } else {
+               sprintf(pbuf, "(null)");
+               pbuf += pos;
+       }
+
+       wrq->u.data.length = strlen(outstr);
+       if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
+                        wrq->u.data.length)) {
+               lbs_deb_ioctl("BT_LIST: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0 ;
+}
+
+/**
+ *  @brief          Sets inverted state of blacklist (non-zero if inverted)
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_bt_set_invert_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       int ret;
+       struct iwreq *wrq = (struct iwreq *)req;
+       union {
+               u32 id;
+               char addr1addr2[2 * ETH_ALEN];
+       } param;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       param.id = SUBCMD_DATA(wrq) ;
+       ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
+                                   CMD_ACT_BT_ACCESS_SET_INVERT,
+                                   CMD_OPTION_WAITFORRSP, 0,
+                                   (char *)&param);
+       if (ret != 0)
+               return -EFAULT;
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          Gets inverted state of blacklist (non-zero if inverted)
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_bt_get_invert_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       int ret;
+       union {
+               __le32 id;
+               char addr1addr2[2 * ETH_ALEN];
+       } param;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
+                                   CMD_ACT_BT_ACCESS_GET_INVERT,
+                                   CMD_OPTION_WAITFORRSP, 0,
+                                   (char *)&param);
+
+       if (ret == 0)
+               wrq->u.param.value = le32_to_cpu(param.id);
+       else
+               return -EFAULT;
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          Find the next parameter in an input string
+ *  @param ptr      A pointer to the input parameter string
+ *  @return         A pointer to the next parameter, or 0 if no parameters left.
+ */
+static char * next_param(char * ptr)
+{
+       if (!ptr) return NULL;
+       while (*ptr == ' ' || *ptr == '\t') ++ptr;
+       return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ *  @brief          Add an entry to the FWT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_add_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[128];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+               lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+               lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.metric =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.metric = cpu_to_le32(FWT_DEFAULT_METRIC);
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.dir = FWT_DEFAULT_DIR;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.rate = FWT_DEFAULT_RATE;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.ssn =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.ssn = cpu_to_le32(FWT_DEFAULT_SSN);
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.dsn =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.dsn = cpu_to_le32(FWT_DEFAULT_DSN);
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.ttl = FWT_DEFAULT_TTL;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.expiration =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.expiration = cpu_to_le32(FWT_DEFAULT_EXPIRATION);
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.snr =
+                       cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+       else
+               fwt_access.snr = cpu_to_le32(FWT_DEFAULT_SNR);
+
+#ifdef DEBUG
+       {
+               char ethaddr1_str[18], ethaddr2_str[18];
+               eth_addr2str(fwt_access.da, ethaddr1_str);
+               eth_addr2str(fwt_access.ra, ethaddr2_str);
+               lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
+                      fwt_access.dir, ethaddr2_str);
+               lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
+                      fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
+                      fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
+                      fwt_access.sleepmode, fwt_access.snr);
+       }
+#endif
+
+       ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
+                                               CMD_ACT_FWT_ACCESS_ADD,
+                                               CMD_OPTION_WAITFORRSP, 0,
+                                               (void *)&fwt_access);
+
+       lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  @brief          Delete an entry from the FWT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_del_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[64];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+               lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+               lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
+               return -EINVAL;
+       }
+
+       if ((ptr = next_param(ptr)))
+               fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+       else
+               fwt_access.dir = FWT_DEFAULT_DIR;
+
+#ifdef DEBUG
+       {
+               char ethaddr1_str[18], ethaddr2_str[18];
+               lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
+               eth_addr2str(fwt_access.da, ethaddr1_str);
+               eth_addr2str(fwt_access.ra, ethaddr2_str);
+               lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
+                      ethaddr2_str, fwt_access.dir);
+       }
+#endif
+
+       ret = lbs_prepare_and_send_command(priv,
+                                               CMD_FWT_ACCESS,
+                                               CMD_ACT_FWT_ACCESS_DEL,
+                                               CMD_OPTION_WAITFORRSP, 0,
+                                               (void *)&fwt_access);
+       lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
+       return ret;
+}
+
+
+/**
+ *  @brief             Print route parameters
+ *  @param fwt_access  struct cmd_ds_fwt_access with route info
+ *  @param buf         destination buffer for route info
+ */
+static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
+{
+       buf += sprintf(buf, " ");
+       buf += eth_addr2str(fwt_access.da, buf);
+       buf += sprintf(buf, " ");
+       buf += eth_addr2str(fwt_access.ra, buf);
+       buf += sprintf(buf, " %u", fwt_access.valid);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
+       buf += sprintf(buf, " %u", fwt_access.dir);
+       buf += sprintf(buf, " %u", fwt_access.rate);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
+       buf += sprintf(buf, " %u", fwt_access.hopcount);
+       buf += sprintf(buf, " %u", fwt_access.ttl);
+       buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
+       buf += sprintf(buf, " %u", fwt_access.sleepmode);
+       buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr));
+       buf += eth_addr2str(fwt_access.prec, buf);
+}
+
+/**
+ *  @brief          Lookup an entry in the FWT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_lookup_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[64];
+       char *ptr;
+       static struct cmd_ds_fwt_access fwt_access;
+       static char out_str[128];
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+               lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
+               return -EINVAL;
+       }
+
+#ifdef DEBUG
+       {
+               char ethaddr1_str[18];
+               lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
+               eth_addr2str(fwt_access.da, ethaddr1_str);
+               lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
+       }
+#endif
+
+       ret = lbs_prepare_and_send_command(priv,
+                                               CMD_FWT_ACCESS,
+                                               CMD_ACT_FWT_ACCESS_LOOKUP,
+                                               CMD_OPTION_WAITFORRSP, 0,
+                                               (void *)&fwt_access);
+
+       if (ret == 0)
+               print_route(fwt_access, out_str);
+       else
+               sprintf(out_str, "(null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the FWT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_reset_ioctl(struct lbs_private * priv)
+{
+       lbs_deb_ioctl("FWT: resetting\n");
+
+       return (lbs_prepare_and_send_command(priv,
+                                     CMD_FWT_ACCESS,
+                                     CMD_ACT_FWT_ACCESS_RESET,
+                                     CMD_OPTION_WAITFORRSP, 0, NULL));
+}
+
+/**
+ *  @brief          List an entry from the FWT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_list_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[8];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr = in_str;
+       static char out_str[128];
+       char *pbuf = out_str;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+       {
+               lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str);
+               lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
+       }
+#endif
+
+       ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
+                                   CMD_ACT_FWT_ACCESS_LIST,
+                                   CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access);
+
+       if (ret == 0)
+               print_route(fwt_access, pbuf);
+       else
+               pbuf += sprintf(pbuf, " (null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ret = 0;
+
+out:
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return ret;
+}
+
+/**
+ *  @brief          List an entry from the FRT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_list_route_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[64];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr = in_str;
+       static char out_str[128];
+       char *pbuf = out_str;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+       {
+               lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str);
+               lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
+       }
+#endif
+
+       ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
+                                   CMD_ACT_FWT_ACCESS_LIST_ROUTE,
+                                   CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access);
+
+       if (ret == 0) {
+               print_route(fwt_access, pbuf);
+       } else
+               pbuf += sprintf(pbuf, " (null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          List an entry from the FNT table
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_list_neighbor_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       char in_str[8];
+       static struct cmd_ds_fwt_access fwt_access;
+       char *ptr = in_str;
+       static char out_str[128];
+       char *pbuf = out_str;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+               return -EFAULT;
+
+       memset(&fwt_access, 0, sizeof(fwt_access));
+       fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+       {
+               lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str);
+               lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
+       }
+#endif
+
+       ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
+                                   CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
+                                   CMD_OPTION_WAITFORRSP, 0,
+                                   (void *)&fwt_access);
+
+       if (ret == 0) {
+               pbuf += sprintf(pbuf, " ra ");
+               pbuf += eth_addr2str(fwt_access.ra, pbuf);
+               pbuf += sprintf(pbuf, "  slp %u", fwt_access.sleepmode);
+               pbuf += sprintf(pbuf, "  snr %u", le32_to_cpu(fwt_access.snr));
+               pbuf += sprintf(pbuf, "  ref %u", le32_to_cpu(fwt_access.references));
+       } else
+               pbuf += sprintf(pbuf, " (null)");
+
+       wrq->u.data.length = strlen(out_str);
+       if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+                        wrq->u.data.length)) {
+               lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
+               return -EFAULT;
+       }
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          Cleans up the route (FRT) and neighbor (FNT) tables
+ *                  (Garbage Collection)
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_cleanup_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       static struct cmd_ds_fwt_access fwt_access;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       lbs_deb_ioctl("FWT: cleaning up\n");
+
+       memset(&fwt_access, 0, sizeof(fwt_access));
+
+       ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
+                                   CMD_ACT_FWT_ACCESS_CLEANUP,
+                                   CMD_OPTION_WAITFORRSP, 0,
+                                   (void *)&fwt_access);
+
+       if (ret == 0)
+               wrq->u.param.value = le32_to_cpu(fwt_access.references);
+       else
+               return -EFAULT;
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+/**
+ *  @brief          Gets firmware internal time (debug purposes)
+ *  @param priv     A pointer to struct lbs_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int lbs_fwt_time_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       static struct cmd_ds_fwt_access fwt_access;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       lbs_deb_ioctl("FWT: getting time\n");
+
+       memset(&fwt_access, 0, sizeof(fwt_access));
+
+       ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
+                                   CMD_ACT_FWT_ACCESS_TIME,
+                                   CMD_OPTION_WAITFORRSP, 0,
+                                   (void *)&fwt_access);
+
+       if (ret == 0)
+               wrq->u.param.value = le32_to_cpu(fwt_access.references);
+       else
+               return -EFAULT;
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return 0;
+}
+
+
+/**
+ *  @brief              Manages all mesh related ioctls
+ *  @param priv         A pointer to struct lbs_private structure
+ *  @param req          A pointer to ifreq structure
+ *  @param cmd         The command type
+ *  @param host_subcmd  The device code for the subcommand
+ *                          0: sets a value in the firmware
+ *                          1: retrieves an int from the firmware
+ *  @return             0 --success, otherwise fail
+ */
+static int lbs_mesh_ioctl(struct lbs_private * priv, struct iwreq * wrq, 
+               int cmd, int subcmd)
+{
+       struct cmd_ds_mesh_access mesh_access;
+       int parameter;
+       char str[128];
+       char *ptr = str;
+       int ret, i;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       memset(&mesh_access, 0, sizeof(mesh_access));
+
+       if (cmd == LBS_SETONEINT_GETNONE) {
+               parameter = SUBCMD_DATA(wrq);
+
+               /* Convert rate from Mbps -> firmware rate index */
+               if (subcmd == CMD_ACT_MESH_SET_BCAST_RATE)
+                       parameter = lbs_data_rate_to_fw_index(parameter);
+
+               if (parameter < 0)
+                       return -EINVAL;
+               mesh_access.data[0] = cpu_to_le32(parameter);
+       } else if (subcmd == CMD_ACT_MESH_SET_LINK_COSTS) {
+               if (copy_from_user(str, wrq->u.data.pointer, sizeof(str)))
+                       return -EFAULT;
+
+               for (i = 0; i < COSTS_LIST_SIZE; i++) {
+                       mesh_access.data[i] = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+                       if (!(ptr = next_param(ptr)) && i!= (COSTS_LIST_SIZE - 1))
+                               return -EINVAL;
+               }
+       }
+
+       ret = lbs_mesh_access(priv, subcmd, &mesh_access);
+
+       if (ret != 0)
+               return ret;
+
+       if (cmd == LBS_SETNONE_GETONEINT) {
+               u32 data = le32_to_cpu(mesh_access.data[0]);
+
+               if (subcmd == CMD_ACT_MESH_GET_BCAST_RATE)
+                       wrq->u.param.value = lbs_fw_index_to_data_rate(data);
+               else
+                       wrq->u.param.value = data;
+       } else if (subcmd == CMD_ACT_MESH_GET_LINK_COSTS) {
+               for (i = 0; i < COSTS_LIST_SIZE; i++)
+                       ptr += sprintf (ptr, " %u", le32_to_cpu(mesh_access.data[i]));
+               wrq->u.data.length = strlen(str);
+
+               if (copy_to_user(wrq->u.data.pointer, (char *)str,
+                                wrq->u.data.length)) {
+                       lbs_deb_ioctl("MESH_IOCTL: Copy to user failed!\n");
+                       ret = -EFAULT;
+               }
+       }
+
+       lbs_deb_leave(LBS_DEB_IOCTL);
+       return ret;
+}
+
+/**
+ *  @brief Control Beacon transmissions
+ *  @param priv                 A pointer to struct lbs_private structure
+ *  @param wrq                 A pointer to iwreq structure
+ *  @return                    0 --success, otherwise fail
+ */
+static int lbs_bcn_ioctl(struct lbs_private * priv, struct iwreq *wrq)
+{
+       int ret;
+       int data[2];
+
+       memset(data, 0, sizeof(data));
+       if (!wrq->u.data.length) {
+               lbs_deb_ioctl("Get Beacon control\n");
+               ret = lbs_prepare_and_send_command(priv,
+                                           CMD_802_11_BEACON_CTRL,
+                                           CMD_ACT_GET,
+                                           CMD_OPTION_WAITFORRSP, 0, NULL);
+               data[0] = priv->beacon_enable;
+               data[1] = priv->beacon_period;
+               if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+                       lbs_deb_ioctl("Copy to user failed\n");
+                       return -EFAULT;
+               }
+#define GET_TWO_INT    2
+               wrq->u.data.length = GET_TWO_INT;
+       } else {
+               lbs_deb_ioctl("Set beacon control\n");
+               if (wrq->u.data.length > 2)
+                       return -EINVAL;
+               if (copy_from_user (data, wrq->u.data.pointer,
+                    sizeof(int) * wrq->u.data.length)) {
+                       lbs_deb_ioctl("Copy from user failed\n");
+                       return -EFAULT;
+               }
+               priv->beacon_enable = data[0];
+               if (wrq->u.data.length > 1) {
+               if ((data[1] > MRVDRV_MAX_BEACON_INTERVAL)
+                   || (data[1] < MRVDRV_MIN_BEACON_INTERVAL))
+                       return -ENOTSUPP;
+               priv->beacon_period= data[1];
+               }
+               ret = lbs_prepare_and_send_command(priv,
+                                           CMD_802_11_BEACON_CTRL,
+                                           CMD_ACT_SET,
+                                           CMD_OPTION_WAITFORRSP, 0, NULL);
+       }
+       return ret;
+}
+
+static int lbs_led_gpio_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       int i, ret = 0;
+       int data[16];
+       struct cmd_ds_802_11_led_ctrl ctrl;
+       struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio *) ctrl.data;
+       int len = wrq->u.data.length;
+
+       if ((len > MAX_LEDS * 2) || (len % 2 != 0))
+               return -ENOTSUPP;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       if (len == 0) {
+               ctrl.action = cpu_to_le16(CMD_ACT_GET);
+       } else {
+               if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) {
+                       lbs_deb_ioctl("Copy from user failed\n");
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               ctrl.action = cpu_to_le16(CMD_ACT_SET);
+               ctrl.numled = cpu_to_le16(0);
+               gpio->header.type = cpu_to_le16(TLV_TYPE_LED_GPIO);
+               gpio->header.len = cpu_to_le16(len);
+               for (i = 0; i < len; i += 2) {
+                       gpio->ledpin[i / 2].led = data[i];
+                       gpio->ledpin[i / 2].pin = data[i + 1];
+               }
+       }
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL,
+                       0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl);
+       if (ret) {
+               lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret);
+               goto out;
+       }
+       len = le16_to_cpu(gpio->header.len);
+       for (i = 0; i < len; i += 2) {
+               data[i] = gpio->ledpin[i / 2].led;
+               data[i + 1] = gpio->ledpin[i / 2].pin;
+       }
+
+       if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * len)) {
+               lbs_deb_ioctl("Copy to user failed\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       wrq->u.data.length = len;
+
+out:
+       return ret;
+}
+
+
+static int lbs_led_bhv_ioctl(struct lbs_private * priv, struct ifreq *req)
+{
+       struct iwreq *wrq = (struct iwreq *)req;
+       int i, ret = 0;
+       int data[MAX_LEDS*4];
+       int firmwarestate = 0;
+       struct cmd_ds_802_11_led_ctrl ctrl;
+       struct mrvlietypes_ledbhv *bhv = (struct mrvlietypes_ledbhv *) ctrl.data;
+       int len = wrq->u.data.length;
+
+       if ((len > MAX_LEDS * 4) ||(len == 0)  )
+               return -ENOTSUPP;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) {
+                       lbs_deb_ioctl("Copy from user failed\n");
+                       ret = -EFAULT;
+                       goto out;
+       }
+       if (len == 1) {
+               ctrl.action = cpu_to_le16(CMD_ACT_GET);
+               firmwarestate = data[0];
+       } else {
+               
+               if (len % 4 != 0 )
+                       return -ENOTSUPP;
+
+               bhv->header.type = cpu_to_le16(TLV_TYPE_LEDBEHAVIOR);
+               bhv->header.len = cpu_to_le16(len);
+               ctrl.action = cpu_to_le16(CMD_ACT_SET);
+               ctrl.numled = cpu_to_le16(0);
+               for (i = 0; i < len; i += 4) {
+                       bhv->ledbhv[i / 4].firmwarestate = data[i];
+                       bhv->ledbhv[i / 4].led = data[i + 1];
+                       bhv->ledbhv[i / 4].ledstate = data[i + 2];
+                       bhv->ledbhv[i / 4].ledarg = data[i + 3];
+               }
+       }
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL,
+                       0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl);
+       if (ret) {
+               lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret);
+               goto out;
+       }
+
+       /* Get LED behavior IE, we have received gpio control as well when len 
+          is equal to 1. */
+       if (len ==1 ) {
+               bhv = (struct mrvlietypes_ledbhv *) 
+                       ((unsigned char *)bhv->ledbhv + le16_to_cpu(bhv->header.len));
+               i = 0;
+               while ( i < (MAX_LEDS*4) &&
+                       (bhv->header.type != cpu_to_le16(MRVL_TERMINATE_TLV_ID)) ) {
+                       if (bhv->ledbhv[0].firmwarestate == firmwarestate) {
+                               data[i++] = bhv->ledbhv[0].firmwarestate;
+                               data[i++] = bhv->ledbhv[0].led;
+                               data[i++] = bhv->ledbhv[0].ledstate;
+                               data[i++] = bhv->ledbhv[0].ledarg;
+                       }
+                       bhv++;
+               }
+               len = i;
+       } else {
+               for (i = 0; i < le16_to_cpu(bhv->header.len); i += 4) {
+                       data[i] = bhv->ledbhv[i / 4].firmwarestate;
+                       data[i + 1] = bhv->ledbhv[i / 4].led;
+                       data[i + 2] = bhv->ledbhv[i / 4].ledstate;
+                       data[i + 3] = bhv->ledbhv[i / 4].ledarg;
+               }
+               len = le16_to_cpu(bhv->header.len);
+       }
+
+       if (copy_to_user(wrq->u.data.pointer, data,
+                        sizeof(int) * len)) {
+               lbs_deb_ioctl("Copy to user failed\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       wrq->u.data.length = len;
+
+out:
+       return ret;
+}
+
+/**
+ *  @brief ioctl function - entry point
+ *
+ *  @param dev         A pointer to net_device structure
+ *  @param req         A pointer to ifreq structure
+ *  @param cmd                 command
+ *  @return            0--success, otherwise fail
+ */
+int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+       int *pdata;
+       int ret = 0;
+       struct lbs_private *priv = dev->priv;
+       struct iwreq *wrq = (struct iwreq *)req;
+
+       lbs_deb_enter(LBS_DEB_IOCTL);
+
+       lbs_deb_ioctl("lbs_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+       switch (cmd) {
+       case LBS_SETNONE_GETNONE:
+               switch (wrq->u.data.flags) {
+               case LBS_SUBCMD_BT_RESET:
+                       lbs_bt_reset_ioctl(priv);
+                       break;
+               case LBS_SUBCMD_FWT_RESET:
+                       lbs_fwt_reset_ioctl(priv);
+                       break;
+               }
+               break;
+
+       case LBS_SETONEINT_GETNONE:
+               switch (wrq->u.mode) {
+               case LBS_SUBCMD_SET_REGION:
+                       ret = lbs_set_region(priv, (u16) SUBCMD_DATA(wrq));
+                       break;
+               case LBS_SUBCMD_MESH_SET_TTL:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_SET_TTL);
+                       break;
+               case LBS_SUBCMD_MESH_SET_BCAST_RATE:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_SET_BCAST_RATE);
+                       break;
+               case LBS_SUBCMD_MESH_SET_RREQ_DELAY:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_SET_RREQ_DELAY);
+                       break;
+               case LBS_SUBCMD_MESH_SET_ROUTE_EXP:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_SET_ROUTE_EXP);
+                       break;
+               case LBS_SUBCMD_BT_SET_INVERT:
+                       ret = lbs_bt_set_invert_ioctl(priv, req);
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+               break;
+
+       case LBS_SET128CHAR_GET128CHAR:
+               switch ((int)wrq->u.data.flags) {
+               case LBS_SUBCMD_BT_ADD:
+                       ret = lbs_bt_add_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_BT_DEL:
+                       ret = lbs_bt_del_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_BT_LIST:
+                       ret = lbs_bt_list_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_ADD:
+                       ret = lbs_fwt_add_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_DEL:
+                       ret = lbs_fwt_del_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_LOOKUP:
+                       ret = lbs_fwt_lookup_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_LIST_NEIGHBOR:
+                       ret = lbs_fwt_list_neighbor_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_LIST:
+                       ret = lbs_fwt_list_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_LIST_ROUTE:
+                       ret = lbs_fwt_list_route_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_MESH_SET_LINK_COSTS:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_SET_LINK_COSTS);
+                       break ;
+               case LBS_SUBCMD_MESH_GET_LINK_COSTS:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_GET_LINK_COSTS);
+                       break;
+               }
+               break;
+
+       case LBS_SETNONE_GETONEINT:
+               switch (wrq->u.mode) {
+               case LBS_SUBCMD_GET_REGION:
+                       pdata = (int *)wrq->u.name;
+                       *pdata = (int)priv->regioncode;
+                       break;
+               case LBS_SUBCMD_FWT_CLEANUP:
+                       ret = lbs_fwt_cleanup_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_FWT_TIME:
+                       ret = lbs_fwt_time_ioctl(priv, req);
+                       break;
+               case LBS_SUBCMD_MESH_GET_TTL:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_GET_TTL);
+                       break;
+               case LBS_SUBCMD_MESH_GET_BCAST_RATE:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_GET_BCAST_RATE);
+                       break;
+               case LBS_SUBCMD_MESH_GET_RREQ_DELAY:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_GET_RREQ_DELAY);
+                       break;
+               case LBS_SUBCMD_MESH_GET_ROUTE_EXP:
+                       ret = lbs_mesh_ioctl(priv, wrq, cmd,
+                                       CMD_ACT_MESH_GET_ROUTE_EXP);
+                       break;
+               case LBS_SUBCMD_BT_GET_INVERT:
+                       ret = lbs_bt_get_invert_ioctl(priv, req);
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+               }
+               break;
+
+       case LBS_SET_GET_SIXTEEN_INT:
+               switch ((int)wrq->u.data.flags) {
+               case LBS_LED_GPIO_CTRL:
+                       ret = lbs_led_gpio_ioctl(priv, req);
+                       break;
+               case LBS_BCN_CTRL:
+                       ret = lbs_bcn_ioctl(priv,wrq);
+                       break;
+               case LBS_LED_BEHAVIOR_CTRL:
+                       ret = lbs_led_bhv_ioctl(priv, req);
+                       break;
+               }
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
+       return ret;
+}
diff --git a/package/libertas/src/ioctl.h b/package/libertas/src/ioctl.h
new file mode 100644 (file)
index 0000000..e4f835c
--- /dev/null
@@ -0,0 +1,49 @@
+#define COSTS_LIST_SIZE                        4
+
+/* iwpriv places the subcmd number in the first uint32_t;
+   data buffer follows that */
+#define SUBCMD_OFFSET                  sizeof(uint32_t)
+#define SUBCMD_DATA(x)                 *((int *)(x->u.name + SUBCMD_OFFSET))
+
+/** Private ioctls and ioctls subcommands */
+#define LBS_SETNONE_GETNONE                    (SIOCIWFIRSTPRIV + 8)
+#define LBS_SUBCMD_BT_RESET                    13
+#define LBS_SUBCMD_FWT_RESET                   14
+
+#define LBS_SETNONE_GETONEINT                  (SIOCIWFIRSTPRIV + 15)
+#define LBS_SUBCMD_GET_REGION                  1
+#define LBS_SUBCMD_FWT_CLEANUP                 15
+#define LBS_SUBCMD_FWT_TIME                    16
+#define LBS_SUBCMD_MESH_GET_TTL                        17
+#define LBS_SUBCMD_BT_GET_INVERT               18
+#define LBS_SUBCMD_MESH_GET_BCAST_RATE         19
+#define LBS_SUBCMD_MESH_GET_RREQ_DELAY         20
+#define LBS_SUBCMD_MESH_GET_ROUTE_EXP          21
+
+#define LBS_SETONEINT_GETNONE                  (SIOCIWFIRSTPRIV + 24)
+#define LBS_SUBCMD_SET_REGION                  8
+#define LBS_SUBCMD_MESH_SET_TTL                        18
+#define LBS_SUBCMD_BT_SET_INVERT               19
+#define LBS_SUBCMD_MESH_SET_BCAST_RATE         20
+#define LBS_SUBCMD_MESH_SET_RREQ_DELAY         21
+#define LBS_SUBCMD_MESH_SET_ROUTE_EXP          22
+
+#define LBS_SET128CHAR_GET128CHAR              (SIOCIWFIRSTPRIV + 25)
+#define LBS_SUBCMD_BT_ADD                      18
+#define LBS_SUBCMD_BT_DEL                      19
+#define LBS_SUBCMD_BT_LIST                     20
+#define LBS_SUBCMD_FWT_ADD                     21
+#define LBS_SUBCMD_FWT_DEL                     22
+#define LBS_SUBCMD_FWT_LOOKUP                  23
+#define LBS_SUBCMD_FWT_LIST_NEIGHBOR           24
+#define LBS_SUBCMD_FWT_LIST                    25
+#define LBS_SUBCMD_FWT_LIST_ROUTE              26
+#define LBS_SUBCMD_MESH_SET_LINK_COSTS         27
+#define LBS_SUBCMD_MESH_GET_LINK_COSTS         28
+
+#define LBS_SET_GET_SIXTEEN_INT                        (SIOCIWFIRSTPRIV + 29)
+#define LBS_LED_GPIO_CTRL                      5
+#define LBS_BCN_CTRL                           6
+#define LBS_LED_BEHAVIOR_CTRL                  7
+
+int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
index 91b2f23..3291ced 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
+#include <linux/kfifo.h>
+//#include <asm/olpc.h>
 
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
 #include "dev.h"
 #include "wext.h"
 #include "debugfs.h"
+#include "scan.h"
 #include "assoc.h"
-#include "join.h"
 #include "cmd.h"
+#include "ioctl.h"
 
 #define DRIVER_RELEASE_VERSION "323.p0"
 const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@ -37,6 +40,11 @@ EXPORT_SYMBOL_GPL(lbs_debug);
 module_param_named(libertas_debug, lbs_debug, int, 0644);
 
 
+/* This global structure is used to send the confirm_sleep command as
+ * fast as possible down to the firmware. */
+struct cmd_confirm_sleep confirm_sleep;
+
+
 #define LBS_TX_PWR_DEFAULT             20      /*100mW */
 #define LBS_TX_PWR_US_DEFAULT          20      /*100mW */
 #define LBS_TX_PWR_JP_DEFAULT          16      /*50mW */
@@ -277,10 +285,10 @@ static ssize_t lbs_rtap_set(struct device *dev,
        struct lbs_private *priv = to_net_dev(dev)->priv;
 
        sscanf(buf, "%x", &monitor_mode);
-       if (monitor_mode != LBS_MONITOR_OFF) {
-               if(priv->monitormode == monitor_mode)
+       if (monitor_mode) {
+               if (priv->monitormode == monitor_mode)
                        return strlen(buf);
-               if (priv->monitormode == LBS_MONITOR_OFF) {
+               if (!priv->monitormode) {
                        if (priv->infra_open || priv->mesh_open)
                                return -EBUSY;
                        if (priv->mode == IW_MODE_INFRA)
@@ -293,9 +301,9 @@ static ssize_t lbs_rtap_set(struct device *dev,
        }
 
        else {
-               if (priv->monitormode == LBS_MONITOR_OFF)
+               if (!priv->monitormode)
                        return strlen(buf);
-               priv->monitormode = LBS_MONITOR_OFF;
+               priv->monitormode = 0;
                lbs_remove_rtap(priv);
 
                if (priv->currenttxskb) {
@@ -388,9 +396,11 @@ static int lbs_dev_open(struct net_device *dev)
        struct lbs_private *priv = (struct lbs_private *) dev->priv ;
        int ret = 0;
 
+       lbs_deb_enter(LBS_DEB_NET);
+
        spin_lock_irq(&priv->driver_lock);
 
-       if (priv->monitormode != LBS_MONITOR_OFF) {
+       if (priv->monitormode) {
                ret = -EBUSY;
                goto out;
        }
@@ -413,6 +423,7 @@ static int lbs_dev_open(struct net_device *dev)
  out:
 
        spin_unlock_irq(&priv->driver_lock);
+       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
        return ret;
 }
 
@@ -426,6 +437,7 @@ static int lbs_mesh_stop(struct net_device *dev)
 {
        struct lbs_private *priv = (struct lbs_private *) (dev->priv);
 
+       lbs_deb_enter(LBS_DEB_MESH);
        spin_lock_irq(&priv->driver_lock);
 
        priv->mesh_open = 0;
@@ -435,6 +447,8 @@ static int lbs_mesh_stop(struct net_device *dev)
        netif_carrier_off(dev);
 
        spin_unlock_irq(&priv->driver_lock);
+
+       lbs_deb_leave(LBS_DEB_MESH);
        return 0;
 }
 
@@ -448,13 +462,14 @@ static int lbs_eth_stop(struct net_device *dev)
 {
        struct lbs_private *priv = (struct lbs_private *) dev->priv;
 
-       spin_lock_irq(&priv->driver_lock);
+       lbs_deb_enter(LBS_DEB_NET);
 
+       spin_lock_irq(&priv->driver_lock);
        priv->infra_open = 0;
-
        netif_stop_queue(dev);
-
        spin_unlock_irq(&priv->driver_lock);
+
+       lbs_deb_leave(LBS_DEB_NET);
        return 0;
 }
 
@@ -468,10 +483,9 @@ static void lbs_tx_timeout(struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       if (priv->currenttxskb) {
-               priv->eventcause = 0x01000000;
-               lbs_send_tx_feedback(priv);
-       }
+       if (priv->currenttxskb)
+               lbs_send_tx_feedback(priv, 0);
+
        /* XX: Shouldn't we also call into the hw-specific driver
           to kick it somehow? */
        lbs_host_to_card_done(priv);
@@ -490,6 +504,8 @@ void lbs_host_to_card_done(struct lbs_private *priv)
 {
        unsigned long flags;
 
+       lbs_deb_enter(LBS_DEB_THREAD);
+
        spin_lock_irqsave(&priv->driver_lock, flags);
 
        priv->dnld_sent = DNLD_RES_RECEIVED;
@@ -499,6 +515,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
                wake_up_interruptible(&priv->waitq);
 
        spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbs_deb_leave(LBS_DEB_THREAD);
 }
 EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
 
@@ -512,6 +529,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 {
        struct lbs_private *priv = (struct lbs_private *) dev->priv;
 
+       lbs_deb_enter(LBS_DEB_NET);
        return &priv->stats;
 }
 
@@ -520,34 +538,27 @@ static int lbs_set_mac_address(struct net_device *dev, void *addr)
        int ret = 0;
        struct lbs_private *priv = (struct lbs_private *) dev->priv;
        struct sockaddr *phwaddr = addr;
+       struct cmd_ds_802_11_mac_address cmd;
 
        lbs_deb_enter(LBS_DEB_NET);
 
        /* In case it was called from the mesh device */
-       dev = priv->dev ;
-
-       memset(priv->current_addr, 0, ETH_ALEN);
-
-       /* dev->dev_addr is 8 bytes */
-       lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
-
-       lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
-       memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
+       dev = priv->dev;
 
-       ret = lbs_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
-                                   CMD_ACT_SET,
-                                   CMD_OPTION_WAITFORRSP, 0, NULL);
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
 
+       ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
        if (ret) {
                lbs_deb_net("set MAC address failed\n");
-               ret = -1;
                goto done;
        }
 
-       lbs_deb_hex(LBS_DEB_NET, "priv->macaddr", priv->current_addr, ETH_ALEN);
-       memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+       memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
+       memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
        if (priv->mesh_dev)
-               memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
+               memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
 
 done:
        lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -564,53 +575,51 @@ static int lbs_copy_multicast_address(struct lbs_private *priv,
                memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
                mcptr = mcptr->next;
        }
-
        return i;
-
 }
 
 static void lbs_set_multicast_list(struct net_device *dev)
 {
        struct lbs_private *priv = dev->priv;
-       int oldpacketfilter;
+       int old_mac_control;
        DECLARE_MAC_BUF(mac);
 
        lbs_deb_enter(LBS_DEB_NET);
 
-       oldpacketfilter = priv->currentpacketfilter;
+       old_mac_control = priv->mac_control;
 
        if (dev->flags & IFF_PROMISC) {
                lbs_deb_net("enable promiscuous mode\n");
-               priv->currentpacketfilter |=
+               priv->mac_control |=
                    CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-               priv->currentpacketfilter &=
+               priv->mac_control &=
                    ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
                      CMD_ACT_MAC_MULTICAST_ENABLE);
        } else {
                /* Multicast */
-               priv->currentpacketfilter &=
+               priv->mac_control &=
                    ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
 
                if (dev->flags & IFF_ALLMULTI || dev->mc_count >
                    MRVDRV_MAX_MULTICAST_LIST_SIZE) {
                        lbs_deb_net( "enabling all multicast\n");
-                       priv->currentpacketfilter |=
+                       priv->mac_control |=
                            CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-                       priv->currentpacketfilter &=
+                       priv->mac_control &=
                            ~CMD_ACT_MAC_MULTICAST_ENABLE;
                } else {
-                       priv->currentpacketfilter &=
+                       priv->mac_control &=
                            ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
 
                        if (!dev->mc_count) {
                                lbs_deb_net("no multicast addresses, "
                                       "disabling multicast\n");
-                               priv->currentpacketfilter &=
+                               priv->mac_control &=
                                    ~CMD_ACT_MAC_MULTICAST_ENABLE;
                        } else {
                                int i;
 
-                               priv->currentpacketfilter |=
+                               priv->mac_control |=
                                    CMD_ACT_MAC_MULTICAST_ENABLE;
 
                                priv->nr_of_multicastmacaddr =
@@ -620,7 +629,7 @@ static void lbs_set_multicast_list(struct net_device *dev)
                                       dev->mc_count);
 
                                for (i = 0; i < dev->mc_count; i++) {
-                                       lbs_deb_net("Multicast address %d:%s\n",
+                                       lbs_deb_net("Multicast address %d: %s\n",
                                               i, print_mac(mac,
                                               priv->multicastlist[i]));
                                }
@@ -633,9 +642,8 @@ static void lbs_set_multicast_list(struct net_device *dev)
                }
        }
 
-       if (priv->currentpacketfilter != oldpacketfilter) {
-               lbs_set_mac_packet_filter(priv);
-       }
+       if (priv->mac_control != old_mac_control)
+               lbs_set_mac_control(priv);
 
        lbs_deb_leave(LBS_DEB_NET);
 }
@@ -653,7 +661,6 @@ static int lbs_thread(void *data)
        struct net_device *dev = data;
        struct lbs_private *priv = dev->priv;
        wait_queue_t wait;
-       u8 ireg = 0;
 
        lbs_deb_enter(LBS_DEB_THREAD);
 
@@ -661,9 +668,10 @@ static int lbs_thread(void *data)
 
        for (;;) {
                int shouldsleep;
+               u8 resp_idx;
 
-               lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
-                               priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+               lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
+                               priv->currenttxskb, priv->dnld_sent);
 
                add_wait_queue(&priv->waitq, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
@@ -675,8 +683,6 @@ static int lbs_thread(void *data)
                        shouldsleep = 1;        /* We need to wait until we're _told_ to die */
                else if (priv->psstate == PS_STATE_SLEEP)
                        shouldsleep = 1;        /* Sleep mode. Nothing we can do till it wakes */
-               else if (priv->intcounter)
-                       shouldsleep = 0;        /* Interrupt pending. Deal with it now */
                else if (priv->cmd_timed_out)
                        shouldsleep = 0;        /* Command timed out. Recover */
                else if (!priv->fw_ready)
@@ -689,29 +695,34 @@ static int lbs_thread(void *data)
                        shouldsleep = 1;        /* Can't send a command; one already running */
                else if (!list_empty(&priv->cmdpendingq))
                        shouldsleep = 0;        /* We have a command to send */
+               else if (__kfifo_len(priv->event_fifo))
+                       shouldsleep = 0;        /* We have an event to process */
+               else if (priv->resp_len[priv->resp_idx])
+                       shouldsleep = 0;        /* We have a command response */
                else
                        shouldsleep = 1;        /* No command */
 
                if (shouldsleep) {
-                       lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
-                                      priv->connect_status, priv->intcounter,
-                                      priv->psmode, priv->psstate);
+                       lbs_deb_thread("sleeping, connect_status %d, "
+                               "ps_mode %d, ps_state %d\n",
+                               priv->connect_status,
+                               priv->psmode, priv->psstate);
                        spin_unlock_irq(&priv->driver_lock);
                        schedule();
                } else
                        spin_unlock_irq(&priv->driver_lock);
 
-               lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n",
-                              priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+               lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
+                              priv->currenttxskb, priv->dnld_sent);
 
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&priv->waitq, &wait);
 
-               lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
-                              priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+               lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
+                              priv->currenttxskb, priv->dnld_sent);
 
                if (kthread_should_stop()) {
-                       lbs_deb_thread("main-thread: break from main thread\n");
+                       lbs_deb_thread("break from main thread\n");
                        break;
                }
 
@@ -720,35 +731,23 @@ static int lbs_thread(void *data)
                        continue;
                }
 
-               spin_lock_irq(&priv->driver_lock);
-
-               if (priv->intcounter) {
-                       u8 int_status;
+               lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
+                      priv->currenttxskb, priv->dnld_sent);
 
-                       priv->intcounter = 0;
-                       int_status = priv->hw_get_int_status(priv, &ireg);
-
-                       if (int_status) {
-                               lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n");
-                               spin_unlock_irq(&priv->driver_lock);
-                               continue;
-                       }
-                       priv->hisregcpy |= ireg;
-               }
-
-               lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
-                              priv->intcounter, priv->currenttxskb, priv->dnld_sent);
-
-               /* command response? */
-               if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
-                       lbs_deb_thread("main-thread: cmd response ready\n");
-
-                       priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
+               /* Process any pending command response */
+               spin_lock_irq(&priv->driver_lock);
+               resp_idx = priv->resp_idx;
+               if (priv->resp_len[resp_idx]) {
                        spin_unlock_irq(&priv->driver_lock);
-                       lbs_process_rx_command(priv);
+                       lbs_process_command_response(priv,
+                               priv->resp_buf[resp_idx],
+                               priv->resp_len[resp_idx]);
                        spin_lock_irq(&priv->driver_lock);
+                       priv->resp_len[resp_idx] = 0;
                }
+               spin_unlock_irq(&priv->driver_lock);
 
+               /* command timeout stuff */
                if (priv->cmd_timed_out && priv->cur_cmd) {
                        struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
 
@@ -757,8 +756,17 @@ static int lbs_thread(void *data)
                                            le16_to_cpu(cmdnode->cmdbuf->command));
                                lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
                                priv->nr_retries = 0;
+#ifdef CONFIG_OLPC
+                               if (machine_is_olpc()) {
+                                       spin_unlock_irq(&priv->driver_lock);
+                                       printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
+                                       olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
+                                       spin_lock_irq(&priv->driver_lock);
+                               }
+#endif
                        } else {
                                priv->cur_cmd = NULL;
+                               priv->dnld_sent = DNLD_RES_RECEIVED;
                                lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
                                            le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
 
@@ -769,21 +777,18 @@ static int lbs_thread(void *data)
                }
                priv->cmd_timed_out = 0;
 
-               /* Any Card Event */
-               if (priv->hisregcpy & MRVDRV_CARDEVENT) {
-                       lbs_deb_thread("main-thread: Card Event Activity\n");
-
-                       priv->hisregcpy &= ~MRVDRV_CARDEVENT;
+               /* Process hardware events, e.g. card removed, link lost */
+               spin_lock_irq(&priv->driver_lock);
+               while (__kfifo_len(priv->event_fifo)) {
+                       u32 event;
 
-                       if (priv->hw_read_event_cause(priv)) {
-                               lbs_pr_alert("main-thread: hw_read_event_cause failed\n");
-                               spin_unlock_irq(&priv->driver_lock);
-                               continue;
-                       }
-                       spin_unlock_irq(&priv->driver_lock);
-                       lbs_process_event(priv);
-               } else
+                       __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+                               sizeof(event));
                        spin_unlock_irq(&priv->driver_lock);
+                       lbs_process_event(priv, event);
+                       spin_lock_irq(&priv->driver_lock);
+               }
+               spin_unlock_irq(&priv->driver_lock);
 
                if (!priv->fw_ready)
                        continue;
@@ -792,10 +797,12 @@ static int lbs_thread(void *data)
                if (priv->psstate == PS_STATE_PRE_SLEEP &&
                    !priv->dnld_sent && !priv->cur_cmd) {
                        if (priv->connect_status == LBS_CONNECTED) {
-                               lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n",
-                                              priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd);
+                               lbs_deb_thread("pre-sleep, currenttxskb %p, "
+                                       "dnld_sent %d, cur_cmd %p\n",
+                                       priv->currenttxskb, priv->dnld_sent,
+                                       priv->cur_cmd);
 
-                               lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
+                               lbs_ps_confirm_sleep(priv);
                        } else {
                                /* workaround for firmware sending
                                 * deauth/linkloss event immediately
@@ -803,7 +810,8 @@ static int lbs_thread(void *data)
                                 * after firmware fixes it
                                 */
                                priv->psstate = PS_STATE_AWAKE;
-                               lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n");
+                               lbs_pr_alert("ignore PS_SleepConfirm in "
+                                       "non-connected state\n");
                        }
                }
 
@@ -857,22 +865,24 @@ static int lbs_thread(void *data)
 static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
                                struct cmd_header *cmd)
 {
-       lbs_deb_fw("HOST_SLEEP_ACTIVATE succeeded\n");
+       lbs_deb_enter(LBS_DEB_FW);
 
        netif_device_detach(priv->dev);
        if (priv->mesh_dev)
                netif_device_detach(priv->mesh_dev);
 
        priv->fw_ready = 0;
+       lbs_deb_leave(LBS_DEB_FW);
        return 0;
 }
 
-
 int lbs_suspend(struct lbs_private *priv)
 {
        struct cmd_header cmd;
        int ret;
 
+       lbs_deb_enter(LBS_DEB_FW);
+
        if (priv->wol_criteria == 0xffffffff) {
                lbs_pr_info("Suspend attempt without configuring wake params!\n");
                return -EINVAL;
@@ -885,12 +895,15 @@ int lbs_suspend(struct lbs_private *priv)
        if (ret)
                lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
 
+       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(lbs_suspend);
 
 int lbs_resume(struct lbs_private *priv)
 {
+       lbs_deb_enter(LBS_DEB_FW);
+
        priv->fw_ready = 1;
 
        /* Firmware doesn't seem to give us RX packets any more
@@ -902,6 +915,7 @@ int lbs_resume(struct lbs_private *priv)
        if (priv->mesh_dev)
                netif_device_attach(priv->mesh_dev);
 
+       lbs_deb_leave(LBS_DEB_FW);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lbs_resume);
@@ -930,7 +944,7 @@ static int lbs_setup_firmware(struct lbs_private *priv)
                goto done;
        }
 
-       lbs_set_mac_packet_filter(priv);
+       lbs_set_mac_control(priv);
 
        ret = lbs_get_data_rate(priv);
        if (ret < 0) {
@@ -953,6 +967,7 @@ static void command_timer_fn(unsigned long data)
        struct lbs_private *priv = (struct lbs_private *)data;
        unsigned long flags;
 
+       lbs_deb_enter(LBS_DEB_CMD);
        spin_lock_irqsave(&priv->driver_lock, flags);
 
        if (!priv->cur_cmd) {
@@ -964,15 +979,30 @@ static void command_timer_fn(unsigned long data)
 
        priv->cmd_timed_out = 1;
        wake_up_interruptible(&priv->waitq);
- out:
+out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
+static void lbs_sync_channel_worker(struct work_struct *work)
+{
+       struct lbs_private *priv = container_of(work, struct lbs_private,
+               sync_channel);
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+       if (lbs_update_channel(priv))
+               lbs_pr_info("Channel synchronization failed.");
+       lbs_deb_leave(LBS_DEB_MAIN);
 }
 
+
 static int lbs_init_adapter(struct lbs_private *priv)
 {
        size_t bufsize;
        int i, ret = 0;
 
+       lbs_deb_enter(LBS_DEB_MAIN);
+
        /* Allocate buffer to store the BSSID list */
        bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
        priv->networks = kzalloc(bufsize, GFP_KERNEL);
@@ -990,14 +1020,6 @@ static int lbs_init_adapter(struct lbs_private *priv)
                              &priv->network_free_list);
        }
 
-       priv->lbs_ps_confirm_sleep.seqnum = cpu_to_le16(++priv->seqnum);
-       priv->lbs_ps_confirm_sleep.command =
-           cpu_to_le16(CMD_802_11_PS_MODE);
-       priv->lbs_ps_confirm_sleep.size =
-           cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
-       priv->lbs_ps_confirm_sleep.action =
-           cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
-
        memset(priv->current_addr, 0xff, ETH_ALEN);
 
        priv->connect_status = LBS_DISCONNECTED;
@@ -1005,7 +1027,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
        priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
        priv->mode = IW_MODE_INFRA;
        priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-       priv->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+       priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        priv->radioon = RADIO_ON;
        priv->auto_rate = 1;
        priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
@@ -1015,7 +1037,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
        mutex_init(&priv->lock);
 
        setup_timer(&priv->command_timer, command_timer_fn,
-                   (unsigned long)priv);
+               (unsigned long)priv);
 
        INIT_LIST_HEAD(&priv->cmdfreeq);
        INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1026,24 +1048,38 @@ static int lbs_init_adapter(struct lbs_private *priv)
        /* Allocate the command buffers */
        if (lbs_allocate_cmd_buffer(priv)) {
                lbs_pr_err("Out of memory allocating command buffers\n");
-               ret = -1;
+               ret = -ENOMEM;
+               goto out;
+       }
+       priv->resp_idx = 0;
+       priv->resp_len[0] = priv->resp_len[1] = 0;
+
+       /* Create the event FIFO */
+       priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
+       if (IS_ERR(priv->event_fifo)) {
+               lbs_pr_err("Out of memory allocating event FIFO buffer\n");
+               ret = -ENOMEM;
+               goto out;
        }
 
 out:
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+
        return ret;
 }
 
 static void lbs_free_adapter(struct lbs_private *priv)
 {
-       lbs_deb_fw("free command buffer\n");
-       lbs_free_cmd_buffer(priv);
+       lbs_deb_enter(LBS_DEB_MAIN);
 
-       lbs_deb_fw("free command_timer\n");
+       lbs_free_cmd_buffer(priv);
+       if (priv->event_fifo)
+               kfifo_free(priv->event_fifo);
        del_timer(&priv->command_timer);
-
-       lbs_deb_fw("free scan results table\n");
        kfree(priv->networks);
        priv->networks = NULL;
+
+       lbs_deb_leave(LBS_DEB_MAIN);
 }
 
 /**
@@ -1058,7 +1094,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        struct net_device *dev = NULL;
        struct lbs_private *priv = NULL;
 
-       lbs_deb_enter(LBS_DEB_NET);
+       lbs_deb_enter(LBS_DEB_MAIN);
 
        /* Allocate an Ethernet device and register it */
        dev = alloc_etherdev(sizeof(struct lbs_private));
@@ -1084,6 +1120,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        dev->stop = lbs_eth_stop;
        dev->set_mac_address = lbs_set_mac_address;
        dev->tx_timeout = lbs_tx_timeout;
+       dev->do_ioctl = lbs_do_ioctl;
        dev->get_stats = lbs_get_stats;
        dev->watchdog_timeo = 5 * HZ;
        dev->ethtool_ops = &lbs_ethtool_ops;
@@ -1108,7 +1145,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        priv->work_thread = create_singlethread_workqueue("lbs_worker");
        INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
        INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
-       INIT_WORK(&priv->sync_channel, lbs_sync_channel);
+       INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
 
        sprintf(priv->mesh_ssid, "mesh");
        priv->mesh_ssid_len = 4;
@@ -1124,7 +1161,7 @@ err_init_adapter:
        priv = NULL;
 
 done:
-       lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
+       lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
        return priv;
 }
 EXPORT_SYMBOL_GPL(lbs_add_card);
@@ -1192,31 +1229,35 @@ int lbs_start_card(struct lbs_private *priv)
        if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
                lbs_pr_err("cannot register lbs_rtap attribute\n");
 
-       /* Enable mesh, if supported, and work out which TLV it uses.
-          0x100 + 291 is an unofficial value used in 5.110.20.pXX
-          0x100 + 37 is the official value used in 5.110.21.pXX
-          but we check them in that order because 20.pXX doesn't
-          give an error -- it just silently fails. */
-
-       /* 5.110.20.pXX firmware will fail the command if the channel
-          doesn't match the existing channel. But only if the TLV
-          is correct. If the channel is wrong, _BOTH_ versions will
-          give an error to 0x100+291, and allow 0x100+37 to succeed.
-          It's just that 5.110.20.pXX will not have done anything
-          useful */
-
        lbs_update_channel(priv);
-       priv->mesh_tlv = 0x100 + 291;
-       if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
-               priv->mesh_tlv = 0x100 + 37;
-               if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
-                       priv->mesh_tlv = 0;
-       }
-       if (priv->mesh_tlv) {
-               lbs_add_mesh(priv);
 
-               if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
-                       lbs_pr_err("cannot register lbs_mesh attribute\n");
+       /* 5.0.16p0 is known to NOT support any mesh */
+       if (priv->fwrelease > 0x05001000) {
+               /* Enable mesh, if supported, and work out which TLV it uses.
+                  0x100 + 291 is an unofficial value used in 5.110.20.pXX
+                  0x100 + 37 is the official value used in 5.110.21.pXX
+                  but we check them in that order because 20.pXX doesn't
+                  give an error -- it just silently fails. */
+
+               /* 5.110.20.pXX firmware will fail the command if the channel
+                  doesn't match the existing channel. But only if the TLV
+                  is correct. If the channel is wrong, _BOTH_ versions will
+                  give an error to 0x100+291, and allow 0x100+37 to succeed.
+                  It's just that 5.110.20.pXX will not have done anything
+                  useful */
+
+               priv->mesh_tlv = 0x100 + 291;
+               if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
+                       priv->mesh_tlv = 0x100 + 37;
+                       if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
+                               priv->mesh_tlv = 0;
+               }
+               if (priv->mesh_tlv) {
+                       lbs_add_mesh(priv);
+
+                       if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
+                               lbs_pr_err("cannot register lbs_mesh attribute\n");
+               }
        }
 
        lbs_debugfs_init_one(priv, dev);
@@ -1291,6 +1332,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
        mesh_dev->open = lbs_dev_open;
        mesh_dev->hard_start_xmit = lbs_hard_start_xmit;
        mesh_dev->stop = lbs_mesh_stop;
+       mesh_dev->do_ioctl = lbs_do_ioctl;
        mesh_dev->get_stats = lbs_get_stats;
        mesh_dev->set_mac_address = lbs_set_mac_address;
        mesh_dev->ethtool_ops = &lbs_ethtool_ops;
@@ -1327,35 +1369,25 @@ done:
        lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
        return ret;
 }
-EXPORT_SYMBOL_GPL(lbs_add_mesh);
-
 
 static void lbs_remove_mesh(struct lbs_private *priv)
 {
        struct net_device *mesh_dev;
 
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       if (!priv)
-               goto out;
 
        mesh_dev = priv->mesh_dev;
        if (!mesh_dev)
-               goto out;
+               return;
 
+       lbs_deb_enter(LBS_DEB_MESH);
        netif_stop_queue(mesh_dev);
        netif_carrier_off(priv->mesh_dev);
-
        sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
        unregister_netdev(mesh_dev);
-
        priv->mesh_dev = NULL;
        free_netdev(mesh_dev);
-
-out:
-&