]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Fri, 2 Jul 2010 00:34:14 +0000 (17:34 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Jul 2010 00:34:14 +0000 (17:34 -0700)
Conflicts:
drivers/net/wireless/libertas/host.h

111 files changed:
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/at76c50x-usb.h
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/sdio.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_main.c
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c [moved from drivers/net/wireless/iwlwifi/iwl-calib.c with 98% similarity]
drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/libertas/Makefile
drivers/net/wireless/libertas/assoc.c [deleted file]
drivers/net/wireless/libertas/assoc.h [deleted file]
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/cfg.h
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/debugfs.c
drivers/net/wireless/libertas/decl.h
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/ethtool.c
drivers/net/wireless/libertas/host.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/libertas/mesh.h
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/libertas/scan.c [deleted file]
drivers/net/wireless/libertas/scan.h [deleted file]
drivers/net/wireless/libertas/tx.c
drivers/net/wireless/libertas/wext.c [deleted file]
drivers/net/wireless/libertas/wext.h [deleted file]
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
include/linux/eeprom_93cx6.h
include/linux/nl80211.h
include/net/cfg80211.h
include/net/mac80211.h
net/mac80211/Kconfig
net/mac80211/cfg.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ieee80211_i.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_minstrel_ht.h
net/mac80211/rc80211_minstrel_ht_debugfs.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/reg.h
net/wireless/wext-compat.c

index 429b281d40d16f0a3b401a27768b13b2c4d38699..cd8caeab86ea97873521e8c72517b523f9721ff7 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
  * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
  * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
+ * Copyright (c) 2010 Sebastian Smolorz <sesmo@gmx.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -1649,6 +1650,58 @@ exit:
                return NULL;
 }
 
+static int at76_join(struct at76_priv *priv)
+{
+       struct at76_req_join join;
+       int ret;
+
+       memset(&join, 0, sizeof(struct at76_req_join));
+       memcpy(join.essid, priv->essid, priv->essid_size);
+       join.essid_size = priv->essid_size;
+       memcpy(join.bssid, priv->bssid, ETH_ALEN);
+       join.bss_type = INFRASTRUCTURE_MODE;
+       join.channel = priv->channel;
+       join.timeout = cpu_to_le16(2000);
+
+       at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
+       ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
+                                   sizeof(struct at76_req_join));
+
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               return 0;
+       }
+
+       ret = at76_wait_completion(priv, CMD_JOIN);
+       at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
+       if (ret != CMD_STATUS_COMPLETE) {
+               printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               return 0;
+       }
+
+       at76_set_pm_mode(priv);
+
+       return 0;
+}
+
+static void at76_work_join_bssid(struct work_struct *work)
+{
+       struct at76_priv *priv = container_of(work, struct at76_priv,
+                                             work_join_bssid);
+
+       if (priv->device_unplugged)
+               return;
+
+       mutex_lock(&priv->mtx);
+
+       if (is_valid_ether_addr(priv->bssid))
+               at76_join(priv);
+
+       mutex_unlock(&priv->mtx);
+}
+
 static void at76_mac80211_tx_callback(struct urb *urb)
 {
        struct at76_priv *priv = urb->context;
@@ -1686,6 +1739,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct at76_priv *priv = hw->priv;
        struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
        int padding, submit_len, ret;
 
        at76_dbg(DBG_MAC80211, "%s()", __func__);
@@ -1696,6 +1750,21 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return NETDEV_TX_BUSY;
        }
 
+       /* The following code lines are important when the device is going to
+        * authenticate with a new bssid. The driver must send CMD_JOIN before
+        * an authentication frame is transmitted. For this to succeed, the
+        * correct bssid of the AP must be known. As mac80211 does not inform
+        * drivers about the bssid prior to the authentication process the
+        * following workaround is necessary. If the TX frame is an
+        * authentication frame extract the bssid and send the CMD_JOIN. */
+       if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) {
+               if (compare_ether_addr(priv->bssid, mgmt->bssid)) {
+                       memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
+                       ieee80211_queue_work(hw, &priv->work_join_bssid);
+                       return NETDEV_TX_BUSY;
+               }
+       }
+
        ieee80211_stop_queues(hw);
 
        at76_ledtrig_tx_activity();     /* tell ledtrigger we send a packet */
@@ -1770,6 +1839,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
        at76_dbg(DBG_MAC80211, "%s()", __func__);
 
        cancel_delayed_work(&priv->dwork_hw_scan);
+       cancel_work_sync(&priv->work_join_bssid);
        cancel_work_sync(&priv->work_set_promisc);
 
        mutex_lock(&priv->mtx);
@@ -1818,42 +1888,6 @@ static void at76_remove_interface(struct ieee80211_hw *hw,
        at76_dbg(DBG_MAC80211, "%s()", __func__);
 }
 
-static int at76_join(struct at76_priv *priv)
-{
-       struct at76_req_join join;
-       int ret;
-
-       memset(&join, 0, sizeof(struct at76_req_join));
-       memcpy(join.essid, priv->essid, priv->essid_size);
-       join.essid_size = priv->essid_size;
-       memcpy(join.bssid, priv->bssid, ETH_ALEN);
-       join.bss_type = INFRASTRUCTURE_MODE;
-       join.channel = priv->channel;
-       join.timeout = cpu_to_le16(2000);
-
-       at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
-       ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
-                                   sizeof(struct at76_req_join));
-
-       if (ret < 0) {
-               printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
-                      wiphy_name(priv->hw->wiphy), ret);
-               return 0;
-       }
-
-       ret = at76_wait_completion(priv, CMD_JOIN);
-       at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
-       if (ret != CMD_STATUS_COMPLETE) {
-               printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",
-                      wiphy_name(priv->hw->wiphy), ret);
-               return 0;
-       }
-
-       at76_set_pm_mode(priv);
-
-       return 0;
-}
-
 static void at76_dwork_hw_scan(struct work_struct *work)
 {
        struct at76_priv *priv = container_of(work, struct at76_priv,
@@ -2107,6 +2141,7 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
        mutex_init(&priv->mtx);
        INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
        INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
+       INIT_WORK(&priv->work_join_bssid, at76_work_join_bssid);
        INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);
 
        tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);
@@ -2508,5 +2543,6 @@ MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
 MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
 MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
 MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
+MODULE_AUTHOR("Sebastian Smolorz <sesmo@gmx.net>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
index 972ea0fc1a0b3ec3740b0f75edd452d8e5705005..4a37447dfc01e14e4a97210c9c0500b4a31dad16 100644 (file)
@@ -387,6 +387,7 @@ struct at76_priv {
        /* work queues */
        struct work_struct work_set_promisc;
        struct work_struct work_submit_rx;
+       struct work_struct work_join_bssid;
        struct delayed_work dwork_hw_scan;
 
        struct tasklet_struct rx_tasklet;
index 73c4fcd142bb5ca6aa0ce450fe25b9917ac0cab0..6284c389ba18ba6480b65dbf61c17e1f9f4632e0 100644 (file)
@@ -1768,7 +1768,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
 
        if (enable) {
                AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART,
-                               AR5K_PHY_RESTART_DIV_GC, 1);
+                               AR5K_PHY_RESTART_DIV_GC, 4);
 
                AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV,
                                        AR5K_PHY_FAST_ANT_DIV_EN);
index 82c3ab756cd09ed9b45bc55113cb78085b8a91df..064168909108005531e90e9ea657f51a43866794 100644 (file)
@@ -295,6 +295,26 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
                /* Several PCIe massages to ensure proper behaviour */
                if (ah->config.pcie_waen)
                        REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
+               else
+                       REG_WRITE(ah, AR_WA, ah->WARegVal);
+       }
+
+       /*
+        * Configire PCIE after Ini init. SERDES values now come from ini file
+        * This enables PCIe low power mode.
+        */
+       if (ah->config.pcieSerDesWrite) {
+               unsigned int i;
+               struct ar5416IniArray *array;
+
+               array = power_off ? &ah->iniPcieSerdes :
+                                   &ah->iniPcieSerdesLowPower;
+
+               for (i = 0; i < array->ia_rows; i++) {
+                       REG_WRITE(ah,
+                                 INI_RA(array, i, 0),
+                                 INI_RA(array, i, 1));
+               }
        }
 }
 
index 8d163ae4255ee58814de2484878e9f8a6c46795f..72d5e52abb8f38f112ccfdef4933291fd339e70e 100644 (file)
@@ -226,6 +226,7 @@ struct ath_buf_state {
        int bfs_retries;
        u8 bf_type;
        u8 bfs_paprd;
+       unsigned long bfs_paprd_timestamp;
        u32 bfs_keyix;
        enum ath9k_key_type bfs_keytype;
 };
@@ -425,6 +426,8 @@ int ath_beaconq_config(struct ath_softc *sc);
 #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
+#define ATH_PAPRD_TIMEOUT      100 /* msecs */
+
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 
@@ -516,6 +519,7 @@ void ath_deinit_leds(struct ath_softc *sc);
 #define SC_OP_TSF_RESET              BIT(11)
 #define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
 #define SC_OP_BT_SCAN               BIT(13)
+#define SC_OP_ANI_RUN               BIT(14)
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -559,7 +563,6 @@ struct ath_softc {
        struct mutex mutex;
        struct work_struct paprd_work;
        struct completion paprd_complete;
-       int paprd_txok;
 
        u32 intrstatus;
        u32 sc_flags; /* SC_OP_* */
@@ -628,6 +631,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 
 extern struct ieee80211_ops ath9k_ops;
 extern int modparam_nohwcrypt;
+extern int led_blink;
 
 irqreturn_t ath_isr(int irq, void *dev);
 int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
index 0ee75e79fe35a38f9e0aa4c72c3570922fb17bf7..3a8ee999da5dc111414b6aebf284930dff75cae9 100644 (file)
@@ -76,7 +76,8 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
        case LED_FULL:
                if (led->led_type == ATH_LED_ASSOC) {
                        sc->sc_flags |= SC_OP_LED_ASSOCIATED;
-                       ieee80211_queue_delayed_work(sc->hw,
+                       if (led_blink)
+                               ieee80211_queue_delayed_work(sc->hw,
                                                     &sc->ath_led_blink_work, 0);
                } else if (led->led_type == ATH_LED_RADIO) {
                        ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
@@ -143,7 +144,8 @@ void ath_init_leds(struct ath_softc *sc)
        /* LED off, active low */
        ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
-       INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
+       if (led_blink)
+               INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
 
        trigger = ieee80211_get_radio_led_name(sc->hw);
        snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
@@ -180,7 +182,8 @@ void ath_init_leds(struct ath_softc *sc)
        return;
 
 fail:
-       cancel_delayed_work_sync(&sc->ath_led_blink_work);
+       if (led_blink)
+               cancel_delayed_work_sync(&sc->ath_led_blink_work);
        ath_deinit_leds(sc);
 }
 
index 5f3ea7091ae085240b64ae519d2c2534c9bda15e..ad9134bddd1e67a248201a7c4ad52013819fec64 100644 (file)
 
 #include "htc.h"
 
+/* identify firmware images */
+#define FIRMWARE_AR7010                "ar7010.fw"
+#define FIRMWARE_AR7010_1_1    "ar7010_1_1.fw"
+#define FIRMWARE_AR9271                "ar9271.fw"
+
+MODULE_FIRMWARE(FIRMWARE_AR7010);
+MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
+MODULE_FIRMWARE(FIRMWARE_AR9271);
+
 static struct usb_device_id ath9k_hif_usb_ids[] = {
-       { USB_DEVICE(0x0cf3, 0x9271) },
-       { USB_DEVICE(0x0cf3, 0x1006) },
-       { USB_DEVICE(0x0cf3, 0x7010) },
+       { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
+       { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */
+       { USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */
+       { USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */
+       { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */
+       { USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */
+       { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
+       { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
+       { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
+       { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
+       { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
        { },
 };
 
@@ -879,17 +896,15 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
        /* Find out which firmware to load */
 
        switch(hif_dev->device_id) {
-       case 0x9271:
-       case 0x1006:
-               hif_dev->fw_name = "ar9271.fw";
-               break;
        case 0x7010:
+       case 0x9018:
                if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
-                       hif_dev->fw_name = "ar7010_1_1.fw";
+                       hif_dev->fw_name = FIRMWARE_AR7010_1_1;
                else
-                       hif_dev->fw_name = "ar7010.fw";
+                       hif_dev->fw_name = FIRMWARE_AR7010;
                break;
        default:
+               hif_dev->fw_name = FIRMWARE_AR9271;
                break;
        }
 
index 58f52a1dc7eaf738ca64a3f7c7c8a25659355654..3756400e6bf95658903a1675cd85efd65d4222c4 100644 (file)
@@ -287,6 +287,7 @@ struct ath9k_debug {
 #define ATH_LED_PIN_DEF             1
 #define ATH_LED_PIN_9287            8
 #define ATH_LED_PIN_9271            15
+#define ATH_LED_PIN_7010            12
 #define ATH_LED_ON_DURATION_IDLE    350        /* in msecs */
 #define ATH_LED_OFF_DURATION_IDLE   250        /* in msecs */
 
index a63ae88abf3e8e102955a7e3674140339dee5f55..148b43317fdb1d6b78502ff42d208b197be28c33 100644 (file)
@@ -244,17 +244,12 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
         */
 
        switch(devid) {
-       case 0x9271:
-       case 0x1006:
-               priv->htc->credits = 33;
-               break;
        case 0x7010:
+       case 0x9018:
                priv->htc->credits = 45;
                break;
        default:
-               dev_err(priv->dev, "ath9k_htc: Unsupported device id: 0x%x\n",
-                       devid);
-               goto err;
+               priv->htc->credits = 33;
        }
 
        ret = htc_init(priv->htc);
index 05445d8a9818111c03de6295fce43b0789cdb556..e38ca66db849c0b185aefd347af17507d2d040f7 100644 (file)
@@ -931,6 +931,8 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
                priv->ah->led_pin = ATH_LED_PIN_9287;
        else if (AR_SREV_9271(priv->ah))
                priv->ah->led_pin = ATH_LED_PIN_9271;
+       else if (AR_DEVID_7010(priv->ah))
+               priv->ah->led_pin = ATH_LED_PIN_7010;
        else
                priv->ah->led_pin = ATH_LED_PIN_DEF;
 
index 62597f4ca319f552ee15dbbe0fbf260f2695a90d..3ed5c9ec7bc18a02420a004edd16924e6aedbea0 100644 (file)
@@ -388,6 +388,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
                ah->config.ht_enable = 0;
 
        ah->config.rx_intr_mitigation = true;
+       ah->config.pcieSerDesWrite = true;
 
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -571,24 +572,13 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        ath9k_hw_init_mode_regs(ah);
 
        /*
-        * Configire PCIE after Ini init. SERDES values now come from ini file
-        * This enables PCIe low power mode.
+        * Read back AR_WA into a permanent copy and set bits 14 and 17.
+        * We need to do this to avoid RMW of this register. We cannot
+        * read the reg when chip is asleep.
         */
-       if (AR_SREV_9300_20_OR_LATER(ah)) {
-               u32 regval;
-               unsigned int i;
-
-               /* Set Bits 16 and 17 in the AR_WA register. */
-               regval = REG_READ(ah, AR_WA);
-               regval |= 0x00030000;
-               REG_WRITE(ah, AR_WA, regval);
-
-               for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) {
-                       REG_WRITE(ah,
-                                 INI_RA(&ah->iniPcieSerdesLowPower, i, 0),
-                                 INI_RA(&ah->iniPcieSerdesLowPower, i, 1));
-               }
-       }
+       ah->WARegVal = REG_READ(ah, AR_WA);
+       ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
+                        AR_WA_ASPM_TIMER_BASED_DISABLE);
 
        if (ah->is_pciexpress)
                ath9k_hw_configpcipowersave(ah, 0, 0);
@@ -1009,6 +999,11 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 
        ENABLE_REGWRITE_BUFFER(ah);
 
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_WA, ah->WARegVal);
+               udelay(10);
+       }
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1063,6 +1058,11 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 {
        ENABLE_REGWRITE_BUFFER(ah);
 
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_WA, ah->WARegVal);
+               udelay(10);
+       }
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1070,6 +1070,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
                REG_WRITE(ah, AR_RC, AR_RC_AHB);
 
        REG_WRITE(ah, AR_RTC_RESET, 0);
+       udelay(2);
 
        REGWRITE_BUFFER_FLUSH(ah);
        DISABLE_REGWRITE_BUFFER(ah);
@@ -1099,6 +1100,11 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_WA, ah->WARegVal);
+               udelay(10);
+       }
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE,
                  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1262,7 +1268,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
 
        /* For chips on which RTC reset is done, save TSF before it gets cleared */
-       if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+       if (AR_SREV_9100(ah) ||
+           (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
                tsf = ath9k_hw_gettsf64(ah);
 
        saveLedState = REG_READ(ah, AR_CFG_LED) &
@@ -1294,7 +1301,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        }
 
        /* Restore TSF */
-       if (tsf && AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+       if (tsf)
                ath9k_hw_settsf64(ah, tsf);
 
        if (AR_SREV_9280_10_OR_LATER(ah))
@@ -1307,6 +1314,17 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (r)
                return r;
 
+       /*
+        * Some AR91xx SoC devices frequently fail to accept TSF writes
+        * right after the chip reset. When that happens, write a new
+        * value after the initvals have been applied, with an offset
+        * based on measured time difference
+        */
+       if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
+               tsf += 1500;
+               ath9k_hw_settsf64(ah, tsf);
+       }
+
        /* Setup MFP options for CCMP */
        if (AR_SREV_9280_20_OR_LATER(ah)) {
                /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
@@ -1492,7 +1510,7 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
 }
 EXPORT_SYMBOL(ath9k_hw_keyreset);
 
-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
+static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
 {
        u32 macHi, macLo;
        u32 unicast_flag = AR_KEYTABLE_VALID;
@@ -1530,7 +1548,6 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
 
        return true;
 }
-EXPORT_SYMBOL(ath9k_hw_keysetmac);
 
 bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                                 const struct ath9k_keyval *k,
@@ -1731,17 +1748,6 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
 }
 EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
 
-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
-{
-       if (entry < ah->caps.keycache_size) {
-               u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
-               if (val & AR_KEYTABLE_VALID)
-                       return true;
-       }
-       return false;
-}
-EXPORT_SYMBOL(ath9k_hw_keyisvalid);
-
 /******************************/
 /* Power Management (Chipset) */
 /******************************/
@@ -1768,6 +1774,11 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
                        REG_CLR_BIT(ah, (AR_RTC_RESET),
                                    AR_RTC_RESET_EN);
        }
+
+       /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               REG_WRITE(ah, AR_WA,
+                         ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 /*
@@ -1794,6 +1805,10 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
                                    AR_RTC_FORCE_WAKE_EN);
                }
        }
+
+       /* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
@@ -1801,6 +1816,12 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
        u32 val;
        int i;
 
+       /* Set Bits 14 and 17 of AR_WA before powering on the chip. */
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_WA, ah->WARegVal);
+               udelay(10);
+       }
+
        if (setChip) {
                if ((REG_READ(ah, AR_RTC_STATUS) &
                     AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
@@ -2155,6 +2176,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 
        if (AR_SREV_9271(ah))
                pCap->num_gpio_pins = AR9271_NUM_GPIO;
+       else if (AR_DEVID_7010(ah))
+               pCap->num_gpio_pins = AR7010_NUM_GPIO;
        else if (AR_SREV_9285_10_OR_LATER(ah))
                pCap->num_gpio_pins = AR9285_NUM_GPIO;
        else if (AR_SREV_9280_10_OR_LATER(ah))
@@ -2295,8 +2318,15 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
 
        BUG_ON(gpio >= ah->caps.num_gpio_pins);
 
-       gpio_shift = gpio << 1;
+       if (AR_DEVID_7010(ah)) {
+               gpio_shift = gpio;
+               REG_RMW(ah, AR7010_GPIO_OE,
+                       (AR7010_GPIO_OE_AS_INPUT << gpio_shift),
+                       (AR7010_GPIO_OE_MASK << gpio_shift));
+               return;
+       }
 
+       gpio_shift = gpio << 1;
        REG_RMW(ah,
                AR_GPIO_OE_OUT,
                (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
@@ -2312,7 +2342,11 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
        if (gpio >= ah->caps.num_gpio_pins)
                return 0xffffffff;
 
-       if (AR_SREV_9300_20_OR_LATER(ah))
+       if (AR_DEVID_7010(ah)) {
+               u32 val;
+               val = REG_READ(ah, AR7010_GPIO_IN);
+               return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
+       } else if (AR_SREV_9300_20_OR_LATER(ah))
                return MS_REG_READ(AR9300, gpio) != 0;
        else if (AR_SREV_9271(ah))
                return MS_REG_READ(AR9271, gpio) != 0;
@@ -2332,10 +2366,16 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
 {
        u32 gpio_shift;
 
-       ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
+       if (AR_DEVID_7010(ah)) {
+               gpio_shift = gpio;
+               REG_RMW(ah, AR7010_GPIO_OE,
+                       (AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),
+                       (AR7010_GPIO_OE_MASK << gpio_shift));
+               return;
+       }
 
+       ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
        gpio_shift = 2 * gpio;
-
        REG_RMW(ah,
                AR_GPIO_OE_OUT,
                (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
@@ -2345,6 +2385,13 @@ EXPORT_SYMBOL(ath9k_hw_cfg_output);
 
 void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 {
+       if (AR_DEVID_7010(ah)) {
+               val = val ? 0 : 1;
+               REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),
+                       AR_GPIO_BIT(gpio));
+               return;
+       }
+
        if (AR_SREV_9271(ah))
                val = ~val;
 
index 5ecbfcf7470af6f8082d0bcc065719bed4f71fc7..bb99e2e1f943dedc5ab5eb9e3ee0b6a514574e5d 100644 (file)
@@ -235,6 +235,7 @@ struct ath9k_ops_config {
        int ack_6mb;
        u32 cwm_ignore_extcca;
        u8 pcie_powersave_enable;
+       bool pcieSerDesWrite;
        u8 pcie_clock_req;
        u32 pcie_waen;
        u8 analog_shiftreg;
@@ -819,6 +820,12 @@ struct ath_hw {
 
        u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
        u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
+       /*
+        * Store the permanent value of Reg 0x4004in WARegVal
+        * so we dont have to R/M/W. We should not be reading
+        * this register when in sleep states.
+        */
+       u32 WARegVal;
 };
 
 static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -852,11 +859,9 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
 
 /* Key Cache Management */
 bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);
 bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                                 const struct ath9k_keyval *k,
                                 const u8 *mac);
-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);
 
 /* GPIO / RFKILL / Antennae */
 void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
index 514a4014c1981e8b62dc7721f66d6bccf74029b3..8700e3dc53cf7b98a94e0918de2699cd10b362dd 100644 (file)
@@ -33,6 +33,10 @@ int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
 
+int led_blink = 1;
+module_param_named(blink, led_blink, int, 0444);
+MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
 /* We use the hw_value as an index into our private channel structure */
 
 #define CHAN2G(_freq, _idx)  { \
index c8de50fa6378d5f4321f81dfe7055b793234ced2..efbf53534ade3172eb0e1243782386b604dc2c90 100644 (file)
@@ -268,7 +268,6 @@ void ath_paprd_calibrate(struct work_struct *work)
        int time_left;
        int i;
 
-       ath9k_ps_wakeup(sc);
        skb = alloc_skb(len, GFP_KERNEL);
        if (!skb)
                return;
@@ -289,6 +288,7 @@ void ath_paprd_calibrate(struct work_struct *work)
        qnum = sc->tx.hwq_map[WME_AC_BE];
        txctl.txq = &sc->tx.txq[qnum];
 
+       ath9k_ps_wakeup(sc);
        ar9003_paprd_init_table(ah);
        for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
                if (!(ah->caps.tx_chainmask & BIT(chain)))
@@ -310,13 +310,13 @@ void ath_paprd_calibrate(struct work_struct *work)
                        break;
 
                time_left = wait_for_completion_timeout(&sc->paprd_complete,
-                                                       100);
+                               msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
                if (!time_left) {
                        ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
                                  "Timeout waiting for paprd training on "
                                  "TX chain %d\n",
                                  chain);
-                       break;
+                       goto fail_paprd;
                }
 
                if (!ar9003_paprd_is_done(ah))
@@ -334,6 +334,7 @@ void ath_paprd_calibrate(struct work_struct *work)
                ath_paprd_activate(sc);
        }
 
+fail_paprd:
        ath9k_ps_restore(sc);
 }
 
@@ -451,6 +452,10 @@ static void ath_start_ani(struct ath_common *common)
 {
        struct ath_hw *ah = common->ah;
        unsigned long timestamp = jiffies_to_msecs(jiffies);
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+       if (!(sc->sc_flags & SC_OP_ANI_RUN))
+               return;
 
        common->ani.longcal_timer = timestamp;
        common->ani.shortcal_timer = timestamp;
@@ -766,11 +771,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
                /* Reset rssi stats */
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
+               sc->sc_flags |= SC_OP_ANI_RUN;
                ath_start_ani(common);
        } else {
                ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
                common->curaid = 0;
                /* Stop ANI */
+               sc->sc_flags &= ~SC_OP_ANI_RUN;
                del_timer_sync(&common->ani.timer);
        }
 }
@@ -1241,7 +1248,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        aphy->state = ATH_WIPHY_INACTIVE;
 
-       cancel_delayed_work_sync(&sc->ath_led_blink_work);
+       if (led_blink)
+               cancel_delayed_work_sync(&sc->ath_led_blink_work);
+
        cancel_delayed_work_sync(&sc->tx_complete_work);
        cancel_work_sync(&sc->paprd_work);
 
@@ -1374,8 +1383,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 
        if (vif->type == NL80211_IFTYPE_AP    ||
            vif->type == NL80211_IFTYPE_ADHOC ||
-           vif->type == NL80211_IFTYPE_MONITOR)
+           vif->type == NL80211_IFTYPE_MONITOR) {
+               sc->sc_flags |= SC_OP_ANI_RUN;
                ath_start_ani(common);
+       }
 
 out:
        mutex_unlock(&sc->mutex);
@@ -1396,6 +1407,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
        mutex_lock(&sc->mutex);
 
        /* Stop ANI */
+       sc->sc_flags &= ~SC_OP_ANI_RUN;
        del_timer_sync(&common->ani.timer);
 
        /* Reclaim beacon resources */
index 3e3ccef438dbecba654a803ce85c794c863e882c..633e3d949ec09f172fab67d797ab449a557ae4f1 100644 (file)
 #define AR_WA_BIT7                     (1 << 7)
 #define AR_WA_BIT23                    (1 << 23)
 #define AR_WA_D3_L1_DISABLE            (1 << 14)
+#define AR_WA_D3_TO_L1_DISABLE_REAL     (1 << 16)
+#define AR_WA_ASPM_TIMER_BASED_DISABLE  (1 << 17)
+#define AR_WA_RESET_EN                  (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
+#define AR_WA_ANALOG_SHIFT              (1 << 20)
+#define AR_WA_POR_SHORT                 (1 << 21) /* PCI-E Phy reset control */
 #define AR9285_WA_DEFAULT              0x004a050b
 #define AR9280_WA_DEFAULT              0x0040073b
 #define AR_WA_DEFAULT                  0x0000073f
 #define AR_SREV_9271_11(_ah) \
     (AR_SREV_9271(_ah) && \
      ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+
 #define AR_SREV_9300(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
 #define AR_SREV_9300_20(_ah) \
     (AR_SREV_9285_12_OR_LATER(_ah) && \
      ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
 
+#define AR_DEVID_7010(_ah) \
+       (((_ah)->hw_version.devid == 0x7010) || \
+        ((_ah)->hw_version.devid == 0x9018))
+
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
 #define AR_RAD2133_SREV_MAJOR                 0xd0
@@ -988,6 +998,7 @@ enum {
 #define AR9287_NUM_GPIO                          11
 #define AR9271_NUM_GPIO                          16
 #define AR9300_NUM_GPIO                          17
+#define AR7010_NUM_GPIO                          16
 
 #define AR_GPIO_IN_OUT                           0x4048
 #define AR_GPIO_IN_VAL                           0x0FFFC000
@@ -1002,6 +1013,8 @@ enum {
 #define AR9271_GPIO_IN_VAL_S                     16
 #define AR9300_GPIO_IN_VAL                       0x0001FFFF
 #define AR9300_GPIO_IN_VAL_S                     0
+#define AR7010_GPIO_IN_VAL                       0x0000FFFF
+#define AR7010_GPIO_IN_VAL_S                     0
 
 #define AR_GPIO_OE_OUT                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
 #define AR_GPIO_OE_OUT_DRV                       0x3
@@ -1010,6 +1023,21 @@ enum {
 #define AR_GPIO_OE_OUT_DRV_HI                    0x2
 #define AR_GPIO_OE_OUT_DRV_ALL                   0x3
 
+#define AR7010_GPIO_OE                           0x52000
+#define AR7010_GPIO_OE_MASK                      0x1
+#define AR7010_GPIO_OE_AS_OUTPUT                 0x0
+#define AR7010_GPIO_OE_AS_INPUT                  0x1
+#define AR7010_GPIO_IN                           0x52004
+#define AR7010_GPIO_OUT                          0x52008
+#define AR7010_GPIO_SET                          0x5200C
+#define AR7010_GPIO_CLEAR                        0x52010
+#define AR7010_GPIO_INT                          0x52014
+#define AR7010_GPIO_INT_TYPE                     0x52018
+#define AR7010_GPIO_INT_POLARITY                 0x5201C
+#define AR7010_GPIO_PENDING                      0x52020
+#define AR7010_GPIO_INT_MASK                     0x52024
+#define AR7010_GPIO_FUNCTION                     0x52028
+
 #define AR_GPIO_INTR_POL                         (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)
 #define AR_GPIO_INTR_POL_VAL                     0x0001FFFF
 #define AR_GPIO_INTR_POL_VAL_S                   0
index 20221b8c04fd886ea3556a609bda5494800ba2df..c3681a1dc94116c32aa5e7bbc575f0cdc8bad0de 100644 (file)
@@ -328,6 +328,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        u32 ba[WME_BA_BMP_SIZE >> 5];
        int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
        bool rc_update = true;
+       struct ieee80211_tx_rate rates[4];
 
        skb = bf->bf_mpdu;
        hdr = (struct ieee80211_hdr *)skb->data;
@@ -335,6 +336,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        tx_info = IEEE80211_SKB_CB(skb);
        hw = bf->aphy->hw;
 
+       memcpy(rates, tx_info->control.rates, sizeof(rates));
+
        rcu_read_lock();
 
        /* XXX: use ieee80211_find_sta! */
@@ -375,6 +378,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                txfail = txpending = 0;
                bf_next = bf->bf_next;
 
+               skb = bf->bf_mpdu;
+               tx_info = IEEE80211_SKB_CB(skb);
+
                if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
                        /* transmit completion, subframe is
                         * acked by block ack */
@@ -428,6 +434,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        spin_unlock_bh(&txq->axq_lock);
 
                        if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
+                               memcpy(tx_info->control.rates, rates, sizeof(rates));
                                ath_tx_rc_status(bf, ts, nbad, txok, true);
                                rc_update = false;
                        } else {
@@ -1644,6 +1651,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
        }
 
        bf->bf_state.bfs_paprd = txctl->paprd;
+       if (txctl->paprd)
+               bf->bf_state.bfs_paprd_timestamp = jiffies;
        bf->bf_flags = setup_tx_flags(skb, use_ldpc);
 
        bf->bf_keytype = get_hw_crypto_keytype(skb);
@@ -1944,8 +1953,12 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
        dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
 
        if (bf->bf_state.bfs_paprd) {
-               sc->paprd_txok = txok;
-               complete(&sc->paprd_complete);
+               if (time_after(jiffies,
+                              bf->bf_state.bfs_paprd_timestamp +
+                              msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
+                       dev_kfree_skb_any(skb);
+               else
+                       complete(&sc->paprd_complete);
        } else {
                ath_tx_complete(sc, skb, bf->aphy, tx_flags);
                ath_debug_stat_tx(sc, txq, bf, ts);
@@ -2027,7 +2040,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
                tx_info->status.rates[i].idx = -1;
        }
 
-       tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
+       tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
 }
 
 static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
@@ -2138,7 +2151,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                         * This frame is sent out as a single frame.
                         * Use hardware retry status for this frame.
                         */
-                       bf->bf_retries = ts.ts_longretry;
                        if (ts.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
                        ath_tx_rc_status(bf, &ts, 0, txok, true);
@@ -2268,7 +2280,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
                }
 
                if (!bf_isampdu(bf)) {
-                       bf->bf_retries = txs.ts_longretry;
                        if (txs.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
                        ath_tx_rc_status(bf, &txs, 0, txok, true);
index 7965b70efbab5de2d1149eda5eba68f0bd871a9b..8e243798ae9342163aabe18cde7beeafda9305a6 100644 (file)
@@ -1804,7 +1804,7 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
                               dma_reason[2], dma_reason[3],
                               dma_reason[4], dma_reason[5]);
                        b43err(dev->wl, "This device does not support DMA "
-                              "on your system. Please use PIO instead.\n");
+                              "on your system. It will now be switched to PIO.\n");
                        /* Fall back to PIO transfers if we get fatal DMA errors! */
                        dev->use_pio = 1;
                        b43_controller_restart(dev, "DMA error");
index 4e56b7bbcebd0b46c4a56c7822713b62be29446b..45933cf8e8c2297e67728992ebab8891d03b8f16 100644 (file)
@@ -182,6 +182,7 @@ static void b43_sdio_remove(struct sdio_func *func)
 
 static const struct sdio_device_id b43_sdio_ids[] = {
        { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
+       { SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */
        { },
 };
 
index 231dbd77f5f5b31669116799ceeab36467b79963..9cadaa296faccaf7f847a919701c38c51d0cbf7c 100644 (file)
@@ -688,7 +688,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
        struct ap_data *ap = data;
        struct net_device *dev = ap->local->dev;
        struct ieee80211_hdr *hdr;
-       u16 fc, status;
+       u16 status;
        __le16 *pos;
        struct sta_info *sta = NULL;
        char *txt = NULL;
@@ -699,7 +699,6 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
        }
 
        hdr = (struct ieee80211_hdr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_control);
        if ((!ieee80211_is_assoc_resp(hdr->frame_control) &&
             !ieee80211_is_reassoc_resp(hdr->frame_control)) ||
            skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
index eb57d1ea361f73738ee22451e29e6b799a82db81..eaee84b55887b7306491151b2cd0db163158dfb1 100644 (file)
@@ -741,9 +741,7 @@ void hostap_set_multicast_list_queue(struct work_struct *work)
        local_info_t *local =
                container_of(work, local_info_t, set_multicast_list_queue);
        struct net_device *dev = local->dev;
-       struct hostap_interface *iface;
 
-       iface = netdev_priv(dev);
        if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
                            local->is_promisc)) {
                printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
index 7c7235385513b8464c22aca463f76ab549bb9b25..728bb858ba9760cefc0367618cf262d42fb529ee 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_IWLWIFI)  += iwlcore.o
 iwlcore-objs           := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
-iwlcore-objs           += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
+iwlcore-objs           += iwl-rx.o iwl-tx.o iwl-sta.o
 iwlcore-objs           += iwl-scan.o iwl-led.o
 iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
@@ -11,7 +11,7 @@ CFLAGS_iwl-devtrace.o := -I$(src)
 obj-$(CONFIG_IWLAGN)   += iwlagn.o
 iwlagn-objs            := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
 iwlagn-objs            += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
-iwlagn-objs            += iwl-agn-lib.o
+iwlagn-objs            += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
 
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
index dba91e0233b64df8b1cdd02640add02e9a0d0878..1daf159914ad028202a78c1b81d26b4d180afbc0 100644 (file)
@@ -157,6 +157,8 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
                        BIT(IWL_CALIB_TX_IQ)            |
                        BIT(IWL_CALIB_TX_IQ_PERD)       |
                        BIT(IWL_CALIB_BASE_BAND);
+       if (priv->cfg->need_dc_calib)
+               priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
 
        priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
@@ -215,6 +217,7 @@ static struct iwl_lib_ops iwl1000_lib = {
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
+       .update_bcast_station = iwl_update_bcast_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
index 93d513e14186eaf12b4851a3499b0a8826e58689..a07310fefcf2d0e56c45d45fabce4251d26e12fc 100644 (file)
@@ -406,6 +406,11 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
        unsigned int plcp_msec;
        unsigned long plcp_received_jiffies;
 
+       if (priv->cfg->plcp_delta_threshold ==
+           IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+               IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+               return rc;
+       }
        memcpy(&current_stat, pkt->u.raw, sizeof(struct
                        iwl3945_notif_statistics));
        /*
index 83e6a42ca2da9d085082802435b9571c532169c6..1dd3bc4c107ef44134b46ca66a0aa8285b8fd731 100644 (file)
@@ -1580,7 +1580,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
        u32 R4;
 
        if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
-               (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
+           (priv->_agn.statistics.flag &
+                       STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
                IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n");
                R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
                R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
@@ -1604,8 +1605,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
        if (!test_bit(STATUS_TEMPERATURE, &priv->status))
                vt = sign_extend(R4, 23);
        else
-               vt = sign_extend(
-                       le32_to_cpu(priv->statistics.general.temperature), 23);
+               vt = sign_extend(le32_to_cpu(
+                               priv->_agn.statistics.general.temperature), 23);
 
        IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt);
 
@@ -1785,6 +1786,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 {
        unsigned long flags;
        u16 ra_tid;
+       int ret;
 
        if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
            (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
@@ -1800,7 +1802,9 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        ra_tid = BUILD_RAxTID(sta_id, tid);
 
        /* Modify device's station table to Tx this TID */
-       iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+       ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+       if (ret)
+               return ret;
 
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -2276,6 +2280,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
        .manage_ibss_station = iwlagn_manage_ibss_station,
+       .update_bcast_station = iwl_update_bcast_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
index 32710a801cb08698615f2a320861cbcb18940d0b..b8f3e20f2c80d1ff89438bcac71100723f1b73a9 100644 (file)
@@ -249,10 +249,11 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
        /* Set initial calibration set */
        priv->hw_params.sens = &iwl5150_sensitivity;
        priv->hw_params.calib_init_cfg =
-               BIT(IWL_CALIB_DC)               |
                BIT(IWL_CALIB_LO)               |
                BIT(IWL_CALIB_TX_IQ)            |
                BIT(IWL_CALIB_BASE_BAND);
+       if (priv->cfg->need_dc_calib)
+               priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
 
        priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
@@ -264,7 +265,7 @@ static void iwl5150_temperature(struct iwl_priv *priv)
        u32 vt = 0;
        s32 offset =  iwl_temp_calib_to_offset(priv);
 
-       vt = le32_to_cpu(priv->statistics.general.temperature);
+       vt = le32_to_cpu(priv->_agn.statistics.general.temperature);
        vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
        /* now vt hold the temperature in Kelvin */
        priv->temperature = KELVIN_TO_CELSIUS(vt);
@@ -392,6 +393,7 @@ static struct iwl_lib_ops iwl5000_lib = {
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
+       .update_bcast_station = iwl_update_bcast_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -454,6 +456,7 @@ static struct iwl_lib_ops iwl5150_lib = {
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
+       .update_bcast_station = iwl_update_bcast_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -660,6 +663,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
@@ -689,6 +693,7 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
index afdeec56b13fceeb77c2d82e08165b3c1c9f6861..8577664da77c410e11cd5afc01570c6cfc156c13 100644 (file)
@@ -84,9 +84,10 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 }
 
 /* Indicate calibration version to uCode. */
-static void iwl6050_set_calib_version(struct iwl_priv *priv)
+static void iwl6000_set_calib_version(struct iwl_priv *priv)
 {
-       if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+       if (priv->cfg->need_dc_calib &&
+           (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6))
                iwl_set_bit(priv, CSR_GP_DRIVER_REG,
                                CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
 }
@@ -186,53 +187,8 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
                BIT(IWL_CALIB_LO)               |
                BIT(IWL_CALIB_TX_IQ)            |
                BIT(IWL_CALIB_BASE_BAND);
-
-       priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
-       return 0;
-}
-
-static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
-{
-       if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
-               priv->cfg->num_of_queues =
-                       priv->cfg->mod_params->num_of_queues;
-
-       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
-       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
-       priv->hw_params.scd_bc_tbls_size =
-                       priv->cfg->num_of_queues *
-                       sizeof(struct iwlagn_scd_bc_tbl);
-       priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
-       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
-
-       priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
-       priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
-
-       priv->hw_params.max_bsm_size = 0;
-       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-                                       BIT(IEEE80211_BAND_5GHZ);
-       priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
-
-       priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
-       priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
-       priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
-       priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
-
-       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
-               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
-
-       /* Set initial sensitivity parameters */
-       /* Set initial calibration set */
-       priv->hw_params.sens = &iwl6000_sensitivity;
-       priv->hw_params.calib_init_cfg =
-               BIT(IWL_CALIB_XTAL)             |
-               BIT(IWL_CALIB_DC)               |
-               BIT(IWL_CALIB_LO)               |
-               BIT(IWL_CALIB_TX_IQ)            |
-               BIT(IWL_CALIB_BASE_BAND);
+       if (priv->cfg->need_dc_calib)
+               priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
 
        priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
@@ -359,8 +315,10 @@ static struct iwl_lib_ops iwl6000_lib = {
        .temp_ops = {
                .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
+               .set_calib_version = iwl6000_set_calib_version,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
+       .update_bcast_station = iwl_update_bcast_station,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -397,79 +355,6 @@ static const struct iwl_ops iwl6000g2b_ops = {
        .led = &iwlagn_led_ops,
 };
 
-static struct iwl_lib_ops iwl6050_lib = {
-       .set_hw_params = iwl6050_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_agg_enable = iwlagn_txq_agg_enable,
-       .txq_agg_disable = iwlagn_txq_agg_disable,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwlagn_rx_handler_setup,
-       .setup_deferred_work = iwlagn_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .load_ucode = iwlagn_load_ucode,
-       .dump_nic_event_log = iwl_dump_nic_event_log,
-       .dump_nic_error_log = iwl_dump_nic_error_log,
-       .dump_csr = iwl_dump_csr,
-       .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwlagn_init_alive_start,
-       .alive_notify = iwlagn_alive_notify,
-       .send_tx_power = iwlagn_send_tx_power,
-       .update_chain_flags = iwl_update_chain_flags,
-       .set_channel_switch = iwl6000_hw_channel_switch,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .stop = iwl_apm_stop,
-               .config = iwl6000_nic_config,
-               .set_pwr_src = iwl_set_pwr_src,
-       },
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REG_BAND_52_HT40_CHANNELS
-               },
-               .verify_signature  = iwlcore_eeprom_verify_signature,
-               .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-               .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwlagn_eeprom_calib_version,
-               .query_addr = iwlagn_eeprom_query_addr,
-               .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
-       },
-       .post_associate = iwl_post_associate,
-       .isr = iwl_isr_ict,
-       .config_ap = iwl_config_ap,
-       .temp_ops = {
-               .temperature = iwlagn_temperature,
-               .set_ct_kill = iwl6000_set_ct_threshold,
-               .set_calib_version = iwl6050_set_calib_version,
-        },
-       .manage_ibss_station = iwlagn_manage_ibss_station,
-       .debugfs_ops = {
-               .rx_stats_read = iwl_ucode_rx_stats_read,
-               .tx_stats_read = iwl_ucode_tx_stats_read,
-               .general_stats_read = iwl_ucode_general_stats_read,
-       },
-       .recover_from_tx_stall = iwl_bg_monitor_recover,
-       .check_plcp_health = iwl_good_plcp_health,
-       .check_ack_health = iwl_good_ack_health,
-};
-
-static const struct iwl_ops iwl6050_ops = {
-       .lib = &iwl6050_lib,
-       .hcmd = &iwlagn_hcmd,
-       .utils = &iwlagn_hcmd_utils,
-       .led = &iwlagn_led_ops,
-};
-
-
 struct iwl_cfg iwl6000g2a_2agn_cfg = {
        .name = "6000 Series 2x2 AGN Gen2a",
        .fw_name_pre = IWL6000G2A_FW_PRE,
@@ -505,6 +390,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2a_2abg_cfg = {
@@ -537,6 +423,9 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2a_2bg_cfg = {
@@ -569,6 +458,9 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2b_2agn_cfg = {
@@ -603,6 +495,9 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2b_2abg_cfg = {
@@ -635,6 +530,9 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2b_2bgn_cfg = {
@@ -669,6 +567,9 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2b_2bg_cfg = {
@@ -701,6 +602,9 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2b_bgn_cfg = {
@@ -735,6 +639,9 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000g2b_bg_cfg = {
@@ -767,6 +674,9 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
        .max_event_log_size = 512,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 /*
@@ -885,7 +795,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl6050_ops,
+       .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -914,6 +824,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -922,7 +833,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
-       .ops = &iwl6050_ops,
+       .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -949,6 +860,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+       .need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
similarity index 98%
rename from drivers/net/wireless/iwlwifi/iwl-calib.c
rename to drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 22fa947e8756e5752888e3d8c7d492d6a5ea780e..eb052b05e790498da4062a3ed17fb030ae18fff8 100644 (file)
@@ -96,17 +96,16 @@ int iwl_send_calib_results(struct iwl_priv *priv)
                        hcmd.len = priv->calib_results[i].buf_len;
                        hcmd.data = priv->calib_results[i].buf;
                        ret = iwl_send_cmd_sync(priv, &hcmd);
-                       if (ret)
-                               goto err;
+                       if (ret) {
+                               IWL_ERR(priv, "Error %d iteration %d\n",
+                                       ret, i);
+                               break;
+                       }
                }
        }
 
-       return 0;
-err:
-       IWL_ERR(priv, "Error %d iteration %d\n", ret, i);
        return ret;
 }
-EXPORT_SYMBOL(iwl_send_calib_results);
 
 int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
 {
@@ -121,7 +120,6 @@ int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
        memcpy(res->buf, buf, len);
        return 0;
 }
-EXPORT_SYMBOL(iwl_calib_set);
 
 void iwl_calib_free_results(struct iwl_priv *priv)
 {
@@ -133,7 +131,6 @@ void iwl_calib_free_results(struct iwl_priv *priv)
                priv->calib_results[i].buf_len = 0;
        }
 }
-EXPORT_SYMBOL(iwl_calib_free_results);
 
 /*****************************************************************************
  * RUNTIME calibrations framework
@@ -533,7 +530,6 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
        ret |= iwl_sensitivity_write(priv);
        IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
 }
-EXPORT_SYMBOL(iwl_init_sensitivity);
 
 void iwl_sensitivity_calibration(struct iwl_priv *priv,
                                    struct iwl_notif_statistics *resp)
@@ -639,7 +635,6 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
        iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
        iwl_sensitivity_write(priv);
 }
-EXPORT_SYMBOL(iwl_sensitivity_calibration);
 
 static inline u8 find_first_chain(u8 mask)
 {
@@ -848,10 +843,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
 
        if (active_chains != priv->hw_params.valid_rx_ant &&
            active_chains != priv->chain_noise_data.active_chains)
-               IWL_WARN(priv,
-                        "Detected that not all antennas are connected! "
-                        "Connected: %#x, valid: %#x.\n",
-                        active_chains, priv->hw_params.valid_rx_ant);
+               IWL_DEBUG_CALIB(priv,
+                               "Detected that not all antennas are connected! "
+                               "Connected: %#x, valid: %#x.\n",
+                               active_chains, priv->hw_params.valid_rx_ant);
 
        /* Save for use within RXON, TX, SCAN commands, etc. */
        priv->chain_noise_data.active_chains = active_chains;
@@ -897,8 +892,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
        data->state = IWL_CHAIN_NOISE_DONE;
        iwl_power_update_mode(priv, false);
 }
-EXPORT_SYMBOL(iwl_chain_noise_calibration);
-
 
 void iwl_reset_run_time_calib(struct iwl_priv *priv)
 {
@@ -915,5 +908,3 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv)
         * periodically after association */
        iwl_send_statistics_request(priv, CMD_ASYNC, true);
 }
-EXPORT_SYMBOL(iwl_reset_run_time_calib);
-
index 3d08dc8af1432f532d924a9630825b375905682f..75d6bfcbc60770fe0a3f73f23018c7167ac12a94 100644 (file)
@@ -33,17 +33,17 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
        int p = 0;
 
        p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
-                      le32_to_cpu(priv->statistics.flag));
-       if (le32_to_cpu(priv->statistics.flag) &
+                      le32_to_cpu(priv->_agn.statistics.flag));
+       if (le32_to_cpu(priv->_agn.statistics.flag) &
                        UCODE_STATISTICS_CLEAR_MSK)
                p += scnprintf(buf + p, bufsz - p,
                               "\tStatistics have been cleared\n");
        p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
-                      (le32_to_cpu(priv->statistics.flag) &
+                      (le32_to_cpu(priv->_agn.statistics.flag) &
                        UCODE_STATISTICS_FREQUENCY_MSK)
                        ? "2.4 GHz" : "5.2 GHz");
        p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
-                      (le32_to_cpu(priv->statistics.flag) &
+                      (le32_to_cpu(priv->_agn.statistics.flag) &
                        UCODE_STATISTICS_NARROW_BAND_MSK)
                        ? "enabled" : "disabled");
        return p;
@@ -79,22 +79,22 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
         * the last statistics notification from uCode
         * might not reflect the current uCode activity
         */
-       ofdm = &priv->statistics.rx.ofdm;
-       cck = &priv->statistics.rx.cck;
-       general = &priv->statistics.rx.general;
-       ht = &priv->statistics.rx.ofdm_ht;
-       accum_ofdm = &priv->accum_statistics.rx.ofdm;
-       accum_cck = &priv->accum_statistics.rx.cck;
-       accum_general = &priv->accum_statistics.rx.general;
-       accum_ht = &priv->accum_statistics.rx.ofdm_ht;
-       delta_ofdm = &priv->delta_statistics.rx.ofdm;
-       delta_cck = &priv->delta_statistics.rx.cck;
-       delta_general = &priv->delta_statistics.rx.general;
-       delta_ht = &priv->delta_statistics.rx.ofdm_ht;
-       max_ofdm = &priv->max_delta.rx.ofdm;
-       max_cck = &priv->max_delta.rx.cck;
-       max_general = &priv->max_delta.rx.general;
-       max_ht = &priv->max_delta.rx.ofdm_ht;
+       ofdm = &priv->_agn.statistics.rx.ofdm;
+       cck = &priv->_agn.statistics.rx.cck;
+       general = &priv->_agn.statistics.rx.general;
+       ht = &priv->_agn.statistics.rx.ofdm_ht;
+       accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm;
+       accum_cck = &priv->_agn.accum_statistics.rx.cck;
+       accum_general = &priv->_agn.accum_statistics.rx.general;
+       accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht;
+       delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm;
+       delta_cck = &priv->_agn.delta_statistics.rx.cck;
+       delta_general = &priv->_agn.delta_statistics.rx.general;
+       delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht;
+       max_ofdm = &priv->_agn.max_delta.rx.ofdm;
+       max_cck = &priv->_agn.max_delta.rx.cck;
+       max_general = &priv->_agn.max_delta.rx.general;
+       max_ht = &priv->_agn.max_delta.rx.ofdm_ht;
 
        pos += iwl_statistics_flag(priv, buf, bufsz);
        pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
@@ -560,10 +560,10 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
          * the last statistics notification from uCode
          * might not reflect the current uCode activity
          */
-       tx = &priv->statistics.tx;
-       accum_tx = &priv->accum_statistics.tx;
-       delta_tx = &priv->delta_statistics.tx;
-       max_tx = &priv->max_delta.tx;
+       tx = &priv->_agn.statistics.tx;
+       accum_tx = &priv->_agn.accum_statistics.tx;
+       delta_tx = &priv->_agn.delta_statistics.tx;
+       max_tx = &priv->_agn.max_delta.tx;
        pos += iwl_statistics_flag(priv, buf, bufsz);
        pos += scnprintf(buf + pos, bufsz - pos,  "%-32s     current"
                         "acumulative       delta         max\n",
@@ -777,18 +777,18 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
          * the last statistics notification from uCode
          * might not reflect the current uCode activity
          */
-       general = &priv->statistics.general;
-       dbg = &priv->statistics.general.dbg;
-       div = &priv->statistics.general.div;
-       accum_general = &priv->accum_statistics.general;
-       delta_general = &priv->delta_statistics.general;
-       max_general = &priv->max_delta.general;
-       accum_dbg = &priv->accum_statistics.general.dbg;
-       delta_dbg = &priv->delta_statistics.general.dbg;
-       max_dbg = &priv->max_delta.general.dbg;
-       accum_div = &priv->accum_statistics.general.div;
-       delta_div = &priv->delta_statistics.general.div;
-       max_div = &priv->max_delta.general.div;
+       general = &priv->_agn.statistics.general;
+       dbg = &priv->_agn.statistics.general.dbg;
+       div = &priv->_agn.statistics.general.div;
+       accum_general = &priv->_agn.accum_statistics.general;
+       delta_general = &priv->_agn.delta_statistics.general;
+       max_general = &priv->_agn.max_delta.general;
+       accum_dbg = &priv->_agn.accum_statistics.general.dbg;
+       delta_dbg = &priv->_agn.delta_statistics.general.dbg;
+       max_dbg = &priv->_agn.max_delta.general.dbg;
+       accum_div = &priv->_agn.accum_statistics.general.div;
+       delta_div = &priv->_agn.delta_statistics.general.div;
+       max_div = &priv->_agn.max_delta.general.div;
        pos += iwl_statistics_flag(priv, buf, bufsz);
        pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
                         "acumulative       delta         max\n",
index 3f765ba15cb8d78b4d24cda1cd689540bdbfd8a3..f06d1feedf81a574237d886551bb1c6db9b6f99e 100644 (file)
@@ -214,11 +214,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
 static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
                        __le32 *tx_flags)
 {
-       if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
-           (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
-               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
-       else
-               *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
+       *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
index 0e7b0661d61d4a1ecd7c8d54c10c42327b06b266..5f1e7d802cbf576afcd8f3e008572e9fac506561 100644 (file)
@@ -361,7 +361,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
 void iwlagn_temperature(struct iwl_priv *priv)
 {
        /* store temperature from statistics (in Celsius) */
-       priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+       priv->temperature =
+               le32_to_cpu(priv->_agn.statistics.general.temperature);
        iwl_tt_handler(priv);
 }
 
index 40933a5de027e4d0f8850f3f41450cd89bc6a515..35c86d22b14bc67e33748854b02a80719315fb9e 100644 (file)
@@ -324,18 +324,11 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
                              struct iwl_lq_sta *lq_data,
                              struct ieee80211_sta *sta)
 {
-       if ((tid < TID_MAX_LOAD_COUNT) &&
-           !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) {
-               if (priv->cfg->use_rts_for_ht) {
-                       /*
-                        * switch to RTS/CTS if it is the prefer protection
-                        * method for HT traffic
-                        */
-                       IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
-                       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
-                       iwlcore_commit_rxon(priv);
-               }
-       }
+       if (tid < TID_MAX_LOAD_COUNT)
+               rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+       else
+               IWL_ERR(priv, "tid exceeds max load count: %d/%d\n",
+                       tid, TID_MAX_LOAD_COUNT);
 }
 
 static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
new file mode 100644 (file)
index 0000000..d54edc3
--- /dev/null
@@ -0,0 +1,284 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-calib.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_missed_beacon_notif *missed_beacon;
+
+       missed_beacon = &pkt->u.missed_beacon;
+       if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
+           priv->missed_beacon_threshold) {
+               IWL_DEBUG_CALIB(priv,
+                   "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+                   le32_to_cpu(missed_beacon->consecutive_missed_beacons),
+                   le32_to_cpu(missed_beacon->total_missed_becons),
+                   le32_to_cpu(missed_beacon->num_recvd_beacons),
+                   le32_to_cpu(missed_beacon->num_expected_beacons));
+               if (!test_bit(STATUS_SCANNING, &priv->status))
+                       iwl_init_sensitivity(priv);
+       }
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ *   before arriving beacon.  This measurement can be done only if we know
+ *   exactly when to expect beacons, therefore only when we're associated. */
+static void iwl_rx_calc_noise(struct iwl_priv *priv)
+{
+       struct statistics_rx_non_phy *rx_info
+                               = &(priv->_agn.statistics.rx.general);
+       int num_active_rx = 0;
+       int total_silence = 0;
+       int bcn_silence_a =
+               le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+       int bcn_silence_b =
+               le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+       int bcn_silence_c =
+               le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+       int last_rx_noise;
+
+       if (bcn_silence_a) {
+               total_silence += bcn_silence_a;
+               num_active_rx++;
+       }
+       if (bcn_silence_b) {
+               total_silence += bcn_silence_b;
+               num_active_rx++;
+       }
+       if (bcn_silence_c) {
+               total_silence += bcn_silence_c;
+               num_active_rx++;
+       }
+
+       /* Average among active antennas */
+       if (num_active_rx)
+               last_rx_noise = (total_silence / num_active_rx) - 107;
+       else
+               last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+       IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
+                       bcn_silence_a, bcn_silence_b, bcn_silence_c,
+                       last_rx_noise);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/*
+ *  based on the assumption of all statistics counter are in DWORD
+ *  FIXME: This function is for debugging, do not deal with
+ *  the case of counters roll-over.
+ */
+static void iwl_accumulative_statistics(struct iwl_priv *priv,
+                                       __le32 *stats)
+{
+       int i;
+       __le32 *prev_stats;
+       u32 *accum_stats;
+       u32 *delta, *max_delta;
+
+       prev_stats = (__le32 *)&priv->_agn.statistics;
+       accum_stats = (u32 *)&priv->_agn.accum_statistics;
+       delta = (u32 *)&priv->_agn.delta_statistics;
+       max_delta = (u32 *)&priv->_agn.max_delta;
+
+       for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
+            i += sizeof(__le32), stats++, prev_stats++, delta++,
+            max_delta++, accum_stats++) {
+               if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+                       *delta = (le32_to_cpu(*stats) -
+                               le32_to_cpu(*prev_stats));
+                       *accum_stats += *delta;
+                       if (*delta > *max_delta)
+                               *max_delta = *delta;
+               }
+       }
+
+       /* reset accumulative statistics for "no-counter" type statistics */
+       priv->_agn.accum_statistics.general.temperature =
+               priv->_agn.statistics.general.temperature;
+       priv->_agn.accum_statistics.general.temperature_m =
+               priv->_agn.statistics.general.temperature_m;
+       priv->_agn.accum_statistics.general.ttl_timestamp =
+               priv->_agn.statistics.general.ttl_timestamp;
+       priv->_agn.accum_statistics.tx.tx_power.ant_a =
+               priv->_agn.statistics.tx.tx_power.ant_a;
+       priv->_agn.accum_statistics.tx.tx_power.ant_b =
+               priv->_agn.statistics.tx.tx_power.ant_b;
+       priv->_agn.accum_statistics.tx.tx_power.ant_c =
+               priv->_agn.statistics.tx.tx_power.ant_c;
+}
+#endif
+
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
+{
+       bool rc = true;
+       int combined_plcp_delta;
+       unsigned int plcp_msec;
+       unsigned long plcp_received_jiffies;
+
+       if (priv->cfg->plcp_delta_threshold ==
+           IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+               IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+               return rc;
+       }
+
+       /*
+        * check for plcp_err and trigger radio reset if it exceeds
+        * the plcp error threshold plcp_delta.
+        */
+       plcp_received_jiffies = jiffies;
+       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+                                       (long) priv->plcp_jiffies);
+       priv->plcp_jiffies = plcp_received_jiffies;
+       /*
+        * check to make sure plcp_msec is not 0 to prevent division
+        * by zero.
+        */
+       if (plcp_msec) {
+               combined_plcp_delta =
+                       (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
+                       le32_to_cpu(priv->_agn.statistics.rx.ofdm.plcp_err)) +
+                       (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
+                       le32_to_cpu(priv->_agn.statistics.rx.ofdm_ht.plcp_err));
+
+               if ((combined_plcp_delta > 0) &&
+                   ((combined_plcp_delta * 100) / plcp_msec) >
+                       priv->cfg->plcp_delta_threshold) {
+                       /*
+                        * if plcp_err exceed the threshold,
+                        * the following data is printed in csv format:
+                        *    Text: plcp_err exceeded %d,
+                        *    Received ofdm.plcp_err,
+                        *    Current ofdm.plcp_err,
+                        *    Received ofdm_ht.plcp_err,
+                        *    Current ofdm_ht.plcp_err,
+                        *    combined_plcp_delta,
+                        *    plcp_msec
+                        */
+                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
+                               "%u, %u, %u, %u, %d, %u mSecs\n",
+                               priv->cfg->plcp_delta_threshold,
+                               le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
+                               le32_to_cpu(
+                                      priv->_agn.statistics.rx.ofdm.plcp_err),
+                               le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
+                               le32_to_cpu(
+                                 priv->_agn.statistics.rx.ofdm_ht.plcp_err),
+                               combined_plcp_delta, plcp_msec);
+                       rc = false;
+               }
+       }
+       return rc;
+}
+
+void iwl_rx_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       int change;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+
+       IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
+                    (int)sizeof(priv->_agn.statistics),
+                    le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+
+       change = ((priv->_agn.statistics.general.temperature !=
+                  pkt->u.stats.general.temperature) ||
+                 ((priv->_agn.statistics.flag &
+                   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+                  (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+#endif
+       iwl_recover_from_statistics(priv, pkt);
+
+       memcpy(&priv->_agn.statistics, &pkt->u.stats,
+              sizeof(priv->_agn.statistics));
+
+       set_bit(STATUS_STATISTICS, &priv->status);
+
+       /* Reschedule the statistics timer to occur in
+        * REG_RECALIB_PERIOD seconds to ensure we get a
+        * thermal update even if the uCode doesn't give
+        * us one */
+       mod_timer(&priv->statistics_periodic, jiffies +
+                 msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+
+       if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+           (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+               iwl_rx_calc_noise(priv);
+               queue_work(priv->workqueue, &priv->run_time_calib_work);
+       }
+       if (priv->cfg->ops->lib->temp_ops.temperature && change)
+               priv->cfg->ops->lib->temp_ops.temperature(priv);
+}
+
+void iwl_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+       if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               memset(&priv->_agn.accum_statistics, 0,
+                       sizeof(struct iwl_notif_statistics));
+               memset(&priv->_agn.delta_statistics, 0,
+                       sizeof(struct iwl_notif_statistics));
+               memset(&priv->_agn.max_delta, 0,
+                       sizeof(struct iwl_notif_statistics));
+#endif
+               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+       }
+       iwl_rx_statistics(priv, rxb);
+}
index 84df7fca750d01552e2d2ca2a2e7d761dc402cb5..2573234e4db10ace47bac8dba2f530905a516410 100644 (file)
@@ -233,6 +233,7 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 {
        unsigned long flags;
        u16 ra_tid;
+       int ret;
 
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
            (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
@@ -248,7 +249,9 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        ra_tid = BUILD_RAxTID(sta_id, tid);
 
        /* Modify device's station table to Tx this TID */
-       iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+       ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+       if (ret)
+               return ret;
 
        spin_lock_irqsave(&priv->lock, flags);
 
index d857f8496f695e75a480aae910411418c1fe1a32..3368cfd25a9989bb304a0324ce9118910ea226e0 100644 (file)
@@ -1461,13 +1461,13 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
 
        actual_ack_cnt_delta =
                le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
-               le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
+               le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt);
        expected_ack_cnt_delta =
                le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
-               le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
+               le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt);
        ba_timeout_delta =
                le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
-               le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
+               le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout);
        if ((priv->_agn.agg_tids_count > 0) &&
            (expected_ack_cnt_delta > 0) &&
            (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
@@ -1484,10 +1484,10 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
                 * DEBUG is not, these will just compile out.
                 */
                IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
-                               priv->delta_statistics.tx.rx_detected_cnt);
+                               priv->_agn.delta_statistics.tx.rx_detected_cnt);
                IWL_DEBUG_RADIO(priv,
                                "ack_or_ba_timeout_collision delta = %d\n",
-                               priv->delta_statistics.tx.
+                               priv->_agn.delta_statistics.tx.
                                ack_or_ba_timeout_collision);
 #endif
                IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
@@ -2310,9 +2310,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
                                      blink1, blink2, ilink1, ilink2);
 
-       IWL_ERR(priv, "Desc                               Time       "
+       IWL_ERR(priv, "Desc                                  Time       "
                "data1      data2      line\n");
-       IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+       IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n",
                desc_lookup(desc), desc, time, data1, data2, line);
        IWL_ERR(priv, "pc      blink1  blink2  ilink1  ilink2  hcmd\n");
        IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
@@ -2935,9 +2935,9 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        }
 
        if (priv->start_calib) {
-               iwl_chain_noise_calibration(priv, &priv->statistics);
+               iwl_chain_noise_calibration(priv, &priv->_agn.statistics);
 
-               iwl_sensitivity_calibration(priv, &priv->statistics);
+               iwl_sensitivity_calibration(priv, &priv->_agn.statistics);
        }
 
        mutex_unlock(&priv->mutex);
@@ -3368,13 +3368,32 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        return ret;
 }
 
+/*
+ * switch to RTS/CTS for TX
+ */
+static void iwl_enable_rts_cts(struct iwl_priv *priv)
+{
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+       if (!test_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n");
+               iwlcore_commit_rxon(priv);
+       } else {
+               /* scanning, defer the request until scan completed */
+               IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n");
+       }
+}
+
 static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
                                enum ieee80211_ampdu_mlme_action action,
                                struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
        struct iwl_priv *priv = hw->priv;
-       int ret;
+       int ret = -EINVAL;
 
        IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
                     sta->addr, tid);
@@ -3382,17 +3401,19 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
        if (!(priv->cfg->sku & IWL_SKU_N))
                return -EACCES;
 
+       mutex_lock(&priv->mutex);
+
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
                IWL_DEBUG_HT(priv, "start Rx\n");
-               return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+               break;
        case IEEE80211_AMPDU_RX_STOP:
                IWL_DEBUG_HT(priv, "stop Rx\n");
                ret = iwl_sta_rx_agg_stop(priv, sta, tid);
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-                       return 0;
-               else
-                       return ret;
+                       ret = 0;
+               break;
        case IEEE80211_AMPDU_TX_START:
                IWL_DEBUG_HT(priv, "start Tx\n");
                ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
@@ -3401,7 +3422,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                        IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
                                     priv->_agn.agg_tids_count);
                }
-               return ret;
+               break;
        case IEEE80211_AMPDU_TX_STOP:
                IWL_DEBUG_HT(priv, "stop Tx\n");
                ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
@@ -3411,18 +3432,22 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                                     priv->_agn.agg_tids_count);
                }
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-                       return 0;
-               else
-                       return ret;
+                       ret = 0;
+               break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
-               /* do nothing */
-               return -EOPNOTSUPP;
-       default:
-               IWL_DEBUG_HT(priv, "unknown\n");
-               return -EINVAL;
+               if (priv->cfg->use_rts_for_ht) {
+                       /*
+                        * switch to RTS/CTS if it is the prefer protection
+                        * method for HT traffic
+                        */
+                       iwl_enable_rts_cts(priv);
+               }
+               ret = 0;
                break;
        }
-       return 0;
+       mutex_unlock(&priv->mutex);
+
+       return ret;
 }
 
 static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
index 5c32777b0a49980bfa3d533d014deb47d3f3b189..be9d298cae2c98b8ae9da8547c16189e8b228b2d 100644 (file)
@@ -201,6 +201,16 @@ static inline bool iwl_is_tx_success(u32 status)
               (status == TX_STATUS_DIRECT_DONE);
 }
 
+/* rx */
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb);
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+                         struct iwl_rx_packet *pkt);
+void iwl_rx_statistics(struct iwl_priv *priv,
+                      struct iwl_rx_mem_buffer *rxb);
+void iwl_reply_statistics(struct iwl_priv *priv,
+                         struct iwl_rx_mem_buffer *rxb);
+
 /* scan */
 void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
 
index 28b1098334f7e805813d0ac87477d3093d8e4a83..acf8e980b1fe242208b3c3901b98e899f1df1703 100644 (file)
@@ -1399,18 +1399,27 @@ struct iwl_rx_mpdu_res_start {
 
 /* REPLY_TX Tx flags field */
 
-/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
+/*
+ * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
  * before this frame. if CTS-to-self required check
- * RXON_FLG_SELF_CTS_EN status. */
-#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0)
+ * RXON_FLG_SELF_CTS_EN status.
+ * unused in 3945/4965, used in 5000 series and after
+ */
+#define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
 
-/* 1: Use Request-To-Send protocol before this frame.
- * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+/*
+ * 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK.
+ * used in 3945/4965, unused in 5000 series and after
+ */
 #define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
 
-/* 1: Transmit Clear-To-Send to self before this frame.
+/*
+ * 1: Transmit Clear-To-Send to self before this frame.
  * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
- * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK.
+ * used in 3945/4965, unused in 5000 series and after
+ */
 #define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
 
 /* 1: Expect ACK from receiving station
@@ -1430,8 +1439,11 @@ struct iwl_rx_mpdu_res_start {
  * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
 #define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
 
-/* 1: Frame requires full Tx-Op protection.
- * Set this if either RTS or CTS Tx Flag gets set. */
+/*
+ * 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set.
+ * used in 3945/4965, unused in 5000 series and after
+ */
 #define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
 
 /* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
index 62c50bc0089a071a6d39104bdd14c00c82c83e9c..a56fb466d0b6437d69de229c85724b74a4e5f507 100644 (file)
@@ -1331,7 +1331,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
                        changed_flags, *total_flags);
 
        CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
-       CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK);
        CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
        CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
 
@@ -1346,6 +1345,12 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
 
        mutex_unlock(&priv->mutex);
 
+       /*
+        * Receiving all multicast frames is always enabled by the
+        * default flags setup in iwl_connection_init_rx_config()
+        * since we currently do not support programming multicast
+        * filters into the device.
+        */
        *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
@@ -2105,6 +2110,9 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
                spin_unlock_irqrestore(&priv->lock, flags);
 
+               if (priv->cfg->ops->lib->update_bcast_station)
+                       ret = priv->cfg->ops->lib->update_bcast_station(priv);
+
  set_ch_out:
                /* The list of supported rates and rate mask can be different
                 * for each band; since the band may have changed, reset
@@ -2837,6 +2845,7 @@ int iwl_pci_resume(struct pci_dev *pdev)
 {
        struct iwl_priv *priv = pci_get_drvdata(pdev);
        int ret;
+       bool hw_rfkill = false;
 
        /*
         * We disable the RETRY_TIMEOUT register (0x41) to keep
@@ -2851,6 +2860,17 @@ int iwl_pci_resume(struct pci_dev *pdev)
        pci_restore_state(pdev);
        iwl_enable_interrupts(priv);
 
+       if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+               hw_rfkill = true;
+
+       if (hw_rfkill)
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
+       else
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+       wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill);
+
        return 0;
 }
 EXPORT_SYMBOL(iwl_pci_resume);
index 76288c56a7d7b3d055f2433a3eaf3c0a4909c8ce..15930e06402247b8ff360ccab61b76e254b1353b 100644 (file)
@@ -196,6 +196,7 @@ struct iwl_lib_ops {
        /* station management */
        int (*manage_ibss_station)(struct iwl_priv *priv,
                                   struct ieee80211_vif *vif, bool add);
+       int (*update_bcast_station)(struct iwl_priv *priv);
        /* recover from tx queue stall */
        void (*recover_from_tx_stall)(unsigned long data);
        /* check for plcp health */
@@ -330,6 +331,7 @@ struct iwl_cfg {
        const bool chain_noise_calib_by_driver;
        u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
        u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
+       const bool need_dc_calib;
 };
 
 /***************************
@@ -455,20 +457,10 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
 void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 /* Handlers */
-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb);
 void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
                                          struct iwl_rx_mem_buffer *rxb);
-bool iwl_good_plcp_health(struct iwl_priv *priv,
-                                struct iwl_rx_packet *pkt);
-bool iwl_good_ack_health(struct iwl_priv *priv,
-                                struct iwl_rx_packet *pkt);
 void iwl_recover_from_statistics(struct iwl_priv *priv,
                                struct iwl_rx_packet *pkt);
-void iwl_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb);
-void iwl_reply_statistics(struct iwl_priv *priv,
-                         struct iwl_rx_mem_buffer *rxb);
 void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 
index cee3d12eb383bfd4b001e749252c0ed69653fe2d..7d9ffc1575de761531f3f1610edfa135e54eb468 100644 (file)
@@ -1430,10 +1430,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
                return -EFAULT;
        if (sscanf(buf, "%d", &plcp) != 1)
                return -EINVAL;
-       if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+       if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
                (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
                priv->cfg->plcp_delta_threshold =
-                       IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
+                       IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
        else
                priv->cfg->plcp_delta_threshold = plcp;
        return count;
index 338b5177029de2867c5bca4bf70a5632fbcca8e8..728752aa1bb528ce46de02518c06f9544b66e949 100644 (file)
@@ -1036,11 +1036,12 @@ struct iwl_event_log {
  * This is the threshold value of plcp error rate per 100mSecs.  It is
  * used to set and check for the validity of plcp_delta.
  */
-#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (1)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50)
 #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF    (100)
 #define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF        (200)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE     (0)
 
 #define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
 #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
@@ -1224,13 +1225,6 @@ struct iwl_priv {
        struct iwl_power_mgr power_data;
        struct iwl_tt_mgmt thermal_throttle;
 
-       struct iwl_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       struct iwl_notif_statistics accum_statistics;
-       struct iwl_notif_statistics delta_statistics;
-       struct iwl_notif_statistics max_delta;
-#endif
-
        /* context information */
        u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
 
@@ -1323,6 +1317,13 @@ struct iwl_priv {
 
                        u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
                        u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+                       struct iwl_notif_statistics statistics;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+                       struct iwl_notif_statistics accum_statistics;
+                       struct iwl_notif_statistics delta_statistics;
+                       struct iwl_notif_statistics max_delta;
+#endif
                } _agn;
 #endif
        };
index ee11452519e6490a52b8176e445e40edede91e27..a45d02e555cfffbcd3d174deb5dbdc4352ff6bef 100644 (file)
@@ -629,6 +629,9 @@ int iwl_eeprom_check_version(struct iwl_priv *priv)
            calib_ver < priv->cfg->eeprom_calib_ver)
                goto err;
 
+       IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+                eeprom_ver, calib_ver);
+
        return 0;
 err:
        IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
index 86a35376579600f446cbd30e488435aae0b1ce4b..b437f317b979066576f2482dd4a58e3cfb2f2425 100644 (file)
@@ -205,26 +205,6 @@ err_bd:
 }
 EXPORT_SYMBOL(iwl_rx_queue_alloc);
 
-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
-
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_missed_beacon_notif *missed_beacon;
-
-       missed_beacon = &pkt->u.missed_beacon;
-       if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
-           priv->missed_beacon_threshold) {
-               IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
-                   le32_to_cpu(missed_beacon->consecutive_missed_beacons),
-                   le32_to_cpu(missed_beacon->total_missed_becons),
-                   le32_to_cpu(missed_beacon->num_recvd_beacons),
-                   le32_to_cpu(missed_beacon->num_expected_beacons));
-               if (!test_bit(STATUS_SCANNING, &priv->status))
-                       iwl_init_sensitivity(priv);
-       }
-}
-EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
 
 void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
                                          struct iwl_rx_mem_buffer *rxb)
@@ -243,161 +223,6 @@ void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);
 
-
-
-/* Calculate noise level, based on measurements during network silence just
- *   before arriving beacon.  This measurement can be done only if we know
- *   exactly when to expect beacons, therefore only when we're associated. */
-static void iwl_rx_calc_noise(struct iwl_priv *priv)
-{
-       struct statistics_rx_non_phy *rx_info
-                               = &(priv->statistics.rx.general);
-       int num_active_rx = 0;
-       int total_silence = 0;
-       int bcn_silence_a =
-               le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
-       int bcn_silence_b =
-               le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
-       int bcn_silence_c =
-               le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
-       int last_rx_noise;
-
-       if (bcn_silence_a) {
-               total_silence += bcn_silence_a;
-               num_active_rx++;
-       }
-       if (bcn_silence_b) {
-               total_silence += bcn_silence_b;
-               num_active_rx++;
-       }
-       if (bcn_silence_c) {
-               total_silence += bcn_silence_c;
-               num_active_rx++;
-       }
-
-       /* Average among active antennas */
-       if (num_active_rx)
-               last_rx_noise = (total_silence / num_active_rx) - 107;
-       else
-               last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-       IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
-                       bcn_silence_a, bcn_silence_b, bcn_silence_c,
-                       last_rx_noise);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-/*
- *  based on the assumption of all statistics counter are in DWORD
- *  FIXME: This function is for debugging, do not deal with
- *  the case of counters roll-over.
- */
-static void iwl_accumulative_statistics(struct iwl_priv *priv,
-                                       __le32 *stats)
-{
-       int i;
-       __le32 *prev_stats;
-       u32 *accum_stats;
-       u32 *delta, *max_delta;
-
-       prev_stats = (__le32 *)&priv->statistics;
-       accum_stats = (u32 *)&priv->accum_statistics;
-       delta = (u32 *)&priv->delta_statistics;
-       max_delta = (u32 *)&priv->max_delta;
-
-       for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
-            i += sizeof(__le32), stats++, prev_stats++, delta++,
-            max_delta++, accum_stats++) {
-               if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
-                       *delta = (le32_to_cpu(*stats) -
-                               le32_to_cpu(*prev_stats));
-                       *accum_stats += *delta;
-                       if (*delta > *max_delta)
-                               *max_delta = *delta;
-               }
-       }
-
-       /* reset accumulative statistics for "no-counter" type statistics */
-       priv->accum_statistics.general.temperature =
-               priv->statistics.general.temperature;
-       priv->accum_statistics.general.temperature_m =
-               priv->statistics.general.temperature_m;
-       priv->accum_statistics.general.ttl_timestamp =
-               priv->statistics.general.ttl_timestamp;
-       priv->accum_statistics.tx.tx_power.ant_a =
-               priv->statistics.tx.tx_power.ant_a;
-       priv->accum_statistics.tx.tx_power.ant_b =
-               priv->statistics.tx.tx_power.ant_b;
-       priv->accum_statistics.tx.tx_power.ant_c =
-               priv->statistics.tx.tx_power.ant_c;
-}
-#endif
-
-#define REG_RECALIB_PERIOD (60)
-
-/**
- * iwl_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-bool iwl_good_plcp_health(struct iwl_priv *priv,
-                               struct iwl_rx_packet *pkt)
-{
-       bool rc = true;
-       int combined_plcp_delta;
-       unsigned int plcp_msec;
-       unsigned long plcp_received_jiffies;
-
-       /*
-        * check for plcp_err and trigger radio reset if it exceeds
-        * the plcp error threshold plcp_delta.
-        */
-       plcp_received_jiffies = jiffies;
-       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
-                                       (long) priv->plcp_jiffies);
-       priv->plcp_jiffies = plcp_received_jiffies;
-       /*
-        * check to make sure plcp_msec is not 0 to prevent division
-        * by zero.
-        */
-       if (plcp_msec) {
-               combined_plcp_delta =
-                       (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
-                       le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
-                       (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
-                       le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
-
-               if ((combined_plcp_delta > 0) &&
-                   ((combined_plcp_delta * 100) / plcp_msec) >
-                       priv->cfg->plcp_delta_threshold) {
-                       /*
-                        * if plcp_err exceed the threshold,
-                        * the following data is printed in csv format:
-                        *    Text: plcp_err exceeded %d,
-                        *    Received ofdm.plcp_err,
-                        *    Current ofdm.plcp_err,
-                        *    Received ofdm_ht.plcp_err,
-                        *    Current ofdm_ht.plcp_err,
-                        *    combined_plcp_delta,
-                        *    plcp_msec
-                        */
-                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
-                               "%u, %u, %u, %u, %d, %u mSecs\n",
-                               priv->cfg->plcp_delta_threshold,
-                               le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
-                               le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
-                               le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
-                               le32_to_cpu(
-                                 priv->statistics.rx.ofdm_ht.plcp_err),
-                               combined_plcp_delta, plcp_msec);
-                       rc = false;
-               }
-       }
-       return rc;
-}
-EXPORT_SYMBOL(iwl_good_plcp_health);
-
 void iwl_recover_from_statistics(struct iwl_priv *priv,
                                struct iwl_rx_packet *pkt)
 {
@@ -431,69 +256,6 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_recover_from_statistics);
 
-void iwl_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
-{
-       int change;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-
-       IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
-                    (int)sizeof(priv->statistics),
-                    le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-
-       change = ((priv->statistics.general.temperature !=
-                  pkt->u.stats.general.temperature) ||
-                 ((priv->statistics.flag &
-                   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-                  (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
-#endif
-       iwl_recover_from_statistics(priv, pkt);
-
-       memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
-
-       set_bit(STATUS_STATISTICS, &priv->status);
-
-       /* Reschedule the statistics timer to occur in
-        * REG_RECALIB_PERIOD seconds to ensure we get a
-        * thermal update even if the uCode doesn't give
-        * us one */
-       mod_timer(&priv->statistics_periodic, jiffies +
-                 msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
-
-       if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
-           (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
-               iwl_rx_calc_noise(priv);
-               queue_work(priv->workqueue, &priv->run_time_calib_work);
-       }
-       if (priv->cfg->ops->lib->temp_ops.temperature && change)
-               priv->cfg->ops->lib->temp_ops.temperature(priv);
-}
-EXPORT_SYMBOL(iwl_rx_statistics);
-
-void iwl_reply_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-       if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               memset(&priv->accum_statistics, 0,
-                       sizeof(struct iwl_notif_statistics));
-               memset(&priv->delta_statistics, 0,
-                       sizeof(struct iwl_notif_statistics));
-               memset(&priv->max_delta, 0,
-                       sizeof(struct iwl_notif_statistics));
-#endif
-               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
-       }
-       iwl_rx_statistics(priv, rxb);
-}
-EXPORT_SYMBOL(iwl_reply_statistics);
-
 /*
  * returns non-zero if packet should be dropped
  */
index 798f93e0ff5028f2bbe2b440c82af2f139a76b06..2a7c399fee1ed95b75f3c49b5a360ffbd2b19130 100644 (file)
@@ -537,6 +537,15 @@ void iwl_bg_scan_completed(struct work_struct *work)
        /* Since setting the TXPOWER may have been deferred while
         * performing the scan, fire one off */
        iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+
+       /*
+        * Since setting the RXON may have been deferred while
+        * performing the scan, fire one off if needed
+        */
+       if (memcmp(&priv->active_rxon,
+                  &priv->staging_rxon, sizeof(priv->staging_rxon)))
+               iwlcore_commit_rxon(priv);
+
  out:
        mutex_unlock(&priv->mutex);
 
index d57df6c02db307110a25e4f968d3107bc7d241b6..9511f03f07e053b93af68c83bd534ddfab98122d 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
+#include <linux/lockdep.h>
 
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -54,18 +55,19 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
        }
 }
 
-static void iwl_process_add_sta_resp(struct iwl_priv *priv,
-                                    struct iwl_addsta_cmd *addsta,
-                                    struct iwl_rx_packet *pkt,
-                                    bool sync)
+static int iwl_process_add_sta_resp(struct iwl_priv *priv,
+                                   struct iwl_addsta_cmd *addsta,
+                                   struct iwl_rx_packet *pkt,
+                                   bool sync)
 {
        u8 sta_id = addsta->sta.sta_id;
        unsigned long flags;
+       int ret = -EIO;
 
        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
                IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
                        pkt->hdr.flags);
-               return;
+               return ret;
        }
 
        IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
@@ -77,6 +79,7 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
        case ADD_STA_SUCCESS_MSK:
                IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
                iwl_sta_ucode_activate(priv, sta_id);
+               ret = 0;
                break;
        case ADD_STA_NO_ROOM_IN_TABLE:
                IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
@@ -114,6 +117,8 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
                       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
                       addsta->sta.addr);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       return ret;
 }
 
 static void iwl_add_sta_callback(struct iwl_priv *priv,
@@ -145,8 +150,10 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 
        if (flags & CMD_ASYNC)
                cmd.callback = iwl_add_sta_callback;
-       else
+       else {
                cmd.flags |= CMD_WANT_SKB;
+               might_sleep();
+       }
 
        cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
        ret = iwl_send_cmd(priv, &cmd);
@@ -156,7 +163,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 
        if (ret == 0) {
                pkt = (struct iwl_rx_packet *)cmd.reply_page;
-               iwl_process_add_sta_resp(priv, sta, pkt, true);
+               ret = iwl_process_add_sta_resp(priv, sta, pkt, true);
        }
        iwl_free_pages(priv, cmd.reply_page);
 
@@ -831,7 +838,9 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
 {
        unsigned long flags;
        __le16 key_flags = 0;
-       int ret;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
 
        keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
 
@@ -871,11 +880,10 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
-       ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       return ret;
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
 static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
@@ -884,7 +892,9 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
 {
        unsigned long flags;
        __le16 key_flags = 0;
-       int ret;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
 
        key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@@ -919,11 +929,10 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
-       ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       return ret;
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@@ -1013,9 +1022,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
                                u8 sta_id)
 {
        unsigned long flags;
-       int ret = 0;
        u16 key_flags;
        u8 keyidx;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
 
        priv->key_mapping_key--;
 
@@ -1062,9 +1073,10 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
                spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
-       ret =  iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
+
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_remove_dynamic_key);
 
@@ -1073,6 +1085,8 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
 {
        int ret;
 
+       lockdep_assert_held(&priv->mutex);
+
        priv->key_mapping_key++;
        keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
@@ -1245,6 +1259,36 @@ int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
 }
 EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
 
+/**
+ * iwl_update_bcast_station - update broadcast station's LQ command
+ *
+ * Only used by iwlagn. Placed here to have all bcast station management
+ * code together.
+ */
+int iwl_update_bcast_station(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       struct iwl_link_quality_cmd *link_cmd;
+       u8 sta_id = priv->hw_params.bcast_sta_id;
+
+       link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+       if (!link_cmd) {
+               IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       if (priv->stations[sta_id].lq)
+               kfree(priv->stations[sta_id].lq);
+       else
+               IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");
+       priv->stations[sta_id].lq = link_cmd;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iwl_update_bcast_station);
+
 void iwl_dealloc_bcast_station(struct iwl_priv *priv)
 {
        unsigned long flags;
@@ -1268,17 +1312,22 @@ EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
 /**
  * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
  */
-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 {
        unsigned long flags;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
 
        /* Remove "disable" flag, to enable Tx for this TID */
        spin_lock_irqsave(&priv->sta_lock, flags);
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
        priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
 
@@ -1287,6 +1336,9 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
 {
        unsigned long flags;
        int sta_id;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
 
        sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION)
@@ -1298,10 +1350,10 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
        priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
        priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-                               CMD_ASYNC);
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_start);
 
@@ -1309,7 +1361,10 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
                        int tid)
 {
        unsigned long flags;
-       int sta_id, ret;
+       int sta_id;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
 
        sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
@@ -1322,11 +1377,10 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
        priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       return ret;
-
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
 
index 5b1b1e461eb62c9606441f984e4c7815812058b8..ba95b1a590a5be5c4657b7adb5aaaa503629c67a 100644 (file)
@@ -60,6 +60,7 @@ void iwl_restore_stations(struct iwl_priv *priv);
 void iwl_clear_ucode_stations(struct iwl_priv *priv);
 int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
 void iwl_dealloc_bcast_station(struct iwl_priv *priv);
+int iwl_update_bcast_station(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags);
@@ -73,7 +74,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
 int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
 int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
                         int tid, u16 ssn);
 int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
index 697fa6caaceb25c81a5e5dfcf39cd424e52fb126..8eb347106902c4d7bf5e603ffd02daaab12f9003 100644 (file)
@@ -1424,7 +1424,7 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
                    iwl_read_targ_mem(priv, base + i + 6 * sizeof(u32));
 
                IWL_ERR(priv,
-                       "%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+                       "%-13s (0x%X) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
                        desc_lookup(desc), desc, time, blink1, blink2,
                        ilink1, ilink2, data1);
                trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0,
index 902e95f70f6e7695445d2a3d23d04316bccea1a8..60619678f4ec1cb39c94dd5b97c3977082c168f3 100644 (file)
@@ -670,20 +670,24 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
-                                   enum tx_power_setting type, int dbm)
+                                   enum nl80211_tx_power_setting type, int mbm)
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
        int ret;
 
        switch (type) {
-       case TX_POWER_AUTOMATIC:
+       case NL80211_TX_POWER_AUTOMATIC:
                return 0;
-       case TX_POWER_FIXED:
+       case NL80211_TX_POWER_FIXED:
+               if (mbm < 0 || (mbm % 100))
+                       return -EOPNOTSUPP;
+
                if (!test_bit(IWM_STATUS_READY, &iwm->status))
                        return 0;
 
                ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
-                                             CFG_TX_PWR_LIMIT_USR, dbm * 2);
+                                             CFG_TX_PWR_LIMIT_USR,
+                                             MBM_TO_DBM(mbm) * 2);
                if (ret < 0)
                        return ret;
 
index 45e870e331175f30d47edc2ed85091bce1a924ed..f7d01bfa2e4a1ccd8046607457b32639037cb7cc 100644 (file)
@@ -1,4 +1,3 @@
-libertas-y += assoc.o
 libertas-y += cfg.o
 libertas-y += cmd.o
 libertas-y += cmdresp.o
@@ -6,9 +5,7 @@ libertas-y += debugfs.o
 libertas-y += ethtool.o
 libertas-y += main.o
 libertas-y += rx.o
-libertas-y += scan.o
 libertas-y += tx.o
-libertas-y += wext.o
 libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
 
 usb8xxx-objs += if_usb.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
deleted file mode 100644 (file)
index aa06070..0000000
+++ /dev/null
@@ -1,2264 +0,0 @@
-/* Copyright (C) 2006, Red Hat, Inc. */
-
-#include <linux/types.h>
-#include <linux/etherdevice.h>
-#include <linux/ieee80211.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <net/lib80211.h>
-
-#include "assoc.h"
-#include "decl.h"
-#include "host.h"
-#include "scan.h"
-#include "cmd.h"
-
-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 the following bits masked out of the beacon-derived
- * capability field when associating/joining to a BSS:
- *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
- */
-#define CAPINFO_MASK   (~(0xda00))
-
-/**
- * 802.11b/g supported bitrates (in 500Kb/s units)
- */
-u8 lbs_bg_rates[MAX_RATES] =
-    { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0x00, 0x00 };
-
-
-static int assoc_helper_wep_keys(struct lbs_private *priv,
-               struct assoc_request *assoc_req);
-
-/**
- *  @brief This function finds common rates between rates and card rates.
- *
- * It will fill common rates in rates 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 rates       the buffer which keeps input and output
- *  @param rates_size  the size of rates buffer; new size of buffer on return,
- *                     which will be less than or equal to original rates_size
- *
- *  @return            0 on success, or -1 on error
- */
-static int get_common_rates(struct lbs_private *priv,
-       u8 *rates,
-       u16 *rates_size)
-{
-       int i, j;
-       u8 intersection[MAX_RATES];
-       u16 intersection_size;
-       u16 num_rates = 0;
-
-       intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
-
-       /* Allow each rate from 'rates' that is supported by the hardware */
-       for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
-               for (j = 0; j < intersection_size && rates[j]; j++) {
-                       if (rates[j] == lbs_bg_rates[i])
-                               intersection[num_rates++] = rates[j];
-               }
-       }
-
-       lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
-       lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", lbs_bg_rates,
-                       ARRAY_SIZE(lbs_bg_rates));
-       lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
-       lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
-
-       if (!priv->enablehwauto) {
-               for (i = 0; i < num_rates; i++) {
-                       if (intersection[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);
-               return -1;
-       }
-
-done:
-       memset(rates, 0, *rates_size);
-       *rates_size = num_rates;
-       memcpy(rates, intersection, num_rates);
-       return 0;
-}
-
-
-/**
- *  @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;
-       }
-}
-
-
-static u8 iw_auth_to_ieee_auth(u8 auth)
-{
-       if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
-               return 0x00;
-       else if (auth == IW_AUTH_ALG_SHARED_KEY)
-               return 0x01;
-       else if (auth == IW_AUTH_ALG_LEAP)
-               return 0x80;
-
-       lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
-       return 0;
-}
-
-/**
- *  @brief This function prepares the authenticate command.  AUTHENTICATE only
- *  sets the authentication suite for future associations, as the firmware
- *  handles authentication internally during the ASSOCIATE command.
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param bssid     The peer BSSID with which to authenticate
- *  @param auth      The authentication mode to use (from wireless.h)
- *
- *  @return         0 or -1
- */
-static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
-{
-       struct cmd_ds_802_11_authenticate cmd;
-       int ret = -1;
-
-       lbs_deb_enter(LBS_DEB_JOIN);
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       memcpy(cmd.bssid, bssid, ETH_ALEN);
-
-       cmd.authtype = iw_auth_to_ieee_auth(auth);
-
-       lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
-
-       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-       return ret;
-}
-
-
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
-                          struct assoc_request *assoc)
-{
-       struct cmd_ds_802_11_set_wep cmd;
-       int ret = 0;
-
-       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));
-
-       cmd.action = cpu_to_le16(cmd_action);
-
-       if (cmd_action == CMD_ACT_ADD) {
-               int i;
-
-               /* default tx key index */
-               cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
-                                          CMD_WEP_KEY_INDEX_MASK);
-
-               /* Copy key types and material to host command structure */
-               for (i = 0; i < 4; i++) {
-                       struct enc_key *pkey = &assoc->wep_keys[i];
-
-                       switch (pkey->len) {
-                       case KEY_LEN_WEP_40:
-                               cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
-                               memmove(cmd.keymaterial[i], pkey->key, pkey->len);
-                               lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
-                               break;
-                       case KEY_LEN_WEP_104:
-                               cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
-                               memmove(cmd.keymaterial[i], pkey->key, pkey->len);
-                               lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
-                               break;
-                       case 0:
-                               break;
-                       default:
-                               lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
-                                           i, pkey->len);
-                               ret = -1;
-                               goto done;
-                               break;
-                       }
-               }
-       } else if (cmd_action == CMD_ACT_REMOVE) {
-               /* ACT_REMOVE clears _all_ WEP keys */
-
-               /* default tx key index */
-               cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
-                                          CMD_WEP_KEY_INDEX_MASK);
-               lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
-       }
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
-                             uint16_t *enable)
-{
-       struct cmd_ds_802_11_enable_rsn cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(cmd_action);
-
-       if (cmd_action == CMD_ACT_GET)
-               cmd.enable = 0;
-       else {
-               if (*enable)
-                       cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
-               else
-                       cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
-               lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
-       }
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
-       if (!ret && cmd_action == CMD_ACT_GET)
-               *enable = le16_to_cpu(cmd.enable);
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
-               struct enc_key *key)
-{
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       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);
-
-       /* Length field doesn't include the {type,length} header */
-       keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
-       lbs_deb_leave(LBS_DEB_CMD);
-}
-
-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 cmd;
-       int ret = 0;
-       int index = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       cmd.action = cpu_to_le16(cmd_action);
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       if (cmd_action == CMD_ACT_GET) {
-               cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
-       } else {
-               memset(cmd.keyParamSet, 0, sizeof(cmd.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_MCAST_KEY, &assoc->flags)) {
-                       set_one_wpa_key(&cmd.keyParamSet[index],
-                                       &assoc->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;
-
-                       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;
-
-                       /* 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;
-               }
-       }
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
-{
-/*             Bit     Rate
-*              15:13 Reserved
-*              12    54 Mbps
-*              11    48 Mbps
-*              10    36 Mbps
-*              9     24 Mbps
-*              8     18 Mbps
-*              7     12 Mbps
-*              6     9 Mbps
-*              5     6 Mbps
-*              4     Reserved
-*              3     11 Mbps
-*              2     5.5 Mbps
-*              1     2 Mbps
-*              0     1 Mbps
-**/
-
-       uint16_t ratemask;
-       int i = lbs_data_rate_to_fw_index(rate);
-       if (lower_rates_ok)
-               ratemask = (0x1fef >> (12 - i));
-       else
-               ratemask = (1 << i);
-       return cpu_to_le16(ratemask);
-}
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
-                                     uint16_t cmd_action)
-{
-       struct cmd_ds_802_11_rate_adapt_rateset cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (!priv->cur_rate && !priv->enablehwauto)
-               return -EINVAL;
-
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       cmd.action = cpu_to_le16(cmd_action);
-       cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
-       cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
-       ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
-       if (!ret && cmd_action == CMD_ACT_GET)
-               priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
-
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Set the data rate
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param rate        The desired data rate, or 0 to clear a locked rate
- *
- *  @return            0 on success, error on failure
- */
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
-{
-       struct cmd_ds_802_11_data_rate cmd;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       if (rate > 0) {
-               cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
-               cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
-               if (cmd.rates[0] == 0) {
-                       lbs_deb_cmd("DATA_RATE: invalid requested rate of"
-                               " 0x%02X\n", rate);
-                       ret = 0;
-                       goto out;
-               }
-               lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
-       } else {
-               cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
-               lbs_deb_cmd("DATA_RATE: setting auto\n");
-       }
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
-       if (ret)
-               goto out;
-
-       lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
-
-       /* FIXME: get actual rates FW can do if this command actually returns
-        * all data rates supported.
-        */
-       priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
-       lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
-
-int lbs_cmd_802_11_rssi(struct lbs_private *priv,
-                               struct cmd_ds_command *cmd)
-{
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->command = cpu_to_le16(CMD_802_11_RSSI);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
-               sizeof(struct cmd_header));
-       cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
-       /* reset Beacon SNR/NF/RSSI values */
-       priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
-       priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
-       priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
-       priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
-       priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
-       priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-int lbs_ret_802_11_rssi(struct lbs_private *priv,
-                               struct cmd_ds_command *resp)
-{
-       struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       /* store the non average value */
-       priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
-       priv->NF[TYPE_BEACON][TYPE_NOAVG] =
-               get_unaligned_le16(&rssirsp->noisefloor);
-
-       priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
-       priv->NF[TYPE_BEACON][TYPE_AVG] =
-               get_unaligned_le16(&rssirsp->avgnoisefloor);
-
-       priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
-           CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
-                    priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
-       priv->RSSI[TYPE_BEACON][TYPE_AVG] =
-           CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
-                    priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
-
-       lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
-              priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
-              priv->RSSI[TYPE_BEACON][TYPE_AVG]);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-
-int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
-                               struct cmd_ds_command *cmd,
-                               u16 cmd_action)
-{
-       struct cmd_ds_802_11_beacon_control
-               *bcn_ctrl = &cmd->params.bcn_ctrl;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->size =
-           cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
-                            + sizeof(struct cmd_header));
-       cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
-
-       bcn_ctrl->action = cpu_to_le16(cmd_action);
-       bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
-       bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
-int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
-                                       struct cmd_ds_command *resp)
-{
-       struct cmd_ds_802_11_beacon_control *bcn_ctrl =
-           &resp->params.bcn_ctrl;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (bcn_ctrl->action == CMD_ACT_GET) {
-               priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
-               priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
-       }
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       return 0;
-}
-
-
-
-static int lbs_assoc_post(struct lbs_private *priv,
-                         struct cmd_ds_802_11_associate_response *resp)
-{
-       int ret = 0;
-       union iwreq_data wrqu;
-       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;
-
-       /*
-        * Older FW versions map the IEEE 802.11 Status Code in the association
-        * response to the following values returned in resp->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(resp->statuscode);
-       if (priv->fwrelease < 0x09000000) {
-               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;
-               }
-       } else {
-               /* v9+ returns the AP's association response */
-               lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
-       }
-
-       if (status_code) {
-               lbs_mac_event_disconnected(priv);
-               ret = status_code;
-               goto done;
-       }
-
-       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
-                   (void *) (resp + sizeof (resp->hdr)),
-                   le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
-
-       /* 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, IEEE80211_MAX_SSID_LEN);
-       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;
-}
-
-/**
- *  @brief This function prepares an association-class command.
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param assoc_req The association request describing the BSS to associate
- *                   or reassociate with
- *  @param command   The actual command, either CMD_802_11_ASSOCIATE or
- *                   CMD_802_11_REASSOCIATE
- *
- *  @return         0 or -1
- */
-static int lbs_associate(struct lbs_private *priv,
-                        struct assoc_request *assoc_req,
-                        u16 command)
-{
-       struct cmd_ds_802_11_associate cmd;
-       int ret = 0;
-       struct bss_descriptor *bss = &assoc_req->bss;
-       u8 *pos = &(cmd.iebuf[0]);
-       u16 tmpcap, tmplen, tmpauth;
-       struct mrvl_ie_ssid_param_set *ssid;
-       struct mrvl_ie_ds_param_set *ds;
-       struct mrvl_ie_cf_param_set *cf;
-       struct mrvl_ie_rates_param_set *rates;
-       struct mrvl_ie_rsn_param_set *rsn;
-       struct mrvl_ie_auth_type *auth;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       BUG_ON((command != CMD_802_11_ASSOCIATE) &&
-               (command != CMD_802_11_REASSOCIATE));
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.command = cpu_to_le16(command);
-
-       /* Fill in static fields */
-       memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
-       cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
-
-       /* Capability info */
-       tmpcap = (bss->capability & CAPINFO_MASK);
-       if (bss->mode == IW_MODE_INFRA)
-               tmpcap |= WLAN_CAPABILITY_ESS;
-       cmd.capability = cpu_to_le16(tmpcap);
-       lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
-
-       /* SSID */
-       ssid = (struct mrvl_ie_ssid_param_set *) 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;
-
-       ds = (struct mrvl_ie_ds_param_set *) pos;
-       ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
-       ds->header.len = cpu_to_le16(1);
-       ds->channel = bss->phy.ds.channel;
-       pos += sizeof(ds->header) + 1;
-
-       cf = (struct mrvl_ie_cf_param_set *) pos;
-       cf->header.type = cpu_to_le16(TLV_TYPE_CF);
-       tmplen = sizeof(*cf) - sizeof (cf->header);
-       cf->header.len = cpu_to_le16(tmplen);
-       /* IE payload should be zeroed, firmware fills it in for us */
-       pos += sizeof(*cf);
-
-       rates = (struct mrvl_ie_rates_param_set *) pos;
-       rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
-       tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
-       memcpy(&rates->rates, &bss->rates, tmplen);
-       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);
-
-       /* Firmware v9+ indicate authentication suites as a TLV */
-       if (priv->fwrelease >= 0x09000000) {
-               auth = (struct mrvl_ie_auth_type *) pos;
-               auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
-               auth->header.len = cpu_to_le16(2);
-               tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
-               auth->auth = cpu_to_le16(tmpauth);
-               pos += sizeof(auth->header) + 2;
-
-               lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
-                       bss->bssid, priv->secinfo.auth_mode);
-       }
-
-       /* WPA/WPA2 IEs */
-       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-               rsn = (struct mrvl_ie_rsn_param_set *) 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: WPA/RSN IE", (u8 *) rsn,
-                       sizeof(rsn->header) + tmplen);
-               pos += sizeof(rsn->header) + tmplen;
-       }
-
-       cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
-                                  (u16)(pos - (u8 *) &cmd.iebuf));
-
-       /* update curbssparams */
-       priv->channel = bss->phy.ds.channel;
-
-       ret = lbs_cmd_with_response(priv, command, &cmd);
-       if (ret == 0) {
-               ret = lbs_assoc_post(priv,
-                       (struct cmd_ds_802_11_associate_response *) &cmd);
-       }
-
-done:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Associate to a specific BSS discovered in a scan
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param assoc_req The association request describing the BSS to associate with
- *
- *  @return          0-success, otherwise fail
- */
-static int lbs_try_associate(struct lbs_private *priv,
-       struct assoc_request *assoc_req)
-{
-       int ret;
-       u8 preamble = RADIO_PREAMBLE_LONG;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       /* FW v9 and higher indicate authentication suites as a TLV in the
-        * association command, not as a separate authentication command.
-        */
-       if (priv->fwrelease < 0x09000000) {
-               ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
-                                            priv->secinfo.auth_mode);
-               if (ret)
-                       goto out;
-       }
-
-       /* Use short preamble only when both the BSS and firmware support it */
-       if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-               preamble = RADIO_PREAMBLE_SHORT;
-
-       ret = lbs_set_radio(priv, preamble, 1);
-       if (ret)
-               goto out;
-
-       ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
-       /* If the association fails with current auth mode, let's
-        * try by changing the auth mode
-        */
-       if ((priv->authtype_auto) &&
-                       (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) &&
-                       (assoc_req->secinfo.wep_enabled) &&
-                       (priv->connect_status != LBS_CONNECTED)) {
-               if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM)
-                       priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-               else
-                       priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-               if (!assoc_helper_wep_keys(priv, assoc_req))
-                       ret = lbs_associate(priv, assoc_req,
-                                               CMD_802_11_ASSOCIATE);
-       }
-
-       if (ret)
-               ret = -1;
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_adhoc_post(struct lbs_private *priv,
-                         struct cmd_ds_802_11_ad_hoc_result *resp)
-{
-       int ret = 0;
-       u16 command = le16_to_cpu(resp->hdr.command);
-       u16 result = le16_to_cpu(resp->hdr.result);
-       union iwreq_data wrqu;
-       struct bss_descriptor *bss;
-       DECLARE_SSID_BUF(ssid);
-
-       lbs_deb_enter(LBS_DEB_JOIN);
-
-       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 (result 0x%X)\n", result);
-               if (priv->connect_status == LBS_CONNECTED)
-                       lbs_mac_event_disconnected(priv);
-               ret = -1;
-               goto done;
-       }
-
-       /* 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, resp->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, IEEE80211_MAX_SSID_LEN);
-       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 '%s', BSSID %pM, channel %d\n",
-                    print_ssid(ssid, bss->ssid, bss->ssid_len),
-                    priv->curbssparams.bssid,
-                    priv->channel);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_JOIN, "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 assoc_req    The association request describing the BSS to join
- *
- *  @return             0 on success, error on failure
- */
-static int lbs_adhoc_join(struct lbs_private *priv,
-       struct assoc_request *assoc_req)
-{
-       struct cmd_ds_802_11_ad_hoc_join cmd;
-       struct bss_descriptor *bss = &assoc_req->bss;
-       u8 preamble = RADIO_PREAMBLE_LONG;
-       DECLARE_SSID_BUF(ssid);
-       u16 ratesize = 0;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       lbs_deb_join("current SSID '%s', ssid length %u\n",
-               print_ssid(ssid, priv->curbssparams.ssid,
-               priv->curbssparams.ssid_len),
-               priv->curbssparams.ssid_len);
-       lbs_deb_join("requested ssid '%s', ssid length %u\n",
-               print_ssid(ssid, 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 short preamble only when both the BSS and firmware support it */
-       if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
-               lbs_deb_join("AdhocJoin: Short preamble\n");
-               preamble = RADIO_PREAMBLE_SHORT;
-       }
-
-       ret = lbs_set_radio(priv, preamble, 1);
-       if (ret)
-               goto out;
-
-       lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
-       lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
-
-       priv->adhoccreate = 0;
-       priv->channel = bss->channel;
-
-       /* Build the join command */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       cmd.bss.type = CMD_BSS_TYPE_IBSS;
-       cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
-
-       memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
-       memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
-
-       memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
-
-       memcpy(&cmd.bss.ibss, &bss->ss.ibss,
-              sizeof(struct ieee_ie_ibss_param_set));
-
-       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 = %pM, SSID = '%s'\n",
-                       cmd.bss.bssid, cmd.bss.ssid);
-
-       /* Only v8 and below support setting these */
-       if (priv->fwrelease < 0x09000000) {
-               /* failtimeout */
-               cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
-               /* probedelay */
-               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-       }
-
-       /* Copy Data rates from the rates recorded in scan response */
-       memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
-       ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
-       memcpy(cmd.bss.rates, bss->rates, ratesize);
-       if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
-               lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
-               ret = -1;
-               goto out;
-       }
-
-       /* Copy the ad-hoc creation rates into Current BSS state structure */
-       memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-       memcpy(&priv->curbssparams.rates, 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(cmd.bss.rates, ratesize);
-
-       cmd.bss.ibss.atimwindow = bss->atimwindow;
-
-       if (assoc_req->secinfo.wep_enabled) {
-               u16 tmp = le16_to_cpu(cmd.bss.capability);
-               tmp |= WLAN_CAPABILITY_PRIVACY;
-               cmd.bss.capability = cpu_to_le16(tmp);
-       }
-
-       if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
-               __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
-
-               /* wake up first */
-               ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
-                                                  CMD_ACT_SET, 0, 0,
-                                                  &local_ps_mode);
-               if (ret) {
-                       ret = -1;
-                       goto out;
-               }
-       }
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
-       if (ret == 0) {
-               ret = lbs_adhoc_post(priv,
-                                    (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Start an Adhoc Network
- *
- *  @param priv         A pointer to struct lbs_private structure
- *  @param assoc_req    The association request describing the BSS to start
- *
- *  @return             0 on success, error on failure
- */
-static int lbs_adhoc_start(struct lbs_private *priv,
-       struct assoc_request *assoc_req)
-{
-       struct cmd_ds_802_11_ad_hoc_start cmd;
-       u8 preamble = RADIO_PREAMBLE_SHORT;
-       size_t ratesize = 0;
-       u16 tmpcap = 0;
-       int ret = 0;
-       DECLARE_SSID_BUF(ssid);
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       ret = lbs_set_radio(priv, preamble, 1);
-       if (ret)
-               goto out;
-
-       /* Build the start command */
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
-
-       lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
-               print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
-               assoc_req->ssid_len);
-
-       cmd.bsstype = CMD_BSS_TYPE_IBSS;
-
-       if (priv->beacon_period == 0)
-               priv->beacon_period = MRVDRV_BEACON_INTERVAL;
-       cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
-
-       WARN_ON(!assoc_req->channel);
-
-       /* set Physical parameter set */
-       cmd.ds.header.id = WLAN_EID_DS_PARAMS;
-       cmd.ds.header.len = 1;
-       cmd.ds.channel = assoc_req->channel;
-
-       /* set IBSS parameter set */
-       cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
-       cmd.ibss.header.len = 2;
-       cmd.ibss.atimwindow = cpu_to_le16(0);
-
-       /* set capability info */
-       tmpcap = WLAN_CAPABILITY_IBSS;
-       if (assoc_req->secinfo.wep_enabled ||
-           assoc_req->secinfo.WPAenabled ||
-           assoc_req->secinfo.WPA2enabled) {
-               lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
-               tmpcap |= WLAN_CAPABILITY_PRIVACY;
-       } else
-               lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
-
-       cmd.capability = cpu_to_le16(tmpcap);
-
-       /* Only v8 and below support setting probe delay */
-       if (priv->fwrelease < 0x09000000)
-               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-
-       ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
-       memcpy(cmd.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, &cmd.rates, ratesize);
-
-       /* Set MSB on basic rates as the firmware requires, but _after_
-        * copying to current bss rates.
-        */
-       lbs_set_basic_rate_flags(cmd.rates, ratesize);
-
-       lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
-              cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
-
-       lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
-                    assoc_req->channel, assoc_req->band);
-
-       priv->adhoccreate = 1;
-       priv->mode = IW_MODE_ADHOC;
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
-       if (ret == 0)
-               ret = lbs_adhoc_post(priv,
-                                    (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
- *
- *  @param priv         A pointer to struct lbs_private structure
- *  @return             0 on success, or an error
- */
-int lbs_adhoc_stop(struct lbs_private *priv)
-{
-       struct cmd_ds_802_11_ad_hoc_stop cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_JOIN);
-
-       memset(&cmd, 0, sizeof (cmd));
-       cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
-
-       /* Clean up everything even if there was an error */
-       lbs_mac_event_disconnected(priv);
-
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-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] != WLAN_EID_GENERIC &&
-           match_bss->rsn_ie[0] != WLAN_EID_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] == WLAN_EID_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] == WLAN_EID_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] != WLAN_EID_GENERIC) &&
-           (match_bss->rsn_ie[0] != WLAN_EID_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)
-{
-       int ret = 0;
-       struct bss_descriptor * bss;
-       int channel = -1;
-       DECLARE_SSID_BUF(ssid);
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       /* FIXME: take channel into account when picking SSIDs if a channel
-        * is set.
-        */
-
-       if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
-               channel = assoc_req->channel;
-
-       lbs_deb_assoc("SSID '%s' requested\n",
-                     print_ssid(ssid, 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);
-
-               bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
-                               assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
-               if (bss != NULL) {
-                       memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-                       ret = lbs_try_associate(priv, assoc_req);
-               } else {
-                       lbs_deb_assoc("SSID not found; cannot associate\n");
-               }
-       } else if (assoc_req->mode == IW_MODE_ADHOC) {
-               /* Scan for the network, do not save previous results.  Stale
-                *   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);
-
-               /* Search for the requested SSID in the scan table */
-               bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
-                               assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
-               if (bss != NULL) {
-                       lbs_deb_assoc("SSID found, will join\n");
-                       memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-                       lbs_adhoc_join(priv, assoc_req);
-               } else {
-                       /* else send START command */
-                       lbs_deb_assoc("SSID not found, creating adhoc network\n");
-                       memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
-                               IEEE80211_MAX_SSID_LEN);
-                       assoc_req->bss.ssid_len = assoc_req->ssid_len;
-                       lbs_adhoc_start(priv, assoc_req);
-               }
-       }
-
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int assoc_helper_bssid(struct lbs_private *priv,
-                              struct assoc_request * assoc_req)
-{
-       int ret = 0;
-       struct bss_descriptor * bss;
-
-       lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
-
-       /* Search for index position in list for requested MAC */
-       bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
-                           assoc_req->mode);
-       if (bss == NULL) {
-               lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
-                       "cannot associate.\n", assoc_req->bssid);
-               goto out;
-       }
-
-       memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-       if (assoc_req->mode == IW_MODE_INFRA) {
-               ret = lbs_try_associate(priv, assoc_req);
-               lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
-                             ret);
-       } else if (assoc_req->mode == IW_MODE_ADHOC) {
-               lbs_adhoc_join(priv, assoc_req);
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int assoc_helper_associate(struct lbs_private *priv,
-                                  struct assoc_request * assoc_req)
-{
-       int ret = 0, done = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       /* If we're given and 'any' BSSID, try associating based on SSID */
-
-       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-               if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
-                   compare_ether_addr(bssid_off, assoc_req->bssid)) {
-                       ret = assoc_helper_bssid(priv, assoc_req);
-                       done = 1;
-               }
-       }
-
-       if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-               ret = assoc_helper_essid(priv, assoc_req);
-       }
-
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int assoc_helper_mode(struct lbs_private *priv,
-                             struct assoc_request * assoc_req)
-{
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       if (assoc_req->mode == priv->mode)
-               goto done;
-
-       if (assoc_req->mode == IW_MODE_INFRA) {
-               if (priv->psstate != PS_STATE_FULL_POWER)
-                       lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-               priv->psmode = LBS802_11POWERMODECAM;
-       }
-
-       priv->mode = assoc_req->mode;
-       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
-               assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-static int assoc_helper_channel(struct lbs_private *priv,
-                                struct assoc_request * assoc_req)
-{
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       ret = lbs_update_channel(priv);
-       if (ret) {
-               lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
-               goto done;
-       }
-
-       if (assoc_req->channel == priv->channel)
-               goto done;
-
-       if (priv->mesh_dev) {
-               /* Change mesh channel first; 21.p21 firmware won't let
-                  you change channel otherwise (even though it'll return
-                  an error to this */
-               lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
-                               assoc_req->channel);
-       }
-
-       lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
-                     priv->channel, assoc_req->channel);
-
-       ret = lbs_set_channel(priv, assoc_req->channel);
-       if (ret < 0)
-               lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
-
-       /* FIXME: shouldn't need to grab the channel _again_ after setting
-        * it since the firmware is supposed to return the new channel, but
-        * whatever... */
-       ret = lbs_update_channel(priv);
-       if (ret) {
-               lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
-               goto done;
-       }
-
-       if (assoc_req->channel != priv->channel) {
-               lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
-                             assoc_req->channel);
-               goto restore_mesh;
-       }
-
-       if (assoc_req->secinfo.wep_enabled &&
-           (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
-            assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
-               /* Make sure WEP keys are re-sent to firmware */
-               set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-       }
-
-       /* Must restart/rejoin adhoc networks after channel change */
-       set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-
- restore_mesh:
-       if (priv->mesh_dev)
-               lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-                               priv->channel);
-
- done:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int assoc_helper_wep_keys(struct lbs_private *priv,
-                                struct assoc_request *assoc_req)
-{
-       int i;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       /* Set or remove WEP keys */
-       if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
-           assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
-               ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
-       else
-               ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
-
-       if (ret)
-               goto out;
-
-       /* enable/disable the MAC's WEP packet filter */
-       if (assoc_req->secinfo.wep_enabled)
-               priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
-       else
-               priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
-
-       lbs_set_mac_control(priv);
-
-       mutex_lock(&priv->lock);
-
-       /* Copy WEP keys into priv wep key fields */
-       for (i = 0; i < 4; i++) {
-               memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
-                      sizeof(struct enc_key));
-       }
-       priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
-
-       mutex_unlock(&priv->lock);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-static int assoc_helper_secinfo(struct lbs_private *priv,
-                                struct assoc_request * assoc_req)
-{
-       int ret = 0;
-       uint16_t do_wpa;
-       uint16_t rsn = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       memcpy(&priv->secinfo, &assoc_req->secinfo,
-               sizeof(struct lbs_802_11_security));
-
-       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
-        * 4-way WPA handshake.
-        */
-
-       /* Get RSN enabled/disabled */
-       ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
-       if (ret) {
-               lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
-               goto out;
-       }
-
-       /* Don't re-enable RSN if it's already enabled */
-       do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
-       if (do_wpa == rsn)
-               goto out;
-
-       /* Set RSN enabled/disabled */
-       ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int assoc_helper_wpa_keys(struct lbs_private *priv,
-                                 struct assoc_request * assoc_req)
-{
-       int ret = 0;
-       unsigned int flags = assoc_req->flags;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       /* Work around older firmware bug where WPA unicast and multicast
-        * keys must be set independently.  Seen in SDIO parts with firmware
-        * version 5.0.11p0.
-        */
-
-       if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-               clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-               ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
-               assoc_req->flags = flags;
-       }
-
-       if (ret)
-               goto out;
-
-       memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
-                       sizeof(struct enc_key));
-
-       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
-               clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-
-               ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
-               assoc_req->flags = flags;
-
-               memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
-                               sizeof(struct enc_key));
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int assoc_helper_wpa_ie(struct lbs_private *priv,
-                               struct assoc_request * assoc_req)
-{
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-               memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
-               priv->wpa_ie_len = assoc_req->wpa_ie_len;
-       } else {
-               memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
-               priv->wpa_ie_len = 0;
-       }
-
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int should_deauth_infrastructure(struct lbs_private *priv,
-                                        struct assoc_request * assoc_req)
-{
-       int ret = 0;
-
-       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;
-               goto out;
-       }
-
-       if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-               if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
-                       lbs_deb_assoc("Deauthenticating due to new security\n");
-                       ret = 1;
-                       goto out;
-               }
-       }
-
-       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-               lbs_deb_assoc("Deauthenticating due to new BSSID\n");
-               ret = 1;
-               goto out;
-       }
-
-       if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-               lbs_deb_assoc("Deauthenticating due to channel switch\n");
-               ret = 1;
-               goto out;
-       }
-
-       /* FIXME: deal with 'auto' mode somehow */
-       if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-               if (assoc_req->mode != IW_MODE_INFRA) {
-                       lbs_deb_assoc("Deauthenticating due to leaving "
-                               "infra mode\n");
-                       ret = 1;
-                       goto out;
-               }
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-
-static int should_stop_adhoc(struct lbs_private *priv,
-                             struct assoc_request * assoc_req)
-{
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       if (priv->connect_status != LBS_CONNECTED)
-               return 0;
-
-       if (lbs_ssid_cmp(priv->curbssparams.ssid,
-                             priv->curbssparams.ssid_len,
-                             assoc_req->ssid, assoc_req->ssid_len) != 0)
-               return 1;
-
-       /* FIXME: deal with 'auto' mode somehow */
-       if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-               if (assoc_req->mode != IW_MODE_ADHOC)
-                       return 1;
-       }
-
-       if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-               if (assoc_req->channel != priv->channel)
-                       return 1;
-       }
-
-       lbs_deb_leave(LBS_DEB_ASSOC);
-       return 0;
-}
-
-
-/**
- *  @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, IEEE80211_MAX_SSID_LEN);
-               *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,
-               assoc_work.work);
-       struct assoc_request * assoc_req = NULL;
-       int ret = 0;
-       int find_any_ssid = 0;
-       DECLARE_SSID_BUF(ssid);
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       mutex_lock(&priv->lock);
-       assoc_req = priv->pending_assoc_req;
-       priv->pending_assoc_req = NULL;
-       priv->in_progress_assoc_req = assoc_req;
-       mutex_unlock(&priv->lock);
-
-       if (!assoc_req)
-               goto done;
-
-       lbs_deb_assoc(
-               "Association Request:\n"
-               "    flags:     0x%08lx\n"
-               "    SSID:      '%s'\n"
-               "    chann:     %d\n"
-               "    band:      %d\n"
-               "    mode:      %d\n"
-               "    BSSID:     %pM\n"
-               "    secinfo:  %s%s%s\n"
-               "    auth_mode: %d\n",
-               assoc_req->flags,
-               print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
-               assoc_req->channel, assoc_req->band, assoc_req->mode,
-               assoc_req->bssid,
-               assoc_req->secinfo.WPAenabled ? " WPA" : "",
-               assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
-               assoc_req->secinfo.wep_enabled ? " WEP" : "",
-               assoc_req->secinfo.auth_mode);
-
-       /* If 'any' SSID was specified, find an SSID to associate with */
-       if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
-           !assoc_req->ssid_len)
-               find_any_ssid = 1;
-
-       /* But don't use 'any' SSID if there's a valid locked BSSID to use */
-       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-               if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
-                   compare_ether_addr(assoc_req->bssid, bssid_off))
-                       find_any_ssid = 0;
-       }
-
-       if (find_any_ssid) {
-               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);
-               if (ret) {
-                       lbs_deb_assoc("Could not find best network\n");
-                       ret = -ENETUNREACH;
-                       goto out;
-               }
-
-               /* Ensure we switch to the mode of the AP */
-               if (assoc_req->mode == IW_MODE_AUTO) {
-                       set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
-                       assoc_req->mode = new_mode;
-               }
-       }
-
-       /*
-        * Check if the attributes being changing require deauthentication
-        * from the currently associated infrastructure access point.
-        */
-       if (priv->mode == IW_MODE_INFRA) {
-               if (should_deauth_infrastructure(priv, assoc_req)) {
-                       ret = lbs_cmd_80211_deauthenticate(priv,
-                                                          priv->curbssparams.bssid,
-                                                          WLAN_REASON_DEAUTH_LEAVING);
-                       if (ret) {
-                               lbs_deb_assoc("Deauthentication due to new "
-                                       "configuration request failed: %d\n",
-                                       ret);
-                       }
-               }
-       } else if (priv->mode == IW_MODE_ADHOC) {
-               if (should_stop_adhoc(priv, assoc_req)) {
-                       ret = lbs_adhoc_stop(priv);
-                       if (ret) {
-                               lbs_deb_assoc("Teardown of AdHoc network due to "
-                                       "new configuration request failed: %d\n",
-                                       ret);
-                       }
-
-               }
-       }
-
-       /* Send the various configuration bits to the firmware */
-       if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-               ret = assoc_helper_mode(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
-       if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-               ret = assoc_helper_channel(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
-       if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-               ret = assoc_helper_secinfo(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
-       if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
-               ret = assoc_helper_wpa_ie(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
-       /*
-        * v10 FW wants WPA keys to be set/cleared before WEP key operations,
-        * otherwise it will fail to correctly associate to WEP networks.
-        * Other firmware versions don't appear to care.
-        */
-       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
-           test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-               ret = assoc_helper_wpa_keys(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
-       if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
-           test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
-               ret = assoc_helper_wep_keys(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
-
-       /* SSID/BSSID should be the _last_ config option set, because they
-        * trigger the association attempt.
-        */
-       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
-           test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-               int success = 1;
-
-               ret = assoc_helper_associate(priv, assoc_req);
-               if (ret) {
-                       lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
-                               ret);
-                       success = 0;
-               }
-
-               if (priv->connect_status != LBS_CONNECTED) {
-                       lbs_deb_assoc("ASSOC: association unsuccessful, "
-                               "not connected\n");
-                       success = 0;
-               }
-
-               if (success) {
-                       lbs_deb_assoc("associated to %pM\n",
-                               priv->curbssparams.bssid);
-                       lbs_prepare_and_send_command(priv,
-                               CMD_802_11_RSSI,
-                               0, CMD_OPTION_WAITFORRSP, 0, NULL);
-               } else {
-                       ret = -1;
-               }
-       }
-
-out:
-       if (ret) {
-               lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
-                       ret);
-       }
-
-       mutex_lock(&priv->lock);
-       priv->in_progress_assoc_req = NULL;
-       mutex_unlock(&priv->lock);
-       kfree(assoc_req);
-
-done:
-       lbs_deb_leave(LBS_DEB_ASSOC);
-}
-
-
-/*
- * Caller MUST hold any necessary locks
- */
-struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
-{
-       struct assoc_request * assoc_req;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-       if (!priv->pending_assoc_req) {
-               priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
-                                                    GFP_KERNEL);
-               if (!priv->pending_assoc_req) {
-                       lbs_pr_info("Not enough memory to allocate association"
-                               " request!\n");
-                       return NULL;
-               }
-       }
-
-       /* Copy current configuration attributes to the association request,
-        * but don't overwrite any that are already set.
-        */
-       assoc_req = priv->pending_assoc_req;
-       if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-               memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
-                      IEEE80211_MAX_SSID_LEN);
-               assoc_req->ssid_len = priv->curbssparams.ssid_len;
-       }
-
-       if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
-               assoc_req->channel = priv->channel;
-
-       if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
-               assoc_req->band = priv->curbssparams.band;
-
-       if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
-               assoc_req->mode = priv->mode;
-
-       if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-               memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
-                       ETH_ALEN);
-       }
-
-       if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
-               int i;
-               for (i = 0; i < 4; i++) {
-                       memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
-                               sizeof(struct enc_key));
-               }
-       }
-
-       if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
-               assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
-
-       if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
-               memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
-                       sizeof(struct enc_key));
-       }
-
-       if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-               memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
-                       sizeof(struct enc_key));
-       }
-
-       if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-               memcpy(&assoc_req->secinfo, &priv->secinfo,
-                       sizeof(struct lbs_802_11_security));
-       }
-
-       if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
-               memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
-                       MAX_WPA_IE_LEN);
-               assoc_req->wpa_ie_len = priv->wpa_ie_len;
-       }
-
-       lbs_deb_leave(LBS_DEB_ASSOC);
-       return assoc_req;
-}
-
-
-/**
- *  @brief Deauthenticate from a specific BSS
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param bssid       The specific BSS to deauthenticate from
- *  @param reason      The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
- *
- *  @return            0 on success, error on failure
- */
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
-                                u16 reason)
-{
-       struct cmd_ds_802_11_deauthenticate cmd;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_JOIN);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
-       cmd.reasoncode = cpu_to_le16(reason);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
-
-       /* Clean up everything even if there was an error; can't assume that
-        * we're still authenticated to the AP after trying to deauth.
-        */
-       lbs_mac_event_disconnected(priv);
-
-       lbs_deb_leave(LBS_DEB_JOIN);
-       return ret;
-}
-
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
deleted file mode 100644 (file)
index 40621b7..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Copyright (C) 2006, Red Hat, Inc. */
-
-#ifndef _LBS_ASSOC_H_
-#define _LBS_ASSOC_H_
-
-
-#include "defs.h"
-#include "host.h"
-
-
-struct lbs_private;
-
-/*
- * In theory, the IE is limited to the IE length, 255,
- * but in practice 64 bytes are enough.
- */
-#define MAX_WPA_IE_LEN 64
-
-
-
-struct lbs_802_11_security {
-       u8 WPAenabled;
-       u8 WPA2enabled;
-       u8 wep_enabled;
-       u8 auth_mode;
-       u32 key_mgmt;
-};
-
-/** Current Basic Service Set State Structure */
-struct current_bss_params {
-       /** bssid */
-       u8 bssid[ETH_ALEN];
-       /** ssid */
-       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 ssid_len;
-
-       /** band */
-       u8 band;
-       /** channel is directly in priv->channel */
-       /** zero-terminated array of supported data rates */
-       u8 rates[MAX_RATES + 1];
-};
-
-/**
- *  @brief Structure used to store information for each beacon/probe response
- */
-struct bss_descriptor {
-       u8 bssid[ETH_ALEN];
-
-       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 ssid_len;
-
-       u16 capability;
-       u32 rssi;
-       u32 channel;
-       u16 beaconperiod;
-       __le16 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 ieee_phy_param_set phy;
-       union ieee_ss_param_set ss;
-
-       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
- * or configuration of the wireless card's radio, mode, and security settings.
- */
-struct assoc_request {
-#define ASSOC_FLAG_SSID                        1
-#define ASSOC_FLAG_CHANNEL             2
-#define ASSOC_FLAG_BAND                        3
-#define ASSOC_FLAG_MODE                        4
-#define ASSOC_FLAG_BSSID               5
-#define ASSOC_FLAG_WEP_KEYS            6
-#define ASSOC_FLAG_WEP_TX_KEYIDX       7
-#define ASSOC_FLAG_WPA_MCAST_KEY       8
-#define ASSOC_FLAG_WPA_UCAST_KEY       9
-#define ASSOC_FLAG_SECINFO             10
-#define ASSOC_FLAG_WPA_IE              11
-       unsigned long flags;
-
-       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 ssid_len;
-       u8 channel;
-       u8 band;
-       u8 mode;
-       u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
-
-       /** WEP keys */
-       struct enc_key wep_keys[4];
-       u16 wep_tx_keyidx;
-
-       /** WPA keys */
-       struct enc_key wpa_mcast_key;
-       struct enc_key wpa_unicast_key;
-
-       struct lbs_802_11_security secinfo;
-
-       /** WPA Information Elements*/
-       u8 wpa_ie[MAX_WPA_IE_LEN];
-       u8 wpa_ie_len;
-
-       /* BSS to associate with for infrastructure of Ad-Hoc join */
-       struct bss_descriptor bss;
-};
-
-
-extern u8 lbs_bg_rates[MAX_RATES];
-
-void lbs_association_worker(struct work_struct *work);
-struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
-
-int lbs_adhoc_stop(struct lbs_private *priv);
-
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
-                                u8 bssid[ETH_ALEN], u16 reason);
-
-int lbs_cmd_802_11_rssi(struct lbs_private *priv,
-                               struct cmd_ds_command *cmd);
-int lbs_ret_802_11_rssi(struct lbs_private *priv,
-                               struct cmd_ds_command *resp);
-
-int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
-                               struct cmd_ds_command *cmd,
-                               u16 cmd_action);
-int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
-                                       struct cmd_ds_command *resp);
-
-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_ASSOC_H */
index 9d5d3ccf08c854376e9a22d3364019b37512baf5..f36cc970ad1b272feab889de344e0ee6bd66a38d 100644 (file)
@@ -7,8 +7,12 @@
  */
 
 #include <linux/slab.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
 #include <net/cfg80211.h>
+#include <asm/unaligned.h>
 
+#include "decl.h"
 #include "cfg.h"
 #include "cmd.h"
 
@@ -39,26 +43,27 @@ static struct ieee80211_channel lbs_2ghz_channels[] = {
        CHAN2G(14, 2484, 0),
 };
 
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
-       .bitrate  = (_rate),                  \
-       .hw_value = (_rateid),                \
-       .flags    = (_flags),                 \
+#define RATETAB_ENT(_rate, _hw_value, _flags) { \
+       .bitrate  = (_rate),                    \
+       .hw_value = (_hw_value),                \
+       .flags    = (_flags),                   \
 }
 
 
+/* Table 6 in section 3.2.1.1 */
 static struct ieee80211_rate lbs_rates[] = {
-       RATETAB_ENT(10,  0x1,   0),
-       RATETAB_ENT(20,  0x2,   0),
-       RATETAB_ENT(55,  0x4,   0),
-       RATETAB_ENT(110, 0x8,   0),
-       RATETAB_ENT(60,  0x10,  0),
-       RATETAB_ENT(90,  0x20,  0),
-       RATETAB_ENT(120, 0x40,  0),
-       RATETAB_ENT(180, 0x80,  0),
-       RATETAB_ENT(240, 0x100, 0),
-       RATETAB_ENT(360, 0x200, 0),
-       RATETAB_ENT(480, 0x400, 0),
-       RATETAB_ENT(540, 0x800, 0),
+       RATETAB_ENT(10,  0,  0),
+       RATETAB_ENT(20,  1,  0),
+       RATETAB_ENT(55,  2,  0),
+       RATETAB_ENT(110, 3,  0),
+       RATETAB_ENT(60,  9,  0),
+       RATETAB_ENT(90,  6,  0),
+       RATETAB_ENT(120, 7,  0),
+       RATETAB_ENT(180, 8,  0),
+       RATETAB_ENT(240, 9,  0),
+       RATETAB_ENT(360, 10, 0),
+       RATETAB_ENT(480, 11, 0),
+       RATETAB_ENT(540, 12, 0),
 };
 
 static struct ieee80211_supported_band lbs_band_2ghz = {
@@ -76,22 +81,1824 @@ static const u32 cipher_suites[] = {
        WLAN_CIPHER_SUITE_CCMP,
 };
 
+/* Time to stay on the channel */
+#define LBS_DWELL_PASSIVE 100
+#define LBS_DWELL_ACTIVE  40
 
 
+/***************************************************************************
+ * Misc utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+/*
+ * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
+ * in the firmware spec
+ */
+static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
+{
+       int ret = -ENOTSUPP;
+
+       switch (auth_type) {
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               ret = auth_type;
+               break;
+       case NL80211_AUTHTYPE_AUTOMATIC:
+               ret = NL80211_AUTHTYPE_OPEN_SYSTEM;
+               break;
+       case NL80211_AUTHTYPE_NETWORK_EAP:
+               ret = 0x80;
+               break;
+       default:
+               /* silence compiler */
+               break;
+       }
+       return ret;
+}
+
+
+/* Various firmware commands need the list of supported rates, but with
+   the hight-bit set for basic rates */
+static int lbs_add_rates(u8 *rates)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+               u8 rate = lbs_rates[i].bitrate / 5;
+               if (rate == 0x02 || rate == 0x04 ||
+                   rate == 0x0b || rate == 0x16)
+                       rate |= 0x80;
+               rates[i] = rate;
+       }
+       return ARRAY_SIZE(lbs_rates);
+}
+
+
+/***************************************************************************
+ * TLV utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+
+/*
+ * Add ssid TLV
+ */
+#define LBS_MAX_SSID_TLV_SIZE                  \
+       (sizeof(struct mrvl_ie_header)          \
+        + IEEE80211_MAX_SSID_LEN)
+
+static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len)
+{
+       struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
+
+       /*
+        * TLV-ID SSID  00 00
+        * length       06 00
+        * ssid         4d 4e 54 45 53 54
+        */
+       ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+       ssid_tlv->header.len = cpu_to_le16(ssid_len);
+       memcpy(ssid_tlv->ssid, ssid, ssid_len);
+       return sizeof(ssid_tlv->header) + ssid_len;
+}
+
+
+/*
+ * Add channel list TLV (section 8.4.2)
+ *
+ * Actual channel data comes from priv->wdev->wiphy->channels.
+ */
+#define LBS_MAX_CHANNEL_LIST_TLV_SIZE                                  \
+       (sizeof(struct mrvl_ie_header)                                  \
+        + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset)))
+
+static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv,
+                                   int last_channel, int active_scan)
+{
+       int chanscanparamsize = sizeof(struct chanscanparamset) *
+               (last_channel - priv->scan_channel);
+
+       struct mrvl_ie_header *header = (void *) tlv;
+
+       /*
+        * TLV-ID CHANLIST  01 01
+        * length           0e 00
+        * channel          00 01 00 00 00 64 00
+        *   radio type     00
+        *   channel           01
+        *   scan type            00
+        *   min scan time           00 00
+        *   max scan time                 64 00
+        * channel 2        00 02 00 00 00 64 00
+        *
+        */
+
+       header->type = cpu_to_le16(TLV_TYPE_CHANLIST);
+       header->len  = cpu_to_le16(chanscanparamsize);
+       tlv += sizeof(struct mrvl_ie_header);
+
+       /* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel,
+                    last_channel); */
+       memset(tlv, 0, chanscanparamsize);
+
+       while (priv->scan_channel < last_channel) {
+               struct chanscanparamset *param = (void *) tlv;
+
+               param->radiotype = CMD_SCAN_RADIO_TYPE_BG;
+               param->channumber =
+                       priv->scan_req->channels[priv->scan_channel]->hw_value;
+               if (active_scan) {
+                       param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE);
+               } else {
+                       param->chanscanmode.passivescan = 1;
+                       param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE);
+               }
+               tlv += sizeof(struct chanscanparamset);
+               priv->scan_channel++;
+       }
+       return sizeof(struct mrvl_ie_header) + chanscanparamsize;
+}
+
+
+/*
+ * Add rates TLV
+ *
+ * The rates are in lbs_bg_rates[], but for the 802.11b
+ * rates the high bit is set. We add this TLV only because
+ * there's a firmware which otherwise doesn't report all
+ * APs in range.
+ */
+#define LBS_MAX_RATES_TLV_SIZE                 \
+       (sizeof(struct mrvl_ie_header)          \
+        + (ARRAY_SIZE(lbs_rates)))
+
+/* Adds a TLV with all rates the hardware supports */
+static int lbs_add_supported_rates_tlv(u8 *tlv)
+{
+       size_t i;
+       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+
+       /*
+        * TLV-ID RATES  01 00
+        * length        0e 00
+        * rates         82 84 8b 96 0c 12 18 24 30 48 60 6c
+        */
+       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+       tlv += sizeof(rate_tlv->header);
+       i = lbs_add_rates(tlv);
+       tlv += i;
+       rate_tlv->header.len = cpu_to_le16(i);
+       return sizeof(rate_tlv->header) + i;
+}
+
+
+/*
+ * Adds a TLV with all rates the hardware *and* BSS supports.
+ */
+static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
+{
+       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+       const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+       int n;
+
+       /*
+        * 01 00                   TLV_TYPE_RATES
+        * 04 00                   len
+        * 82 84 8b 96             rates
+        */
+       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+       tlv += sizeof(rate_tlv->header);
+
+       if (!rates_eid) {
+               /* Fallback: add basic 802.11b rates */
+               *tlv++ = 0x82;
+               *tlv++ = 0x84;
+               *tlv++ = 0x8b;
+               *tlv++ = 0x96;
+               n = 4;
+       } else {
+               int hw, ap;
+               u8 ap_max = rates_eid[1];
+               n = 0;
+               for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+                       u8 hw_rate = lbs_rates[hw].bitrate / 5;
+                       for (ap = 0; ap < ap_max; ap++) {
+                               if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
+                                       *tlv++ = rates_eid[ap+2];
+                                       n++;
+                               }
+                       }
+               }
+       }
+
+       rate_tlv->header.len = cpu_to_le16(n);
+       return sizeof(rate_tlv->header) + n;
+}
+
+
+/*
+ * Add auth type TLV.
+ *
+ * This is only needed for newer firmware (V9 and up).
+ */
+#define LBS_MAX_AUTH_TYPE_TLV_SIZE \
+       sizeof(struct mrvl_ie_auth_type)
+
+static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type)
+{
+       struct mrvl_ie_auth_type *auth = (void *) tlv;
+
+       /*
+        * 1f 01  TLV_TYPE_AUTH_TYPE
+        * 01 00  len
+        * 01     auth type
+        */
+       auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+       auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header));
+       auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type));
+       return sizeof(*auth);
+}
+
+
+/*
+ * Add channel (phy ds) TLV
+ */
+#define LBS_MAX_CHANNEL_TLV_SIZE \
+       sizeof(struct mrvl_ie_header)
+
+static int lbs_add_channel_tlv(u8 *tlv, u8 channel)
+{
+       struct mrvl_ie_ds_param_set *ds = (void *) tlv;
+
+       /*
+        * 03 00  TLV_TYPE_PHY_DS
+        * 01 00  len
+        * 06     channel
+        */
+       ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+       ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header));
+       ds->channel = channel;
+       return sizeof(*ds);
+}
+
+
+/*
+ * Add (empty) CF param TLV of the form:
+ */
+#define LBS_MAX_CF_PARAM_TLV_SIZE              \
+       sizeof(struct mrvl_ie_header)
+
+static int lbs_add_cf_param_tlv(u8 *tlv)
+{
+       struct mrvl_ie_cf_param_set *cf = (void *)tlv;
+
+       /*
+        * 04 00  TLV_TYPE_CF
+        * 06 00  len
+        * 00     cfpcnt
+        * 00     cfpperiod
+        * 00 00  cfpmaxduration
+        * 00 00  cfpdurationremaining
+        */
+       cf->header.type = cpu_to_le16(TLV_TYPE_CF);
+       cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header));
+       return sizeof(*cf);
+}
+
+/*
+ * Add WPA TLV
+ */
+#define LBS_MAX_WPA_TLV_SIZE                   \
+       (sizeof(struct mrvl_ie_header)          \
+        + 128 /* TODO: I guessed the size */)
+
+static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
+{
+       size_t tlv_len;
+
+       /*
+        * We need just convert an IE to an TLV. IEs use u8 for the header,
+        *   u8      type
+        *   u8      len
+        *   u8[]    data
+        * but TLVs use __le16 instead:
+        *   __le16  type
+        *   __le16  len
+        *   u8[]    data
+        */
+       *tlv++ = *ie++;
+       *tlv++ = 0;
+       tlv_len = *tlv++ = *ie++;
+       *tlv++ = 0;
+       while (tlv_len--)
+               *tlv++ = *ie++;
+       /* the TLV is two bytes larger than the IE */
+       return ie_len + 2;
+}
+
+/***************************************************************************
+ * Set Channel
+ */
+
 static int lbs_cfg_set_channel(struct wiphy *wiphy,
        struct net_device *netdev,
-       struct ieee80211_channel *chan,
+       struct ieee80211_channel *channel,
        enum nl80211_channel_type channel_type)
 {
        struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = -ENOTSUPP;
+       int ret = -ENOTSUPP;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+                          channel->center_freq, channel_type);
+
+       if (channel_type != NL80211_CHAN_NO_HT)
+               goto out;
+
+       ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+/***************************************************************************
+ * Scanning
+ */
+
+/*
+ * When scanning, the firmware doesn't send a nul packet with the power-safe
+ * bit to the AP. So we cannot stay away from our current channel too long,
+ * otherwise we loose data. So take a "nap" while scanning every other
+ * while.
+ */
+#define LBS_SCAN_BEFORE_NAP 4
+
+
+/*
+ * When the firmware reports back a scan-result, it gives us an "u8 rssi",
+ * which isn't really an RSSI, as it becomes larger when moving away from
+ * the AP. Anyway, we need to convert that into mBm.
+ */
+#define LBS_SCAN_RSSI_TO_MBM(rssi) \
+       ((-(int)rssi + 3)*100)
+
+static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
+       struct cmd_header *resp)
+{
+       struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
+       int bsssize;
+       const u8 *pos;
+       u16 nr_sets;
+       const u8 *tsfdesc;
+       int tsfsize;
+       int i;
+       int ret = -EILSEQ;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
+       nr_sets = le16_to_cpu(resp->size);
+
+       /*
+        * The general layout of the scan response is described in chapter
+        * 5.7.1. Basically we have a common part, then any number of BSS
+        * descriptor sections. Finally we have section with the same number
+        * of TSFs.
+        *
+        * cmd_ds_802_11_scan_rsp
+        *   cmd_header
+        *   pos_size
+        *   nr_sets
+        *   bssdesc 1
+        *     bssid
+        *     rssi
+        *     timestamp
+        *     intvl
+        *     capa
+        *     IEs
+        *   bssdesc 2
+        *   bssdesc n
+        *   MrvlIEtypes_TsfFimestamp_t
+        *     TSF for BSS 1
+        *     TSF for BSS 2
+        *     TSF for BSS n
+        */
+
+       pos = scanresp->bssdesc_and_tlvbuffer;
+
+       tsfdesc = pos + bsssize;
+       tsfsize = 4 + 8 * scanresp->nr_sets;
+
+       /* Validity check: we expect a Marvell-Local TLV */
+       i = get_unaligned_le16(tsfdesc);
+       tsfdesc += 2;
+       if (i != TLV_TYPE_TSFTIMESTAMP)
+               goto done;
+       /* Validity check: the TLV holds TSF values with 8 bytes each, so
+        * the size in the TLV must match the nr_sets value */
+       i = get_unaligned_le16(tsfdesc);
+       tsfdesc += 2;
+       if (i / 8 != scanresp->nr_sets)
+               goto done;
+
+       for (i = 0; i < scanresp->nr_sets; i++) {
+               const u8 *bssid;
+               const u8 *ie;
+               int left;
+               int ielen;
+               int rssi;
+               u16 intvl;
+               u16 capa;
+               int chan_no = -1;
+               const u8 *ssid = NULL;
+               u8 ssid_len = 0;
+               DECLARE_SSID_BUF(ssid_buf);
+
+               int len = get_unaligned_le16(pos);
+               pos += 2;
+
+               /* BSSID */
+               bssid = pos;
+               pos += ETH_ALEN;
+               /* RSSI */
+               rssi = *pos++;
+               /* Packet time stamp */
+               pos += 8;
+               /* Beacon interval */
+               intvl = get_unaligned_le16(pos);
+               pos += 2;
+               /* Capabilities */
+               capa = get_unaligned_le16(pos);
+               pos += 2;
+
+               /* To find out the channel, we must parse the IEs */
+               ie = pos;
+               /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
+                  interval, capabilities */
+               ielen = left = len - (6 + 1 + 8 + 2 + 2);
+               while (left >= 2) {
+                       u8 id, elen;
+                       id = *pos++;
+                       elen = *pos++;
+                       left -= 2;
+                       if (elen > left || elen == 0)
+                               goto done;
+                       if (id == WLAN_EID_DS_PARAMS)
+                               chan_no = *pos;
+                       if (id == WLAN_EID_SSID) {
+                               ssid = pos;
+                               ssid_len = elen;
+                       }
+                       left -= elen;
+                       pos += elen;
+               }
+
+               /* No channel, no luck */
+               if (chan_no != -1) {
+                       struct wiphy *wiphy = priv->wdev->wiphy;
+                       int freq = ieee80211_channel_to_frequency(chan_no);
+                       struct ieee80211_channel *channel =
+                               ieee80211_get_channel(wiphy, freq);
+
+                       lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
+                                    "%d dBm\n",
+                                    bssid, capa, chan_no,
+                                    print_ssid(ssid_buf, ssid, ssid_len),
+                                    LBS_SCAN_RSSI_TO_MBM(rssi)/100);
+
+                       if (channel ||
+                           !(channel->flags & IEEE80211_CHAN_DISABLED))
+                               cfg80211_inform_bss(wiphy, channel,
+                                       bssid, le64_to_cpu(*(__le64 *)tsfdesc),
+                                       capa, intvl, ie, ielen,
+                                       LBS_SCAN_RSSI_TO_MBM(rssi),
+                                       GFP_KERNEL);
+               }
+               tsfdesc += 8;
+       }
+       ret = 0;
+
+ done:
+       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+       return ret;
+}
+
+
+/*
+ * Our scan command contains a TLV, consting of a SSID TLV, a channel list
+ * TLV and a rates TLV. Determine the maximum size of them:
+ */
+#define LBS_SCAN_MAX_CMD_SIZE                  \
+       (sizeof(struct cmd_ds_802_11_scan)      \
+        + LBS_MAX_SSID_TLV_SIZE                \
+        + LBS_MAX_CHANNEL_LIST_TLV_SIZE        \
+        + LBS_MAX_RATES_TLV_SIZE)
+
+/*
+ * Assumes priv->scan_req is initialized and valid
+ * Assumes priv->scan_channel is initialized
+ */
+static void lbs_scan_worker(struct work_struct *work)
+{
+       struct lbs_private *priv =
+               container_of(work, struct lbs_private, scan_work.work);
+       struct cmd_ds_802_11_scan *scan_cmd;
+       u8 *tlv; /* pointer into our current, growing TLV storage area */
+       int last_channel;
+       int running, carrier;
+
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
+       if (scan_cmd == NULL)
+               goto out_no_scan_cmd;
+
+       /* prepare fixed part of scan command */
+       scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
+
+       /* stop network while we're away from our main channel */
+       running = !netif_queue_stopped(priv->dev);
+       carrier = netif_carrier_ok(priv->dev);
+       if (running)
+               netif_stop_queue(priv->dev);
+       if (carrier)
+               netif_carrier_off(priv->dev);
+
+       /* prepare fixed part of scan command */
+       tlv = scan_cmd->tlvbuffer;
+
+       /* add SSID TLV */
+       if (priv->scan_req->n_ssids)
+               tlv += lbs_add_ssid_tlv(tlv,
+                                       priv->scan_req->ssids[0].ssid,
+                                       priv->scan_req->ssids[0].ssid_len);
+
+       /* add channel TLVs */
+       last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP;
+       if (last_channel > priv->scan_req->n_channels)
+               last_channel = priv->scan_req->n_channels;
+       tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel,
+               priv->scan_req->n_ssids);
+
+       /* add rates TLV */
+       tlv += lbs_add_supported_rates_tlv(tlv);
+
+       if (priv->scan_channel < priv->scan_req->n_channels) {
+               cancel_delayed_work(&priv->scan_work);
+               queue_delayed_work(priv->work_thread, &priv->scan_work,
+                       msecs_to_jiffies(300));
+       }
+
+       /* This is the final data we are about to send */
+       scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd);
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
+                   sizeof(*scan_cmd));
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
+                   tlv - scan_cmd->tlvbuffer);
+
+       __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
+               le16_to_cpu(scan_cmd->hdr.size),
+               lbs_ret_scan, 0);
+
+       if (priv->scan_channel >= priv->scan_req->n_channels) {
+               /* Mark scan done */
+               cfg80211_scan_done(priv->scan_req, false);
+               priv->scan_req = NULL;
+       }
+
+       /* Restart network */
+       if (carrier)
+               netif_carrier_on(priv->dev);
+       if (running && !priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       kfree(scan_cmd);
+
+ out_no_scan_cmd:
+       lbs_deb_leave(LBS_DEB_SCAN);
+}
+
+
+static int lbs_cfg_scan(struct wiphy *wiphy,
+       struct net_device *dev,
+       struct cfg80211_scan_request *request)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
+               /* old scan request not yet processed */
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
+               request->n_ssids, request->n_channels, request->ie_len);
+
+       priv->scan_channel = 0;
+       queue_delayed_work(priv->work_thread, &priv->scan_work,
+               msecs_to_jiffies(50));
+
+       if (priv->surpriseremoved)
+               ret = -EIO;
+
+       priv->scan_req = request;
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Events
+ */
+
+void lbs_send_disconnect_notification(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       cfg80211_disconnected(priv->dev,
+               0,
+               NULL, 0,
+               GFP_KERNEL);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       cfg80211_michael_mic_failure(priv->dev,
+               priv->assoc_bss,
+               event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
+                       NL80211_KEYTYPE_GROUP :
+                       NL80211_KEYTYPE_PAIRWISE,
+               -1,
+               NULL,
+               GFP_KERNEL);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
+
+
+/***************************************************************************
+ * Connect/disconnect
+ */
+
+
+/*
+ * This removes all WEP keys
+ */
+static int lbs_remove_wep_keys(struct lbs_private *priv)
+{
+       struct cmd_ds_802_11_set_wep cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+       cmd.action = cpu_to_le16(CMD_ACT_REMOVE);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+/*
+ * Set WEP keys
+ */
+static int lbs_set_wep_keys(struct lbs_private *priv)
+{
+       struct cmd_ds_802_11_set_wep cmd;
+       int i;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * command         13 00
+        * size            50 00
+        * sequence        xx xx
+        * result          00 00
+        * action          02 00     ACT_ADD
+        * transmit key    00 00
+        * type for key 1  01        WEP40
+        * type for key 2  00
+        * type for key 3  00
+        * type for key 4  00
+        * key 1           39 39 39 39 39 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * key 2           00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * key 3           00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * key 4           00 00 00 00 00 00 00 00
+        */
+       if (priv->wep_key_len[0] || priv->wep_key_len[1] ||
+           priv->wep_key_len[2] || priv->wep_key_len[3]) {
+               /* Only set wep keys if we have at least one of them */
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+               cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+               cmd.action = cpu_to_le16(CMD_ACT_ADD);
+
+               for (i = 0; i < 4; i++) {
+                       switch (priv->wep_key_len[i]) {
+                       case WLAN_KEY_LEN_WEP40:
+                               cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+                               break;
+                       case WLAN_KEY_LEN_WEP104:
+                               cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+                               break;
+                       default:
+                               cmd.keytype[i] = 0;
+                               break;
+                       }
+                       memcpy(cmd.keymaterial[i], priv->wep_key[i],
+                              priv->wep_key_len[i]);
+               }
+
+               ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+       } else {
+               /* Otherwise remove all wep keys */
+               ret = lbs_remove_wep_keys(priv);
+       }
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+/*
+ * Enable/Disable RSN status
+ */
+static int lbs_enable_rsn(struct lbs_private *priv, int enable)
+{
+       struct cmd_ds_802_11_enable_rsn cmd;
+       int ret;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
+
+       /*
+        * cmd       2f 00
+        * size      0c 00
+        * sequence  xx xx
+        * result    00 00
+        * action    01 00    ACT_SET
+        * enable    01 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.enable = cpu_to_le16(enable);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+/*
+ * Set WPA/WPA key material
+ */
+
+/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h */
+
+struct cmd_key_material {
+       struct cmd_header hdr;
+
+       __le16 action;
+       struct MrvlIEtype_keyParamSet param;
+} __attribute__ ((packed));
+
+static int lbs_set_key_material(struct lbs_private *priv,
+                               int key_type,
+                               int key_info,
+                               u8 *key, u16 key_len)
+{
+       struct cmd_key_material cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * Example for WPA (TKIP):
+        *
+        * cmd       5e 00
+        * size      34 00
+        * sequence  xx xx
+        * result    00 00
+        * action    01 00
+        * TLV type  00 01    key param
+        * length    00 26
+        * key type  01 00    TKIP
+        * key info  06 00    UNICAST | ENABLED
+        * key len   20 00
+        * key       32 bytes
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+       cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4);
+       cmd.param.keytypeid = cpu_to_le16(key_type);
+       cmd.param.keyinfo = cpu_to_le16(key_info);
+       cmd.param.keylen = cpu_to_le16(key_len);
+       if (key && key_len)
+               memcpy(cmd.param.key, key, key_len);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+/*
+ * Sets the auth type (open, shared, etc) in the firmware. That
+ * we use CMD_802_11_AUTHENTICATE is misleading, this firmware
+ * command doesn't send an authentication frame at all, it just
+ * stores the auth_type.
+ */
+static int lbs_set_authtype(struct lbs_private *priv,
+                           struct cfg80211_connect_params *sme)
+{
+       struct cmd_ds_802_11_authenticate cmd;
+       int ret;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
+
+       /*
+        * cmd        11 00
+        * size       19 00
+        * sequence   xx xx
+        * result     00 00
+        * BSS id     00 13 19 80 da 30
+        * auth type  00
+        * reserved   00 00 00 00 00 00 00 00 00 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       if (sme->bssid)
+               memcpy(cmd.bssid, sme->bssid, ETH_ALEN);
+       /* convert auth_type */
+       ret = lbs_auth_to_authtype(sme->auth_type);
+       if (ret < 0)
+               goto done;
+
+       cmd.authtype = ret;
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
+
+ done:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+/*
+ * Create association request
+ */
+#define LBS_ASSOC_MAX_CMD_SIZE                     \
+       (sizeof(struct cmd_ds_802_11_associate)    \
+        - 512 /* cmd_ds_802_11_associate.iebuf */ \
+        + LBS_MAX_SSID_TLV_SIZE                   \
+        + LBS_MAX_CHANNEL_TLV_SIZE                \
+        + LBS_MAX_CF_PARAM_TLV_SIZE               \
+        + LBS_MAX_AUTH_TYPE_TLV_SIZE              \
+        + LBS_MAX_WPA_TLV_SIZE)
+
+static int lbs_associate(struct lbs_private *priv,
+               struct cfg80211_bss *bss,
+               struct cfg80211_connect_params *sme)
+{
+       struct cmd_ds_802_11_associate_response *resp;
+       struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE,
+                                                     GFP_KERNEL);
+       const u8 *ssid_eid;
+       size_t len, resp_ie_len;
+       int status;
+       int ret;
+       u8 *pos = &(cmd->iebuf[0]);
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       /*
+        * cmd              50 00
+        * length           34 00
+        * sequence         xx xx
+        * result           00 00
+        * BSS id           00 13 19 80 da 30
+        * capabilities     11 00
+        * listen interval  0a 00
+        * beacon interval  00 00
+        * DTIM period      00
+        * TLVs             xx   (up to 512 bytes)
+        */
+       cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE);
+
+       /* Fill in static fields */
+       memcpy(cmd->bssid, bss->bssid, ETH_ALEN);
+       cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+       cmd->capability = cpu_to_le16(bss->capability);
+
+       /* add SSID TLV */
+       ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
+       if (ssid_eid)
+               pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
+       else
+               lbs_deb_assoc("no SSID\n");
+
+       /* add DS param TLV */
+       if (bss->channel)
+               pos += lbs_add_channel_tlv(pos, bss->channel->hw_value);
+       else
+               lbs_deb_assoc("no channel\n");
+
+       /* add (empty) CF param TLV */
+       pos += lbs_add_cf_param_tlv(pos);
+
+       /* add rates TLV */
+       pos += lbs_add_common_rates_tlv(pos, bss);
+
+       /* add auth type TLV */
+       if (priv->fwrelease >= 0x09000000)
+               pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
+
+       /* add WPA/WPA2 TLV */
+       if (sme->ie && sme->ie_len)
+               pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len);
+
+       len = (sizeof(*cmd) - sizeof(cmd->iebuf)) +
+               (u16)(pos - (u8 *) &cmd->iebuf);
+       cmd->hdr.size = cpu_to_le16(len);
+
+       /* store for later use */
+       memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd);
+       if (ret)
+               goto done;
+
+
+       /* generate connect message to cfg80211 */
+
+       resp = (void *) cmd; /* recast for easier field access */
+       status = le16_to_cpu(resp->statuscode);
+
+       /* Convert statis code of old firmware */
+       if (priv->fwrelease < 0x09000000)
+               switch (status) {
+               case 0:
+                       break;
+               case 1:
+                       lbs_deb_assoc("invalid association parameters\n");
+                       status = WLAN_STATUS_CAPS_UNSUPPORTED;
+                       break;
+               case 2:
+                       lbs_deb_assoc("timer expired while waiting for AP\n");
+                       status = WLAN_STATUS_AUTH_TIMEOUT;
+                       break;
+               case 3:
+                       lbs_deb_assoc("association refused by AP\n");
+                       status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+                       break;
+               case 4:
+                       lbs_deb_assoc("authentication refused by AP\n");
+                       status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+                       break;
+               default:
+                       lbs_deb_assoc("association failure %d\n", status);
+                       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       lbs_deb_assoc("status %d, capability 0x%04x\n", status,
+                     le16_to_cpu(resp->capability));
+
+       resp_ie_len = le16_to_cpu(resp->hdr.size)
+               - sizeof(resp->hdr)
+               - 6;
+       cfg80211_connect_result(priv->dev,
+                               priv->assoc_bss,
+                               sme->ie, sme->ie_len,
+                               resp->iebuf, resp_ie_len,
+                               status,
+                               GFP_KERNEL);
+
+       if (status == 0) {
+               /* TODO: get rid of priv->connect_status */
+               priv->connect_status = LBS_CONNECTED;
+               netif_carrier_on(priv->dev);
+               if (!priv->tx_pending_len)
+                       netif_tx_wake_all_queues(priv->dev);
+       }
+
+
+done:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
+                          struct cfg80211_connect_params *sme)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       struct cfg80211_bss *bss = NULL;
+       int ret = 0;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (sme->bssid) {
+               bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
+                       sme->ssid, sme->ssid_len,
+                       WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       } else {
+               /*
+                * Here we have an impedance mismatch. The firmware command
+                * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot
+                * connect otherwise. However, for the connect-API of
+                * cfg80211 the bssid is purely optional. We don't get one,
+                * except the user specifies one on the "iw" command line.
+                *
+                * If we don't got one, we could initiate a scan and look
+                * for the best matching cfg80211_bss entry.
+                *
+                * Or, better yet, net/wireless/sme.c get's rewritten into
+                * something more generally useful.
+                */
+               lbs_pr_err("TODO: no BSS specified\n");
+               ret = -ENOTSUPP;
+               goto done;
+       }
+
+
+       if (!bss) {
+               lbs_pr_err("assicate: bss %pM not in scan results\n",
+                          sme->bssid);
+               ret = -ENOENT;
+               goto done;
+       }
+       lbs_deb_assoc("trying %pM", sme->bssid);
+       lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
+                     sme->crypto.cipher_group,
+                     sme->key_idx, sme->key_len);
+
+       /* As this is a new connection, clear locally stored WEP keys */
+       priv->wep_tx_key = 0;
+       memset(priv->wep_key, 0, sizeof(priv->wep_key));
+       memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
+
+       /* set/remove WEP keys */
+       switch (sme->crypto.cipher_group) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               /* Store provided WEP keys in priv-> */
+               priv->wep_tx_key = sme->key_idx;
+               priv->wep_key_len[sme->key_idx] = sme->key_len;
+               memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len);
+               /* Set WEP keys and WEP mode */
+               lbs_set_wep_keys(priv);
+               priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
+               lbs_set_mac_control(priv);
+               /* No RSN mode for WEP */
+               lbs_enable_rsn(priv, 0);
+               break;
+       case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */
+               /*
+                * If we don't have no WEP, no WPA and no WPA2,
+                * we remove all keys like in the WPA/WPA2 setup,
+                * we just don't set RSN.
+                *
+                * Therefore: fall-throught
+                */
+       case WLAN_CIPHER_SUITE_TKIP:
+       case WLAN_CIPHER_SUITE_CCMP:
+               /* Remove WEP keys and WEP mode */
+               lbs_remove_wep_keys(priv);
+               priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
+               lbs_set_mac_control(priv);
+
+               /* clear the WPA/WPA2 keys */
+               lbs_set_key_material(priv,
+                       KEY_TYPE_ID_WEP, /* doesn't matter */
+                       KEY_INFO_WPA_UNICAST,
+                       NULL, 0);
+               lbs_set_key_material(priv,
+                       KEY_TYPE_ID_WEP, /* doesn't matter */
+                       KEY_INFO_WPA_MCAST,
+                       NULL, 0);
+               /* RSN mode for WPA/WPA2 */
+               lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
+               break;
+       default:
+               lbs_pr_err("unsupported cipher group 0x%x\n",
+                          sme->crypto.cipher_group);
+               ret = -ENOTSUPP;
+               goto done;
+       }
+
+       lbs_set_authtype(priv, sme);
+       lbs_set_radio(priv, preamble, 1);
+
+       /* Do the actual association */
+       lbs_associate(priv, bss, sme);
+
+ done:
+       if (bss)
+               cfg80211_put_bss(bss);
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+       u16 reason_code)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       struct cmd_ds_802_11_deauthenticate cmd;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+       /* store for lbs_cfg_ret_disconnect() */
+       priv->disassoc_reason = reason_code;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       /* Mildly ugly to use a locally store my own BSSID ... */
+       memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
+       cmd.reasoncode = cpu_to_le16(reason_code);
+
+       if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd))
+               return -EFAULT;
+
+       cfg80211_disconnected(priv->dev,
+                       priv->disassoc_reason,
+                       NULL, 0,
+                       GFP_KERNEL);
+       priv->connect_status = LBS_DISCONNECTED;
+
+       return 0;
+}
+
+
+static int lbs_cfg_set_default_key(struct wiphy *wiphy,
+                                  struct net_device *netdev,
+                                  u8 key_index)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (key_index != priv->wep_tx_key) {
+               lbs_deb_assoc("set_default_key: to %d\n", key_index);
+               priv->wep_tx_key = key_index;
+               lbs_set_wep_keys(priv);
+       }
+
+       return 0;
+}
+
+
+static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 idx, const u8 *mac_addr,
+                          struct key_params *params)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       u16 key_info;
+       u16 key_type;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
+                     params->cipher, mac_addr);
+       lbs_deb_assoc("add_key: key index %d, key len %d\n",
+                     idx, params->key_len);
+       if (params->key_len)
+               lbs_deb_hex(LBS_DEB_CFG80211, "KEY",
+                           params->key, params->key_len);
+
+       lbs_deb_assoc("add_key: seq len %d\n", params->seq_len);
+       if (params->seq_len)
+               lbs_deb_hex(LBS_DEB_CFG80211, "SEQ",
+                           params->seq, params->seq_len);
+
+       switch (params->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               /* actually compare if something has changed ... */
+               if ((priv->wep_key_len[idx] != params->key_len) ||
+                       memcmp(priv->wep_key[idx],
+                              params->key, params->key_len) != 0) {
+                       priv->wep_key_len[idx] = params->key_len;
+                       memcpy(priv->wep_key[idx],
+                              params->key, params->key_len);
+                       lbs_set_wep_keys(priv);
+               }
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+       case WLAN_CIPHER_SUITE_CCMP:
+               key_info = KEY_INFO_WPA_ENABLED | ((idx == 0)
+                                                  ? KEY_INFO_WPA_UNICAST
+                                                  : KEY_INFO_WPA_MCAST);
+               key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+                       ? KEY_TYPE_ID_TKIP
+                       : KEY_TYPE_ID_AES;
+               lbs_set_key_material(priv,
+                                    key_type,
+                                    key_info,
+                                    params->key, params->key_len);
+               break;
+       default:
+               lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
+               ret = -ENOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+
+
+static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
+                          u8 key_index, const u8 *mac_addr)
+{
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
+                     key_index, mac_addr);
+
+#ifdef TODO
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       /*
+        * I think can keep this a NO-OP, because:
 
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type);
+        * - we clear all keys whenever we do lbs_cfg_connect() anyway
+        * - neither "iw" nor "wpa_supplicant" won't call this during
+        *   an ongoing connection
+        * - TODO: but I have to check if this is still true when
+        *   I set the AP to periodic re-keying
+        * - we've not kzallec() something when we've added a key at
+        *   lbs_cfg_connect() or lbs_cfg_add_key().
+        *
+        * This causes lbs_cfg_del_key() only called at disconnect time,
+        * where we'd just waste time deleting a key that is not going
+        * to be used anyway.
+        */
+       if (key_index < 3 && priv->wep_key_len[key_index]) {
+               priv->wep_key_len[key_index] = 0;
+               lbs_set_wep_keys(priv);
+       }
+#endif
 
-       if (channel_type != NL80211_CHAN_NO_HT)
+       return 0;
+}
+
+
+
+/***************************************************************************
+ * Monitor mode
+ */
+
+/* like "struct cmd_ds_802_11_monitor_mode", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h */
+struct cmd_monitor_mode {
+       struct cmd_header hdr;
+
+       __le16 action;
+       __le16 mode;
+} __attribute__ ((packed));
+
+static int lbs_enable_monitor_mode(struct lbs_private *priv, int mode)
+{
+       struct cmd_monitor_mode cmd;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * cmd       98 00
+        * size      0c 00
+        * sequence  xx xx
+        * result    00 00
+        * action    01 00    ACT_SET
+        * enable    01 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.mode = cpu_to_le16(mode);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
+
+       if (ret == 0)
+               priv->dev->type = ARPHRD_IEEE80211_RADIOTAP;
+       else
+               priv->dev->type = ARPHRD_ETHER;
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+       return ret;
+}
+
+
+
+
+
+
+/***************************************************************************
+ * Get station
+ */
+
+/*
+ * Returns the signal or 0 in case of an error.
+ */
+
+/* like "struct cmd_ds_802_11_rssi", but with cmd_header. Once we get rid
+ * of WEXT, this should go into host.h */
+struct cmd_rssi {
+       struct cmd_header hdr;
+
+       __le16 n_or_snr;
+       __le16 nf;
+       __le16 avg_snr;
+       __le16 avg_nf;
+} __attribute__ ((packed));
+
+static int lbs_get_signal(struct lbs_private *priv, s8 *signal, s8 *noise)
+{
+       struct cmd_rssi cmd;
+       int ret;
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.n_or_snr = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
+
+       if (ret == 0) {
+               *signal = CAL_RSSI(le16_to_cpu(cmd.n_or_snr),
+                               le16_to_cpu(cmd.nf));
+               *noise  = CAL_NF(le16_to_cpu(cmd.nf));
+       }
+       return ret;
+}
+
+
+static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
+                             u8 *mac, struct station_info *sinfo)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       s8 signal, noise;
+       int ret;
+       size_t i;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       sinfo->filled |= STATION_INFO_TX_BYTES |
+                        STATION_INFO_TX_PACKETS |
+                        STATION_INFO_RX_BYTES |
+                        STATION_INFO_RX_PACKETS;
+       sinfo->tx_bytes = priv->dev->stats.tx_bytes;
+       sinfo->tx_packets = priv->dev->stats.tx_packets;
+       sinfo->rx_bytes = priv->dev->stats.rx_bytes;
+       sinfo->rx_packets = priv->dev->stats.rx_packets;
+
+       /* Get current RSSI */
+       ret = lbs_get_signal(priv, &signal, &noise);
+       if (ret == 0) {
+               sinfo->signal = signal;
+               sinfo->filled |= STATION_INFO_SIGNAL;
+       }
+
+       /* Convert priv->cur_rate from hw_value to NL80211 value */
+       for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+               if (priv->cur_rate == lbs_rates[i].hw_value) {
+                       sinfo->txrate.legacy = lbs_rates[i].bitrate;
+                       sinfo->filled |= STATION_INFO_TX_BITRATE;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+
+
+
+/***************************************************************************
+ * "Site survey", here just current channel and noise level
+ */
+
+static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
+       int idx, struct survey_info *survey)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       s8 signal, noise;
+       int ret;
+
+       if (idx != 0)
+               ret = -ENOENT;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       survey->channel = ieee80211_get_channel(wiphy,
+               ieee80211_channel_to_frequency(priv->channel));
+
+       ret = lbs_get_signal(priv, &signal, &noise);
+       if (ret == 0) {
+               survey->filled = SURVEY_INFO_NOISE_DBM;
+               survey->noise = noise;
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Change interface
+ */
+
+static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
+       enum nl80211_iftype type, u32 *flags,
+              struct vif_params *params)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       switch (type) {
+       case NL80211_IFTYPE_MONITOR:
+               ret = lbs_enable_monitor_mode(priv, 1);
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+                       ret = lbs_enable_monitor_mode(priv, 0);
+               if (!ret)
+                       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+                       ret = lbs_enable_monitor_mode(priv, 0);
+               if (!ret)
+                       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
+               break;
+       default:
+               ret = -ENOTSUPP;
+       }
+
+       if (!ret)
+               priv->wdev->iftype = type;
+
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+/***************************************************************************
+ * IBSS (Ad-Hoc)
+ */
+
+/* The firmware needs the following bits masked out of the beacon-derived
+ * capability field when associating/joining to a BSS:
+ *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
+ */
+#define CAPINFO_MASK (~(0xda00))
+
+
+static void lbs_join_post(struct lbs_private *priv,
+                         struct cfg80211_ibss_params *params,
+                         u8 *bssid, u16 capability)
+{
+       u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */
+                  2 + 4 +                      /* basic rates */
+                  2 + 1 +                      /* DS parameter */
+                  2 + 2 +                      /* atim */
+                  2 + 8];                      /* extended rates */
+       u8 *fake = fake_ie;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /*
+        * For cfg80211_inform_bss, we'll need a fake IE, as we can't get
+        * the real IE from the firmware. So we fabricate a fake IE based on
+        * what the firmware actually sends (sniffed with wireshark).
+        */
+       /* Fake SSID IE */
+       *fake++ = WLAN_EID_SSID;
+       *fake++ = params->ssid_len;
+       memcpy(fake, params->ssid, params->ssid_len);
+       fake += params->ssid_len;
+       /* Fake supported basic rates IE */
+       *fake++ = WLAN_EID_SUPP_RATES;
+       *fake++ = 4;
+       *fake++ = 0x82;
+       *fake++ = 0x84;
+       *fake++ = 0x8b;
+       *fake++ = 0x96;
+       /* Fake DS channel IE */
+       *fake++ = WLAN_EID_DS_PARAMS;
+       *fake++ = 1;
+       *fake++ = params->channel->hw_value;
+       /* Fake IBSS params IE */
+       *fake++ = WLAN_EID_IBSS_PARAMS;
+       *fake++ = 2;
+       *fake++ = 0; /* ATIM=0 */
+       *fake++ = 0;
+       /* Fake extended rates IE, TODO: don't add this for 802.11b only,
+        * but I don't know how this could be checked */
+       *fake++ = WLAN_EID_EXT_SUPP_RATES;
+       *fake++ = 8;
+       *fake++ = 0x0c;
+       *fake++ = 0x12;
+       *fake++ = 0x18;
+       *fake++ = 0x24;
+       *fake++ = 0x30;
+       *fake++ = 0x48;
+       *fake++ = 0x60;
+       *fake++ = 0x6c;
+       lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
+
+       cfg80211_inform_bss(priv->wdev->wiphy,
+                           params->channel,
+                           bssid,
+                           0,
+                           capability,
+                           params->beacon_interval,
+                           fake_ie, fake - fake_ie,
+                           0, GFP_KERNEL);
+
+       memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
+       priv->wdev->ssid_len = params->ssid_len;
+
+       cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+
+       /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
+       priv->connect_status = LBS_CONNECTED;
+       netif_carrier_on(priv->dev);
+       if (!priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+static int lbs_ibss_join_existing(struct lbs_private *priv,
+       struct cfg80211_ibss_params *params,
+       struct cfg80211_bss *bss)
+{
+       const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+       struct cmd_ds_802_11_ad_hoc_join cmd;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /* TODO: set preamble based on scan result */
+       ret = lbs_set_radio(priv, preamble, 1);
+       if (ret)
+               goto out;
+
+       /*
+        * Example CMD_802_11_AD_HOC_JOIN command:
+        *
+        * command         2c 00         CMD_802_11_AD_HOC_JOIN
+        * size            65 00
+        * sequence        xx xx
+        * result          00 00
+        * bssid           02 27 27 97 2f 96
+        * ssid            49 42 53 53 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * type            02            CMD_BSS_TYPE_IBSS
+        * beacon period   64 00
+        * dtim period     00
+        * timestamp       00 00 00 00 00 00 00 00
+        * localtime       00 00 00 00 00 00 00 00
+        * IE DS           03
+        * IE DS len       01
+        * IE DS channel   01
+        * reserveed       00 00 00 00
+        * IE IBSS         06
+        * IE IBSS len     02
+        * IE IBSS atim    00 00
+        * reserved        00 00 00 00
+        * capability      02 00
+        * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c 00
+        * fail timeout    ff 00
+        * probe delay     00 00
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+       memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN);
+       memcpy(cmd.bss.ssid, params->ssid, params->ssid_len);
+       cmd.bss.type = CMD_BSS_TYPE_IBSS;
+       cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
+       cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
+       cmd.bss.ds.header.len = 1;
+       cmd.bss.ds.channel = params->channel->hw_value;
+       cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+       cmd.bss.ibss.header.len = 2;
+       cmd.bss.ibss.atimwindow = 0;
+       cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+
+       /* set rates to the intersection of our rates and the rates in the
+          bss */
+       if (!rates_eid) {
+               lbs_add_rates(cmd.bss.rates);
+       } else {
+               int hw, i;
+               u8 rates_max = rates_eid[1];
+               u8 *rates = cmd.bss.rates;
+               for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+                       u8 hw_rate = lbs_rates[hw].bitrate / 5;
+                       for (i = 0; i < rates_max; i++) {
+                               if (hw_rate == (rates_eid[i+2] & 0x7f)) {
+                                       u8 rate = rates_eid[i+2];
+                                       if (rate == 0x02 || rate == 0x04 ||
+                                           rate == 0x0b || rate == 0x16)
+                                               rate |= 0x80;
+                                       *rates++ = rate;
+                               }
+                       }
+               }
+       }
+
+       /* Only v8 and below support setting this */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
+               cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+       }
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
+       if (ret)
+               goto out;
+
+       /*
+        * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+        *
+        * response        2c 80
+        * size            09 00
+        * sequence        xx xx
+        * result          00 00
+        * reserved        00
+        */
+       lbs_join_post(priv, params, bss->bssid, bss->capability);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
+static int lbs_ibss_start_new(struct lbs_private *priv,
+       struct cfg80211_ibss_params *params)
+{
+       struct cmd_ds_802_11_ad_hoc_start cmd;
+       struct cmd_ds_802_11_ad_hoc_result *resp =
+               (struct cmd_ds_802_11_ad_hoc_result *) &cmd;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
+       int ret = 0;
+       u16 capability;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       ret = lbs_set_radio(priv, preamble, 1);
+       if (ret)
                goto out;
 
-       ret = lbs_set_channel(priv, chan->hw_value);
+       /*
+        * Example CMD_802_11_AD_HOC_START command:
+        *
+        * command         2b 00         CMD_802_11_AD_HOC_START
+        * size            b1 00
+        * sequence        xx xx
+        * result          00 00
+        * ssid            54 45 53 54 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        *                 00 00 00 00 00 00 00 00
+        * bss type        02
+        * beacon period   64 00
+        * dtim period     00
+        * IE IBSS         06
+        * IE IBSS len     02
+        * IE IBSS atim    00 00
+        * reserved        00 00 00 00
+        * IE DS           03
+        * IE DS len       01
+        * IE DS channel   01
+        * reserved        00 00 00 00
+        * probe delay     00 00
+        * capability      02 00
+        * rates           82 84 8b 96   (basic rates with have bit 7 set)
+        *                 0c 12 18 24 30 48 60 6c
+        * padding         100 bytes
+        */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       memcpy(cmd.ssid, params->ssid, params->ssid_len);
+       cmd.bsstype = CMD_BSS_TYPE_IBSS;
+       cmd.beaconperiod = cpu_to_le16(params->beacon_interval);
+       cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+       cmd.ibss.header.len = 2;
+       cmd.ibss.atimwindow = 0;
+       cmd.ds.header.id = WLAN_EID_DS_PARAMS;
+       cmd.ds.header.len = 1;
+       cmd.ds.channel = params->channel->hw_value;
+       /* Only v8 and below support setting probe delay */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
+               cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+       /* TODO: mix in WLAN_CAPABILITY_PRIVACY */
+       capability = WLAN_CAPABILITY_IBSS;
+       cmd.capability = cpu_to_le16(capability);
+       lbs_add_rates(cmd.rates);
+
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
+       if (ret)
+               goto out;
+
+       /*
+        * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+        *
+        * response        2b 80
+        * size            14 00
+        * sequence        xx xx
+        * result          00 00
+        * reserved        00
+        * bssid           02 2b 7b 0f 86 0e
+        */
+       lbs_join_post(priv, params, resp->bssid, capability);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+               struct cfg80211_ibss_params *params)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = 0;
+       struct cfg80211_bss *bss;
+       DECLARE_SSID_BUF(ssid_buf);
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       if (!params->channel) {
+               ret = -ENOTSUPP;
+               goto out;
+       }
+
+       ret = lbs_set_channel(priv, params->channel->hw_value);
+       if (ret)
+               goto out;
+
+       /* Search if someone is beaconing. This assumes that the
+        * bss list is populated already */
+       bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
+               params->ssid, params->ssid_len,
+               WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+
+       if (bss) {
+               ret = lbs_ibss_join_existing(priv, params, bss);
+               cfg80211_put_bss(bss);
+       } else
+               ret = lbs_ibss_start_new(priv, params);
+
 
  out:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -99,10 +1906,45 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
 }
 
 
+static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       struct cmd_ds_802_11_ad_hoc_stop cmd;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
+
+       /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
+       lbs_mac_event_disconnected(priv);
+
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+
+
 
+/***************************************************************************
+ * Initialization
+ */
 
 static struct cfg80211_ops lbs_cfg80211_ops = {
        .set_channel = lbs_cfg_set_channel,
+       .scan = lbs_cfg_scan,
+       .connect = lbs_cfg_connect,
+       .disconnect = lbs_cfg_disconnect,
+       .add_key = lbs_cfg_add_key,
+       .del_key = lbs_cfg_del_key,
+       .set_default_key = lbs_cfg_set_default_key,
+       .get_station = lbs_cfg_get_station,
+       .dump_survey = lbs_get_survey,
+       .change_virtual_intf = lbs_change_intf,
+       .join_ibss = lbs_join_ibss,
+       .leave_ibss = lbs_leave_ibss,
 };
 
 
@@ -142,6 +1984,36 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
 }
 
 
+static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
+{
+       struct region_code_mapping {
+               const char *cn;
+               int code;
+       };
+
+       /* Section 5.17.2 */
+       static struct region_code_mapping regmap[] = {
+               {"US ", 0x10}, /* US FCC */
+               {"CA ", 0x20}, /* Canada */
+               {"EU ", 0x30}, /* ETSI   */
+               {"ES ", 0x31}, /* Spain  */
+               {"FR ", 0x32}, /* France */
+               {"JP ", 0x40}, /* Japan  */
+       };
+       size_t i;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       for (i = 0; i < ARRAY_SIZE(regmap); i++)
+               if (regmap[i].code == priv->regioncode) {
+                       regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
+                       break;
+               }
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
 /*
  * This function get's called after lbs_setup_firmware() determined the
  * firmware capabities. So we can setup the wiphy according to our
@@ -157,10 +2029,12 @@ int lbs_cfg_register(struct lbs_private *priv)
        wdev->wiphy->max_scan_ssids = 1;
        wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
-       /* TODO: BIT(NL80211_IFTYPE_ADHOC); */
-       wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       wdev->wiphy->interface_modes =
+                       BIT(NL80211_IFTYPE_STATION) |
+                       BIT(NL80211_IFTYPE_ADHOC);
+       if (lbs_rtap_supported(priv))
+               wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
 
-       /* TODO: honor priv->regioncode */
        wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
 
        /*
@@ -169,6 +2043,7 @@ int lbs_cfg_register(struct lbs_private *priv)
         */
        wdev->wiphy->cipher_suites = cipher_suites;
        wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+       wdev->wiphy->reg_notifier = lbs_reg_notifier;
 
        ret = wiphy_register(wdev->wiphy);
        if (ret < 0)
@@ -180,10 +2055,129 @@ int lbs_cfg_register(struct lbs_private *priv)
        if (ret)
                lbs_pr_err("cannot register network device\n");
 
+       INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+
+       lbs_cfg_set_regulatory_hint(priv);
+
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
        return ret;
 }
 
+/**
+ *  @brief This function sets DOMAIN INFO to FW
+ *  @param priv       pointer to struct lbs_private
+ *  @return          0; -1
+*/
+static int lbs_11d_set_domain_info(struct lbs_private *priv)
+{
+       int ret;
+
+       ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
+                       CMD_ACT_SET,
+                       CMD_OPTION_WAITFORRSP, 0, NULL);
+       if (ret)
+               lbs_deb_11d("fail to dnld domain info\n");
+
+       return ret;
+}
+
+static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy,
+                                       struct regulatory_request *request)
+{
+       u8   no_of_triplet = 0;
+       u8   no_of_parsed_chan = 0;
+       u8   first_channel = 0, next_chan = 0, max_pwr = 0;
+       u8   i, flag = 0;
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CFG80211);
+
+       /* Set country code */
+       domain_info->country_code[0] = request->alpha2[0];
+       domain_info->country_code[1] = request->alpha2[1];
+       domain_info->country_code[2] = ' ';
+
+       for (band = 0; band < IEEE80211_NUM_BANDS ; band++) {
+
+               if (!wiphy->bands[band])
+                       continue;
+
+               sband = wiphy->bands[band];
+
+               for (i = 0; i < sband->n_channels ; i++) {
+                       ch = &sband->channels[i];
+                       if (ch->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       if (!flag) {
+                               flag = 1;
+                               next_chan = first_channel = (u32) ch->hw_value;
+                               max_pwr = ch->max_power;
+                               no_of_parsed_chan = 1;
+                               continue;
+                       }
+
+                       if (ch->hw_value == next_chan + 1 &&
+                                       ch->max_power == max_pwr) {
+                               next_chan++;
+                               no_of_parsed_chan++;
+                       } else {
+                               domain_info->triplet[no_of_triplet]
+                                       .chans.first_channel = first_channel;
+                               domain_info->triplet[no_of_triplet]
+                                       .chans.num_channels = no_of_parsed_chan;
+                               domain_info->triplet[no_of_triplet]
+                                       .chans.max_power = max_pwr;
+                               no_of_triplet++;
+                               flag = 0;
+                       }
+               }
+               if (flag) {
+                       domain_info->triplet[no_of_triplet]
+                               .chans.first_channel = first_channel;
+                       domain_info->triplet[no_of_triplet]
+                               .chans.num_channels = no_of_parsed_chan;
+                       domain_info->triplet[no_of_triplet]
+                               .chans.max_power = max_pwr;
+                       no_of_triplet++;
+               }
+       }
+
+       domain_info->no_triplet = no_of_triplet;
+
+       /* Set domain info */
+       ret = lbs_11d_set_domain_info(priv);
+       if (ret)
+               lbs_pr_err("11D: error setting domain info in FW\n");
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+int lbs_reg_notifier(struct wiphy *wiphy,
+               struct regulatory_request *request)
+{
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+                       "callback for domain %c%c\n", request->alpha2[0],
+                       request->alpha2[1]);
+
+       lbs_send_domain_info_cmd_fw(wiphy, request);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+
+       return 0;
+}
+
+void lbs_scan_deinit(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_CFG80211);
+       cancel_delayed_work_sync(&priv->scan_work);
+}
+
 
 void lbs_cfg_free(struct lbs_private *priv)
 {
index e09a193a34d6ace048f3da6b8144f8cd9046a4a3..756fb98f9f057233d64f648264b669b69ee2df28 100644 (file)
@@ -1,16 +1,27 @@
 #ifndef __LBS_CFG80211_H__
 #define __LBS_CFG80211_H__
 
-#include "dev.h"
+struct device;
+struct lbs_private;
+struct regulatory_request;
+struct wiphy;
 
 struct wireless_dev *lbs_cfg_alloc(struct device *dev);
 int lbs_cfg_register(struct lbs_private *priv);
 void lbs_cfg_free(struct lbs_private *priv);
 
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
-       u8 ssid_len);
-int lbs_scan_networks(struct lbs_private *priv, int full_scan);
-void lbs_cfg_scan_worker(struct work_struct *work);
+int lbs_reg_notifier(struct wiphy *wiphy,
+               struct regulatory_request *request);
 
+/* All of those are TODOs: */
+#define lbs_cmd_802_11_rssi(priv, cmdptr) (0)
+#define lbs_ret_802_11_rssi(priv, resp) (0)
+#define lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action) (0)
+#define lbs_ret_802_11_bcn_ctrl(priv, resp) (0)
+
+void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
+void lbs_scan_deinit(struct lbs_private *priv);
 
 #endif
index 0fa6b0e59ea58238e2a8cc91e257462d6d1fc587..6c8a9d952a01b6f5ac1a5c531dde1c64f2b162ee 100644 (file)
@@ -7,13 +7,8 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-#include "host.h"
 #include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
-#include "scan.h"
+#include "cfg.h"
 #include "cmd.h"
 
 
@@ -177,11 +172,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
        if (priv->mesh_dev)
                memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
 
-       if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
-               ret = -1;
-               goto out;
-       }
-
 out:
        lbs_deb_leave(LBS_DEB_CMD);
        return ret;
@@ -908,6 +898,66 @@ void lbs_set_mac_control(struct lbs_private *priv)
        lbs_deb_leave(LBS_DEB_CMD);
 }
 
+/**
+ *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *  @param priv       pointer to struct lbs_private
+ *  @param cmd        pointer to cmd buffer
+ *  @param cmdno      cmd ID
+ *  @param cmdOption  cmd action
+ *  @return           0
+*/
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+                                struct cmd_ds_command *cmd,
+                                u16 cmdoption)
+{
+       struct cmd_ds_802_11d_domain_info *pdomaininfo =
+           &cmd->params.domaininfo;
+       struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
+       u8 nr_triplet = priv->domain_reg.no_triplet;
+
+       lbs_deb_enter(LBS_DEB_11D);
+
+       lbs_deb_11d("nr_triplet=%x\n", nr_triplet);
+
+       pdomaininfo->action = cpu_to_le16(cmdoption);
+       if (cmdoption == CMD_ACT_GET) {
+               cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+                                       sizeof(struct cmd_header));
+               lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
+                       le16_to_cpu(cmd->size));
+               goto done;
+       }
+
+       domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+       memcpy(domain->countrycode, priv->domain_reg.country_code,
+              sizeof(domain->countrycode));
+
+       domain->header.len = cpu_to_le16(nr_triplet
+                               * sizeof(struct ieee80211_country_ie_triplet)
+                               + sizeof(domain->countrycode));
+
+       if (nr_triplet) {
+               memcpy(domain->triplet, priv->domain_reg.triplet,
+                               nr_triplet *
+                               sizeof(struct ieee80211_country_ie_triplet));
+
+               cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+                                            le16_to_cpu(domain->header.len) +
+                                            sizeof(struct mrvl_ie_header) +
+                                            sizeof(struct cmd_header));
+       } else {
+               cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+                                       sizeof(struct cmd_header));
+       }
+
+       lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
+                       le16_to_cpu(cmd->size));
+
+done:
+       lbs_deb_enter(LBS_DEB_11D);
+       return 0;
+}
+
 /**
  *  @brief This function prepare the command before send to firmware.
  *
@@ -1006,6 +1056,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = 0;
                goto done;
 
+       case CMD_802_11D_DOMAIN_INFO:
+               cmdptr->command = cpu_to_le16(cmd_no);
+               ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
+               break;
+
        case CMD_802_11_TPC_CFG:
                cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
                cmdptr->size =
@@ -1325,6 +1380,15 @@ int lbs_execute_next_command(struct lbs_private *priv)
                 * check if in power save mode, if yes, put the device back
                 * to PS mode
                 */
+#ifdef TODO
+               /*
+                * This was the old code for libertas+wext. Someone that
+                * understands this beast should re-code it in a sane way.
+                *
+                * I actually don't understand why this is related to WPA
+                * and to connection status, shouldn't powering should be
+                * independ of such things?
+                */
                if ((priv->psmode != LBS802_11POWERMODECAM) &&
                    (priv->psstate == PS_STATE_FULL_POWER) &&
                    ((priv->connect_status == LBS_CONNECTED) ||
@@ -1346,6 +1410,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                lbs_ps_sleep(priv, 0);
                        }
                }
+#endif
        }
 
        ret = 0;
index d6c3063536403a66119d4f4ced1d4c336f11b8e4..a0d9482ef5e28351fe372933d7feb9c089e7228d 100644 (file)
@@ -5,18 +5,10 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/if_arp.h>
-#include <linux/netdevice.h>
 #include <asm/unaligned.h>
-#include <net/iw_handler.h>
+#include <net/cfg80211.h>
 
-#include "host.h"
-#include "decl.h"
-#include "cmd.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
+#include "cfg.h"
 #include "cmd.h"
 
 /**
@@ -39,7 +31,9 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
         * It causes problem in the Supplicant
         */
        msleep_interruptible(1000);
-       lbs_send_disconnect_notification(priv);
+
+       if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
+               lbs_send_disconnect_notification(priv);
 
        /* report disconnect to upper layer */
        netif_stop_queue(priv->dev);
@@ -50,23 +44,8 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
        priv->currenttxskb = NULL;
        priv->tx_pending_len = 0;
 
-       /* reset SNR/NF/RSSI values */
-       memset(priv->SNR, 0x00, sizeof(priv->SNR));
-       memset(priv->NF, 0x00, sizeof(priv->NF));
-       memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
-       memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
-       memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
-       priv->nextSNRNF = 0;
-       priv->numSNRNF = 0;
        priv->connect_status = LBS_DISCONNECTED;
 
-       /* Clear out associated SSID and BSSID since connection is
-        * no longer valid.
-        */
-       memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
-       memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
-       priv->curbssparams.ssid_len = 0;
-
        if (priv->psstate != PS_STATE_FULL_POWER) {
                /* make firmware to exit PS mode */
                lbs_deb_cmd("disconnected, so exit PS mode\n");
@@ -118,6 +97,52 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
        return ret;
 }
 
+/**
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to struct lbs_private
+ *  @param resp    pointer to command response buffer
+ *  @return        0; -1
+ */
+static int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11d_domain_info *domaininfo =
+                       &resp->params.domaininforesp;
+       struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
+       u16 action = le16_to_cpu(domaininfo->action);
+       s16 ret = 0;
+       u8 nr_triplet = 0;
+
+       lbs_deb_enter(LBS_DEB_11D);
+
+       lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
+                       (int)le16_to_cpu(resp->size));
+
+       nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
+               sizeof(struct ieee80211_country_ie_triplet);
+
+       lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet);
+
+       if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) {
+               lbs_deb_11d("invalid number of triplets returned!!\n");
+               return -1;
+       }
+
+       switch (action) {
+       case CMD_ACT_SET:       /*Proc set action */
+               break;
+
+       case CMD_ACT_GET:
+               break;
+       default:
+               lbs_deb_11d("invalid action:%d\n", domaininfo->action);
+               ret = -1;
+               break;
+       }
+
+       lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
+       return ret;
+}
+
 static inline int handle_cmd_response(struct lbs_private *priv,
                                      struct cmd_header *cmd_response)
 {
@@ -151,6 +176,10 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                ret = lbs_ret_802_11_rssi(priv, resp);
                break;
 
+       case CMD_RET(CMD_802_11D_DOMAIN_INFO):
+               ret = lbs_ret_802_11d_domain_info(resp);
+               break;
+
        case CMD_RET(CMD_802_11_TPC_CFG):
                spin_lock_irqsave(&priv->driver_lock, flags);
                memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
@@ -262,7 +291,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
                         * ad-hoc mode. It takes place in
                         * lbs_execute_next_command().
                         */
-                       if (priv->mode == IW_MODE_ADHOC &&
+                       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
                            action == CMD_SUBCMD_ENTER_PS)
                                priv->psmode = LBS802_11POWERMODECAM;
                } else if (action == CMD_SUBCMD_ENTER_PS) {
index de2caac11dd61a37cc9d0ee591db84616f825f33..17367463c8554451c757e78d92d692c2d67a0ec7 100644 (file)
@@ -1,18 +1,13 @@
-#include <linux/module.h>
 #include <linux/dcache.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
 
-#include "dev.h"
 #include "decl.h"
-#include "host.h"
-#include "debugfs.h"
 #include "cmd.h"
+#include "debugfs.h"
 
 static struct dentry *lbs_dir;
 static char *szStates[] = {
@@ -60,51 +55,6 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
        return res;
 }
 
-
-static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
-                                 size_t count, loff_t *ppos)
-{
-       struct lbs_private *priv = file->private_data;
-       size_t pos = 0;
-       int numscansdone = 0, res;
-       unsigned long addr = get_zeroed_page(GFP_KERNEL);
-       char *buf = (char *)addr;
-       DECLARE_SSID_BUF(ssid);
-       struct bss_descriptor * iter_bss;
-       if (!buf)
-               return -ENOMEM;
-
-       pos += snprintf(buf+pos, len-pos,
-               "# | ch  | rssi |       bssid       |   cap    | Qual | SSID\n");
-
-       mutex_lock(&priv->lock);
-       list_for_each_entry (iter_bss, &priv->network_list, list) {
-               u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
-               u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
-               u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
-
-               pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |",
-                       numscansdone, iter_bss->channel, iter_bss->rssi,
-                       iter_bss->bssid);
-               pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
-               pos += snprintf(buf+pos, len-pos, "%c%c%c |",
-                               ibss ? 'A' : 'I', privacy ? 'P' : ' ',
-                               spectrum_mgmt ? 'S' : ' ');
-               pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
-               pos += snprintf(buf+pos, len-pos, " %s\n",
-                               print_ssid(ssid, iter_bss->ssid,
-                                          iter_bss->ssid_len));
-
-               numscansdone++;
-       }
-       mutex_unlock(&priv->lock);
-
-       res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
-       free_page(addr);
-       return res;
-}
-
 static ssize_t lbs_sleepparams_write(struct file *file,
                                const char __user *user_buf, size_t count,
                                loff_t *ppos)
@@ -723,8 +673,6 @@ struct lbs_debugfs_files {
 
 static const struct lbs_debugfs_files debugfs_files[] = {
        { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
-       { "getscantable", 0444, FOPS(lbs_getscantable,
-                                       write_file_dummy), },
        { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
                                lbs_sleepparams_write), },
 };
index 61db8bc62b3c2d519d1859ee01027cd1e942f258..ba5438a7ba1713c3f6a5f40e54c697bb698858eb 100644 (file)
@@ -1,3 +1,4 @@
+
 /**
   *  This file contains declaration referring to
   *  functions defined in other source files
@@ -12,6 +13,7 @@
 struct lbs_private;
 struct sk_buff;
 struct net_device;
+struct cmd_ds_command;
 
 
 /* ethtool.c */
@@ -34,6 +36,8 @@ int lbs_start_card(struct lbs_private *priv);
 void lbs_stop_card(struct lbs_private *priv);
 void lbs_host_to_card_done(struct lbs_private *priv);
 
+int lbs_rtap_supported(struct lbs_private *priv);
+
 int lbs_set_mac_address(struct net_device *dev, void *addr);
 void lbs_set_multicast_list(struct net_device *dev);
 
@@ -49,5 +53,9 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
 
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
+               struct cmd_ds_command *cmd, u16 cmdoption);
+
+int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
 
 #endif
index 71c5ad46ebf6a5ca8627f52bb31a92e62811feb0..4536d9c0ad8725952ff94ff8172e7446e6b1ce75 100644 (file)
@@ -7,8 +7,8 @@
 #define _LBS_DEV_H_
 
 #include "mesh.h"
-#include "scan.h"
-#include "assoc.h"
+#include "defs.h"
+#include "host.h"
 
 #include <linux/kfifo.h>
 
@@ -29,7 +29,6 @@ struct lbs_private {
        /* Basic networking */
        struct net_device *dev;
        u32 connect_status;
-       int infra_open;
        struct work_struct mcast_work;
        u32 nr_of_multicastmacaddr;
        u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
@@ -37,6 +36,9 @@ struct lbs_private {
        /* CFG80211 */
        struct wireless_dev *wdev;
        bool wiphy_registered;
+       struct cfg80211_scan_request *scan_req;
+       u8 assoc_bss[ETH_ALEN];
+       u8 disassoc_reason;
 
        /* Mesh */
        struct net_device *mesh_dev; /* Virtual device */
@@ -49,10 +51,6 @@ struct lbs_private {
        u8 mesh_ssid_len;
 #endif
 
-       /* Monitor mode */
-       struct net_device *rtap_net_dev;
-       u32 monitormode;
-
        /* Debugfs */
        struct dentry *debugfs_dir;
        struct dentry *debugfs_debug;
@@ -62,6 +60,9 @@ struct lbs_private {
        struct dentry *regs_dir;
        struct dentry *debugfs_regs_files[6];
 
+       /** 11D and domain regulatory data */
+       struct lbs_802_11d_domain_reg domain_reg;
+
        /* Hardware debugging */
        u32 mac_offset;
        u32 bbp_offset;
@@ -133,14 +134,10 @@ struct lbs_private {
        struct workqueue_struct *work_thread;
 
        /** Encryption stuff */
-       struct lbs_802_11_security secinfo;
-       struct enc_key wpa_mcast_key;
-       struct enc_key wpa_unicast_key;
-       u8 wpa_ie[MAX_WPA_IE_LEN];
-       u8 wpa_ie_len;
-       u16 wep_tx_keyidx;
-       struct enc_key wep_keys[4];
        u8 authtype_auto;
+       u8 wep_tx_key;
+       u8 wep_key[4][WLAN_KEY_LEN_WEP104];
+       u8 wep_key_len[4];
 
        /* Wake On LAN */
        uint32_t wol_criteria;
@@ -161,6 +158,7 @@ struct lbs_private {
        /* NIC/link operation characteristics */
        u16 mac_control;
        u8 radio_on;
+       u8 cur_rate;
        u8 channel;
        s16 txpower_cur;
        s16 txpower_min;
@@ -169,42 +167,6 @@ struct lbs_private {
        /** Scanning */
        struct delayed_work scan_work;
        int scan_channel;
-       /* remember which channel was scanned last, != 0 if currently scanning */
-       u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 scan_ssid_len;
-
-       /* Associating */
-       struct delayed_work assoc_work;
-       struct current_bss_params curbssparams;
-       u8 mode;
-       struct list_head network_list;
-       struct list_head network_free_list;
-       struct bss_descriptor *networks;
-       struct assoc_request * pending_assoc_req;
-       struct assoc_request * in_progress_assoc_req;
-       uint16_t enablehwauto;
-
-       /* ADHOC */
-       u16 beacon_period;
-       u8 beacon_enable;
-       u8 adhoccreate;
-
-       /* WEXT */
-       char name[DEV_NAME_LEN];
-       u8 nodename[16];
-       struct iw_statistics wstats;
-       u8 cur_rate;
-#define        MAX_REGION_CHANNEL_NUM  2
-       struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
-
-       /** Requested Signal Strength*/
-       u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
-       u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
-       u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
-       u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
-       u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
-       u16 nextSNRNF;
-       u16 numSNRNF;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
index 0cf31bbf6567b52923245e9a3dfdf935a8d64f7d..50193aac679e81b5c0a157e933db006958fa4463 100644 (file)
@@ -2,13 +2,8 @@
 #include <linux/ethtool.h>
 #include <linux/delay.h>
 
-#include "host.h"
 #include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "wext.h"
 #include "cmd.h"
-#include "mesh.h"
 
 
 static void lbs_ethtool_get_drvinfo(struct net_device *dev,
index 3bd5d3b6037ab8ac0cb09a14ed8d1c1b13c29c0a..db8e209878c1ec3054d495d56d33dd4ba9b21bb8 100644 (file)
@@ -389,6 +389,30 @@ struct lbs_offset_value {
        u32 value;
 } __packed;
 
+#define MRVDRV_MAX_TRIPLET_802_11D              83
+
+#define COUNTRY_CODE_LEN                        3
+
+struct mrvl_ie_domain_param_set {
+       struct mrvl_ie_header header;
+
+       u8 countrycode[COUNTRY_CODE_LEN];
+       struct ieee80211_country_ie_triplet triplet[1];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11d_domain_info {
+       __le16 action;
+       struct mrvl_ie_domain_param_set domain;
+} __attribute__ ((packed));
+
+struct lbs_802_11d_domain_reg {
+       /** Country code*/
+       u8 country_code[COUNTRY_CODE_LEN];
+       /** No. of triplet*/
+       u8 no_triplet;
+       struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D];
+} __attribute__ ((packed));
+
 /*
  * Define data structure for CMD_GET_HW_SPEC
  * This structure defines the response for the GET_HW_SPEC command
@@ -949,6 +973,9 @@ struct cmd_ds_command {
                struct cmd_ds_bbp_reg_access bbpreg;
                struct cmd_ds_rf_reg_access rfreg;
 
+               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_afc afc;
                struct cmd_ds_802_11_led_ctrl ledgpio;
@@ -958,5 +985,4 @@ struct cmd_ds_command {
                struct cmd_ds_802_11_beacon_control bcn_ctrl;
        } params;
 } __packed;
-
 #endif
index abfecc4814b47ac5ba8d9088a907857f85d574fd..b519fc70f04fe5c80a533c7e231c46236f69e105 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
-#include <linux/stddef.h>
-#include <linux/ieee80211.h>
 #include <linux/slab.h>
-#include <net/iw_handler.h>
 #include <net/cfg80211.h>
 
 #include "host.h"
 #include "decl.h"
 #include "dev.h"
-#include "wext.h"
 #include "cfg.h"
 #include "debugfs.h"
-#include "scan.h"
-#include "assoc.h"
 #include "cmd.h"
 
 #define DRIVER_RELEASE_VERSION "323.p0"
@@ -96,72 +90,6 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
 }
 
 
-static int lbs_add_rtap(struct lbs_private *priv);
-static void lbs_remove_rtap(struct lbs_private *priv);
-
-
-/**
- * Get function for sysfs attribute rtap
- */
-static ssize_t lbs_rtap_get(struct device *dev,
-               struct device_attribute *attr, char * buf)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       return snprintf(buf, 5, "0x%X\n", priv->monitormode);
-}
-
-/**
- *  Set function for sysfs attribute rtap
- */
-static ssize_t lbs_rtap_set(struct device *dev,
-               struct device_attribute *attr, const char * buf, size_t count)
-{
-       int monitor_mode;
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-
-       sscanf(buf, "%x", &monitor_mode);
-       if (monitor_mode) {
-               if (priv->monitormode == monitor_mode)
-                       return strlen(buf);
-               if (!priv->monitormode) {
-                       if (priv->infra_open || lbs_mesh_open(priv))
-                               return -EBUSY;
-                       if (priv->mode == IW_MODE_INFRA)
-                               lbs_cmd_80211_deauthenticate(priv,
-                                                            priv->curbssparams.bssid,
-                                                            WLAN_REASON_DEAUTH_LEAVING);
-                       else if (priv->mode == IW_MODE_ADHOC)
-                               lbs_adhoc_stop(priv);
-                       lbs_add_rtap(priv);
-               }
-               priv->monitormode = monitor_mode;
-       } else {
-               if (!priv->monitormode)
-                       return strlen(buf);
-               priv->monitormode = 0;
-               lbs_remove_rtap(priv);
-
-               if (priv->currenttxskb) {
-                       dev_kfree_skb_any(priv->currenttxskb);
-                       priv->currenttxskb = NULL;
-               }
-
-               /* Wake queues, command thread, etc. */
-               lbs_host_to_card_done(priv);
-       }
-
-       lbs_prepare_and_send_command(priv,
-                       CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
-                       CMD_OPTION_WAITFORRSP, 0, &priv->monitormode);
-       return strlen(buf);
-}
-
-/**
- * lbs_rtap attribute to be exported per ethX interface
- * through sysfs (/sys/class/net/ethX/lbs_rtap)
- */
-static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
-
 /**
  *  @brief This function opens the ethX interface
  *
@@ -177,13 +105,6 @@ static int lbs_dev_open(struct net_device *dev)
 
        spin_lock_irq(&priv->driver_lock);
 
-       if (priv->monitormode) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       priv->infra_open = 1;
-
        if (priv->connect_status == LBS_CONNECTED)
                netif_carrier_on(dev);
        else
@@ -191,7 +112,6 @@ static int lbs_dev_open(struct net_device *dev)
 
        if (!priv->tx_pending_len)
                netif_wake_queue(dev);
- out:
 
        spin_unlock_irq(&priv->driver_lock);
        lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -211,7 +131,6 @@ static int lbs_eth_stop(struct net_device *dev)
        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);
 
@@ -733,6 +652,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
                priv->txpower_max = maxlevel;
        }
 
+       /* Send cmd to FW to enable 11D function */
+       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+
        lbs_set_mac_control(priv);
 done:
        lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
@@ -822,37 +744,16 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
 
 static int lbs_init_adapter(struct lbs_private *priv)
 {
-       size_t bufsize;
-       int i, ret = 0;
+       int ret;
 
        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);
-       if (!priv->networks) {
-               lbs_pr_err("Out of memory allocating beacons\n");
-               ret = -1;
-               goto out;
-       }
-
-       /* Initialize scan result lists */
-       INIT_LIST_HEAD(&priv->network_free_list);
-       INIT_LIST_HEAD(&priv->network_list);
-       for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-               list_add_tail(&priv->networks[i].list,
-                             &priv->network_free_list);
-       }
-
        memset(priv->current_addr, 0xff, ETH_ALEN);
 
        priv->connect_status = LBS_DISCONNECTED;
-       priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-       priv->mode = IW_MODE_INFRA;
        priv->channel = DEFAULT_AD_HOC_CHANNEL;
        priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        priv->radio_on = 1;
-       priv->enablehwauto = 1;
        priv->psmode = LBS802_11POWERMODECAM;
        priv->psstate = PS_STATE_FULL_POWER;
        priv->is_deep_sleep = 0;
@@ -907,8 +808,6 @@ static void lbs_free_adapter(struct lbs_private *priv)
        kfifo_free(&priv->event_fifo);
        del_timer(&priv->command_timer);
        del_timer(&priv->auto_deepsleep_timer);
-       kfree(priv->networks);
-       priv->networks = NULL;
 
        lbs_deb_leave(LBS_DEB_MAIN);
 }
@@ -945,7 +844,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
                lbs_pr_err("cfg80211 init failed\n");
                goto done;
        }
-       /* TODO? */
+
        wdev->iftype = NL80211_IFTYPE_STATION;
        priv = wdev_priv(wdev);
        priv->wdev = wdev;
@@ -955,7 +854,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
                goto err_wdev;
        }
 
-       //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
        dev = alloc_netdev(0, "wlan%d", ether_setup);
        if (!dev) {
                dev_err(dmdev, "no memory for network device instance\n");
@@ -971,20 +869,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        dev->netdev_ops = &lbs_netdev_ops;
        dev->watchdog_timeo = 5 * HZ;
        dev->ethtool_ops = &lbs_ethtool_ops;
-#ifdef WIRELESS_EXT
-       dev->wireless_handlers = &lbs_handler_def;
-#endif
        dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
 
-
-       // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
-
-
        priv->card = card;
-       priv->infra_open = 0;
-
 
-       priv->rtap_net_dev = NULL;
        strcpy(dev->name, "wlan%d");
 
        lbs_deb_thread("Starting main thread...\n");
@@ -996,8 +884,6 @@ 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->mcast_work, lbs_set_mcast_worker);
 
        priv->wol_criteria = 0xffffffff;
@@ -1031,12 +917,10 @@ void lbs_remove_card(struct lbs_private *priv)
        lbs_deb_enter(LBS_DEB_MAIN);
 
        lbs_remove_mesh(priv);
-       lbs_remove_rtap(priv);
+       lbs_scan_deinit(priv);
 
        dev = priv->dev;
 
-       cancel_delayed_work_sync(&priv->scan_work);
-       cancel_delayed_work_sync(&priv->assoc_work);
        cancel_work_sync(&priv->mcast_work);
 
        /* worker thread destruction blocks on the in-flight command which
@@ -1051,8 +935,6 @@ void lbs_remove_card(struct lbs_private *priv)
                lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
        }
 
-       lbs_send_disconnect_notification(priv);
-
        if (priv->is_deep_sleep) {
                priv->is_deep_sleep = 0;
                wake_up_interruptible(&priv->ds_awake_q);
@@ -1077,7 +959,7 @@ void lbs_remove_card(struct lbs_private *priv)
 EXPORT_SYMBOL_GPL(lbs_remove_card);
 
 
-static int lbs_rtap_supported(struct lbs_private *priv)
+int lbs_rtap_supported(struct lbs_private *priv)
 {
        if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
                return 1;
@@ -1109,16 +991,6 @@ int lbs_start_card(struct lbs_private *priv)
 
        lbs_init_mesh(priv);
 
-       /*
-        * While rtap isn't related to mesh, only mesh-enabled
-        * firmware implements the rtap functionality via
-        * CMD_802_11_MONITOR_MODE.
-        */
-       if (lbs_rtap_supported(priv)) {
-               if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
-                       lbs_pr_err("cannot register lbs_rtap attribute\n");
-       }
-
        lbs_debugfs_init_one(priv, dev);
 
        lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
@@ -1150,9 +1022,6 @@ void lbs_stop_card(struct lbs_private *priv)
        lbs_debugfs_remove_one(priv);
        lbs_deinit_mesh(priv);
 
-       if (lbs_rtap_supported(priv))
-               device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
-
        /* Delete the timeout of the currently processing command */
        del_timer_sync(&priv->command_timer);
        del_timer_sync(&priv->auto_deepsleep_timer);
@@ -1239,87 +1108,6 @@ static void __exit lbs_exit_module(void)
        lbs_deb_leave(LBS_DEB_MAIN);
 }
 
-/*
- * rtap interface support fuctions
- */
-
-static int lbs_rtap_open(struct net_device *dev)
-{
-       /* Yes, _stop_ the queue. Because we don't support injection */
-       lbs_deb_enter(LBS_DEB_MAIN);
-       netif_carrier_off(dev);
-       netif_stop_queue(dev);
-       lbs_deb_leave(LBS_DEB_LEAVE);
-       return 0;
-}
-
-static int lbs_rtap_stop(struct net_device *dev)
-{
-       lbs_deb_enter(LBS_DEB_MAIN);
-       lbs_deb_leave(LBS_DEB_MAIN);
-       return 0;
-}
-
-static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb,
-                                           struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       return NETDEV_TX_BUSY;
-}
-
-static void lbs_remove_rtap(struct lbs_private *priv)
-{
-       lbs_deb_enter(LBS_DEB_MAIN);
-       if (priv->rtap_net_dev == NULL)
-               goto out;
-       unregister_netdev(priv->rtap_net_dev);
-       free_netdev(priv->rtap_net_dev);
-       priv->rtap_net_dev = NULL;
-out:
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-static const struct net_device_ops rtap_netdev_ops = {
-       .ndo_open = lbs_rtap_open,
-       .ndo_stop = lbs_rtap_stop,
-       .ndo_start_xmit = lbs_rtap_hard_start_xmit,
-};
-
-static int lbs_add_rtap(struct lbs_private *priv)
-{
-       int ret = 0;
-       struct net_device *rtap_dev;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-       if (priv->rtap_net_dev) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       rtap_dev = alloc_netdev(0, "rtap%d", ether_setup);
-       if (rtap_dev == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
-       rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-       rtap_dev->netdev_ops = &rtap_netdev_ops;
-       rtap_dev->ml_priv = priv;
-       SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
-
-       ret = register_netdev(rtap_dev);
-       if (ret) {
-               free_netdev(rtap_dev);
-               goto out;
-       }
-       priv->rtap_net_dev = rtap_dev;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-       return ret;
-}
-
 module_init(lbs_init_module);
 module_exit(lbs_exit_module);
 
index e385af1f458351faa38601318c7880c508f181f6..bc5bc1384c355d536692b4e2da9408e093b639d4 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
+#include <net/cfg80211.h>
 
 #include "mesh.h"
 #include "decl.h"
@@ -314,7 +315,7 @@ static int lbs_mesh_dev_open(struct net_device *dev)
 
        spin_lock_irq(&priv->driver_lock);
 
-       if (priv->monitormode) {
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
                ret = -EBUSY;
                goto out;
        }
@@ -369,9 +370,6 @@ int lbs_add_mesh(struct lbs_private *priv)
 
        SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
 
-#ifdef WIRELESS_EXT
-       mesh_dev->wireless_handlers = &mesh_handler_def;
-#endif
        mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
        /* Register virtual mesh interface */
        ret = register_netdev(mesh_dev);
index e2573303a328f63ac2e28f23f64739c0759d1017..84ea2481ff2086da3c486b6da48e197837cb5144 100644 (file)
@@ -70,11 +70,6 @@ void lbs_persist_config_init(struct net_device *net);
 void lbs_persist_config_remove(struct net_device *net);
 
 
-/* WEXT handler */
-
-extern struct iw_handler_def mesh_handler_def;
-
-
 /* Ethtool statistics */
 
 struct ethtool_stats;
index 1c63f8ce73494ecc328f71262e08688fcdbe71f5..a4d0bca9ef2c8aeac99f629b955d8056eaaa4c66 100644 (file)
@@ -4,12 +4,13 @@
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <net/cfg80211.h>
 
+#include "defs.h"
 #include "host.h"
 #include "radiotap.h"
 #include "decl.h"
 #include "dev.h"
-#include "wext.h"
 
 struct eth803hdr {
        u8 dest_addr[6];
@@ -38,98 +39,6 @@ struct rx80211packethdr {
 static int process_rxed_802_11_packet(struct lbs_private *priv,
        struct sk_buff *skb);
 
-/**
- *  @brief     This function computes the avgSNR .
- *
- *  @param     priv    A pointer to struct lbs_private structure
- *  @return    avgSNR
- */
-static u8 lbs_getavgsnr(struct lbs_private *priv)
-{
-       u8 i;
-       u16 temp = 0;
-       if (priv->numSNRNF == 0)
-               return 0;
-       for (i = 0; i < priv->numSNRNF; i++)
-               temp += priv->rawSNR[i];
-       return (u8) (temp / priv->numSNRNF);
-
-}
-
-/**
- *  @brief     This function computes the AvgNF
- *
- *  @param     priv    A pointer to struct lbs_private structure
- *  @return    AvgNF
- */
-static u8 lbs_getavgnf(struct lbs_private *priv)
-{
-       u8 i;
-       u16 temp = 0;
-       if (priv->numSNRNF == 0)
-               return 0;
-       for (i = 0; i < priv->numSNRNF; i++)
-               temp += priv->rawNF[i];
-       return (u8) (temp / priv->numSNRNF);
-
-}
-
-/**
- *  @brief     This function save the raw SNR/NF to our internel buffer
- *
- *  @param     priv    A pointer to struct lbs_private structure
- *  @param     prxpd   A pointer to rxpd structure of received packet
- *  @return    n/a
- */
-static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
-{
-       if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
-               priv->numSNRNF++;
-       priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
-       priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
-       priv->nextSNRNF++;
-       if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
-               priv->nextSNRNF = 0;
-}
-
-/**
- *  @brief     This function computes the RSSI in received packet.
- *
- *  @param     priv    A pointer to struct lbs_private structure
- *  @param     prxpd   A pointer to rxpd structure of received packet
- *  @return    n/a
- */
-static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
-{
-
-       lbs_deb_enter(LBS_DEB_RX);
-
-       lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
-       lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
-              priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-              priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
-       priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
-       priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
-       lbs_save_rawSNRNF(priv, p_rx_pd);
-
-       priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
-       priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
-       lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
-              priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-              priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
-       priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
-           CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
-                    priv->NF[TYPE_RXPD][TYPE_NOAVG]);
-
-       priv->RSSI[TYPE_RXPD][TYPE_AVG] =
-           CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-                    priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
-       lbs_deb_leave(LBS_DEB_RX);
-}
-
 /**
  *  @brief This function processes received packet and forwards it
  *  to kernel/upper layer
@@ -154,7 +63,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
 
        skb->ip_summed = CHECKSUM_NONE;
 
-       if (priv->monitormode)
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
                return process_rxed_802_11_packet(priv, skb);
 
        p_rx_pd = (struct rxpd *) skb->data;
@@ -225,13 +134,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
         */
        skb_pull(skb, hdrchop);
 
-       /* Take the data rate from the rxpd structure
-        * only if the rate is auto
-        */
-       if (priv->enablehwauto)
-               priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
-
-       lbs_compute_rssi(priv, p_rx_pd);
+       priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
 
        lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
        dev->stats.rx_bytes += skb->len;
@@ -352,20 +255,18 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
        pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
        memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
 
-       /* Take the data rate from the rxpd structure
-        * only if the rate is auto
-        */
-       if (priv->enablehwauto)
-               priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
-
-       lbs_compute_rssi(priv, prxpd);
+       priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
 
        lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
        dev->stats.rx_bytes += skb->len;
        dev->stats.rx_packets++;
 
-       skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
-       netif_rx(skb);
+       skb->protocol = eth_type_trans(skb, priv->dev);
+
+       if (in_interrupt())
+               netif_rx(skb);
+       else
+               netif_rx_ni(skb);
 
        ret = 0;
 
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
deleted file mode 100644 (file)
index 7d82f13..0000000
+++ /dev/null
@@ -1,1354 +0,0 @@
-/**
-  * Functions implementing wlan scan IOCTL and firmware command APIs
-  *
-  * IOCTL handlers as well as command preperation and response routines
-  *  for sending scan commands to the firmware.
-  */
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <asm/unaligned.h>
-#include <net/lib80211.h>
-
-#include "host.h"
-#include "dev.h"
-#include "scan.h"
-#include "assoc.h"
-#include "wext.h"
-#include "cmd.h"
-
-//! Approximate amount of data needed to pass a scan result back to iwlist
-#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
-                             + IEEE80211_MAX_SSID_LEN   \
-                             + IW_EV_UINT_LEN           \
-                             + IW_EV_FREQ_LEN           \
-                             + IW_EV_QUAL_LEN           \
-                             + IEEE80211_MAX_SSID_LEN   \
-                             + IW_EV_PARAM_LEN          \
-                             + 40)     /* 40 for WPAIE */
-
-//! Memory needed to store a max sized channel List TLV for a firmware scan
-#define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvl_ie_header)    \
-                            + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
-                               * sizeof(struct chanscanparamset)))
-
-//! Memory needed to store a max number/size SSID TLV for a firmware scan
-#define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvl_ie_ssid_param_set))
-
-//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
-#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan)  \
-                            + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)
-
-//! The maximum number of channels the firmware can scan per command
-#define MRVDRV_MAX_CHANNELS_PER_SCAN   14
-
-/**
- * @brief Number of channels to scan per firmware scan command issuance.
- *
- *  Number restricted to prevent hitting the limit on the amount of scan data
- *  returned in a single firmware scan command.
- */
-#define MRVDRV_CHANNELS_PER_SCAN_CMD   4
-
-//! Scan time specified in the channel TLV for each channel for passive scans
-#define MRVDRV_PASSIVE_SCAN_CHAN_TIME  100
-
-//! Scan time specified in the channel TLV for each channel for active scans
-#define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-
-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
-                             struct cmd_header *resp);
-
-/*********************************************************************/
-/*                                                                   */
-/*  Misc helper functions                                            */
-/*                                                                   */
-/*********************************************************************/
-
-/**
- *  @brief Unsets the MSB on basic rates
- *
- * Scan through an array and unset the MSB for basic data rates.
- *
- *  @param rates     buffer of data rates
- *  @param len       size of buffer
- */
-static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
-{
-       int i;
-
-       for (i = 0; i < len; i++)
-               rates[i] &= 0x7f;
-}
-
-
-static inline void clear_bss_descriptor(struct bss_descriptor *bss)
-{
-       /* Don't blow away ->list, just BSS data */
-       memset(bss, 0, offsetof(struct bss_descriptor, list));
-}
-
-/**
- *  @brief Compare two SSIDs
- *
- *  @param ssid1    A pointer to ssid to compare
- *  @param ssid2    A pointer to ssid to compare
- *
- *  @return         0: ssid is same, otherwise is different
- */
-int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,
-                uint8_t ssid2_len)
-{
-       if (ssid1_len != ssid2_len)
-               return -1;
-
-       return memcmp(ssid1, ssid2, ssid1_len);
-}
-
-static inline int is_same_network(struct bss_descriptor *src,
-                                 struct bss_descriptor *dst)
-{
-       /* A network is only a duplicate if the channel, BSSID, and ESSID
-        * all match.  We treat all <hidden> with the same BSSID and channel
-        * as one network */
-       return ((src->ssid_len == dst->ssid_len) &&
-               (src->channel == dst->channel) &&
-               !compare_ether_addr(src->bssid, dst->bssid) &&
-               !memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/* Region channel support                                            */
-/*                                                                   */
-/*********************************************************************/
-
-#define LBS_TX_PWR_DEFAULT             20      /*100mW */
-#define LBS_TX_PWR_US_DEFAULT          20      /*100mW */
-#define LBS_TX_PWR_JP_DEFAULT          16      /*50mW */
-#define LBS_TX_PWR_FR_DEFAULT          20      /*100mW */
-#define LBS_TX_PWR_EMEA_DEFAULT        20      /*100mW */
-
-/* Format { channel, frequency (MHz), maxtxpower } */
-/* band: 'B/G', region: USA FCC/Canada IC */
-static struct chan_freq_power channel_freq_power_US_BG[] = {
-       {1, 2412, LBS_TX_PWR_US_DEFAULT},
-       {2, 2417, LBS_TX_PWR_US_DEFAULT},
-       {3, 2422, LBS_TX_PWR_US_DEFAULT},
-       {4, 2427, LBS_TX_PWR_US_DEFAULT},
-       {5, 2432, LBS_TX_PWR_US_DEFAULT},
-       {6, 2437, LBS_TX_PWR_US_DEFAULT},
-       {7, 2442, LBS_TX_PWR_US_DEFAULT},
-       {8, 2447, LBS_TX_PWR_US_DEFAULT},
-       {9, 2452, LBS_TX_PWR_US_DEFAULT},
-       {10, 2457, LBS_TX_PWR_US_DEFAULT},
-       {11, 2462, LBS_TX_PWR_US_DEFAULT}
-};
-
-/* band: 'B/G', region: Europe ETSI */
-static struct chan_freq_power channel_freq_power_EU_BG[] = {
-       {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
-       {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
-       {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
-       {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
-       {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
-       {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
-       {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
-       {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
-       {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
-       {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
-       {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
-       {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
-       {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
-};
-
-/* band: 'B/G', region: Spain */
-static struct chan_freq_power channel_freq_power_SPN_BG[] = {
-       {10, 2457, LBS_TX_PWR_DEFAULT},
-       {11, 2462, LBS_TX_PWR_DEFAULT}
-};
-
-/* band: 'B/G', region: France */
-static struct chan_freq_power channel_freq_power_FR_BG[] = {
-       {10, 2457, LBS_TX_PWR_FR_DEFAULT},
-       {11, 2462, LBS_TX_PWR_FR_DEFAULT},
-       {12, 2467, LBS_TX_PWR_FR_DEFAULT},
-       {13, 2472, LBS_TX_PWR_FR_DEFAULT}
-};
-
-/* band: 'B/G', region: Japan */
-static struct chan_freq_power channel_freq_power_JPN_BG[] = {
-       {1, 2412, LBS_TX_PWR_JP_DEFAULT},
-       {2, 2417, LBS_TX_PWR_JP_DEFAULT},
-       {3, 2422, LBS_TX_PWR_JP_DEFAULT},
-       {4, 2427, LBS_TX_PWR_JP_DEFAULT},
-       {5, 2432, LBS_TX_PWR_JP_DEFAULT},
-       {6, 2437, LBS_TX_PWR_JP_DEFAULT},
-       {7, 2442, LBS_TX_PWR_JP_DEFAULT},
-       {8, 2447, LBS_TX_PWR_JP_DEFAULT},
-       {9, 2452, LBS_TX_PWR_JP_DEFAULT},
-       {10, 2457, LBS_TX_PWR_JP_DEFAULT},
-       {11, 2462, LBS_TX_PWR_JP_DEFAULT},
-       {12, 2467, LBS_TX_PWR_JP_DEFAULT},
-       {13, 2472, LBS_TX_PWR_JP_DEFAULT},
-       {14, 2484, LBS_TX_PWR_JP_DEFAULT}
-};
-
-/**
- * the structure for channel, frequency and power
- */
-struct region_cfp_table {
-       u8 region;
-       struct chan_freq_power *cfp_BG;
-       int cfp_no_BG;
-};
-
-/**
- * the structure for the mapping between region and CFP
- */
-static struct region_cfp_table region_cfp_table[] = {
-       {0x10,                  /*US FCC */
-        channel_freq_power_US_BG,
-        ARRAY_SIZE(channel_freq_power_US_BG),
-        }
-       ,
-       {0x20,                  /*CANADA IC */
-        channel_freq_power_US_BG,
-        ARRAY_SIZE(channel_freq_power_US_BG),
-        }
-       ,
-       {0x30, /*EU*/ channel_freq_power_EU_BG,
-        ARRAY_SIZE(channel_freq_power_EU_BG),
-        }
-       ,
-       {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
-        ARRAY_SIZE(channel_freq_power_SPN_BG),
-        }
-       ,
-       {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
-        ARRAY_SIZE(channel_freq_power_FR_BG),
-        }
-       ,
-       {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
-        ARRAY_SIZE(channel_freq_power_JPN_BG),
-        }
-       ,
-/*Add new region here */
-};
-
-/**
- *  @brief This function finds the CFP in
- *  region_cfp_table based on region and band parameter.
- *
- *  @param region  The region code
- *  @param band           The band
- *  @param cfp_no  A pointer to CFP number
- *  @return       A pointer to CFP
- */
-static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
-{
-       int i, end;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       end = ARRAY_SIZE(region_cfp_table);
-
-       for (i = 0; i < end ; i++) {
-               lbs_deb_main("region_cfp_table[i].region=%d\n",
-                       region_cfp_table[i].region);
-               if (region_cfp_table[i].region == region) {
-                       *cfp_no = region_cfp_table[i].cfp_no_BG;
-                       lbs_deb_leave(LBS_DEB_MAIN);
-                       return region_cfp_table[i].cfp_BG;
-               }
-       }
-
-       lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
-       return NULL;
-}
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
-{
-       int ret = 0;
-       int i = 0;
-
-       struct chan_freq_power *cfp;
-       int cfp_no;
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-
-       memset(priv->region_channel, 0, sizeof(priv->region_channel));
-
-       cfp = lbs_get_region_cfp_table(region, &cfp_no);
-       if (cfp != NULL) {
-               priv->region_channel[i].nrcfp = cfp_no;
-               priv->region_channel[i].CFP = cfp;
-       } else {
-               lbs_deb_main("wrong region code %#x in band B/G\n",
-                      region);
-               ret = -1;
-               goto out;
-       }
-       priv->region_channel[i].valid = 1;
-       priv->region_channel[i].region = region;
-       priv->region_channel[i].band = band;
-       i++;
-out:
-       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-       return ret;
-}
-
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Main scanning support                                            */
-/*                                                                   */
-/*********************************************************************/
-
-/**
- *  @brief Create a channel list for the driver to scan based on region info
- *
- *  Only used from lbs_scan_setup_scan_config()
- *
- *  Use the driver region/band information to construct a comprehensive list
- *    of channels to scan.  This routine is used for any scan that is not
- *    provided a specific channel list to scan.
- *
- *  @param priv          A pointer to struct lbs_private structure
- *  @param scanchanlist  Output parameter: resulting channel list to scan
- *
- *  @return              void
- */
-static int lbs_scan_create_channel_list(struct lbs_private *priv,
-                                       struct chanscanparamset *scanchanlist)
-{
-       struct region_channel *scanregion;
-       struct chan_freq_power *cfp;
-       int rgnidx;
-       int chanidx;
-       int nextchan;
-       uint8_t scantype;
-
-       chanidx = 0;
-
-       /* Set the default scan type to the user specified type, will later
-        *   be changed to passive on a per channel basis if restricted by
-        *   regulatory requirements (11d or 11h)
-        */
-       scantype = CMD_SCAN_TYPE_ACTIVE;
-
-       for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
-               if (!priv->region_channel[rgnidx].valid)
-                       continue;
-               scanregion = &priv->region_channel[rgnidx];
-
-               for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
-                       struct chanscanparamset *chan = &scanchanlist[chanidx];
-
-                       cfp = scanregion->CFP + nextchan;
-
-                       if (scanregion->band == BAND_B || scanregion->band == BAND_G)
-                               chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
-
-                       if (scantype == CMD_SCAN_TYPE_PASSIVE) {
-                               chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
-                               chan->chanscanmode.passivescan = 1;
-                       } else {
-                               chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
-                               chan->chanscanmode.passivescan = 0;
-                       }
-
-                       chan->channumber = cfp->channel;
-               }
-       }
-       return chanidx;
-}
-
-/*
- * Add SSID TLV of the form:
- *
- * TLV-ID SSID     00 00
- * length          06 00
- * ssid            4d 4e 54 45 53 54
- */
-static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
-{
-       struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
-
-       ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
-       ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
-       memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);
-       return sizeof(ssid_tlv->header) + priv->scan_ssid_len;
-}
-
-/*
- * Add CHANLIST TLV of the form
- *
- * TLV-ID CHANLIST 01 01
- * length          5b 00
- * channel 1       00 01 00 00 00 64 00
- *   radio type    00
- *   channel          01
- *   scan type           00
- *   min scan time          00 00
- *   max scan time                64 00
- * channel 2       00 02 00 00 00 64 00
- * channel 3       00 03 00 00 00 64 00
- * channel 4       00 04 00 00 00 64 00
- * channel 5       00 05 00 00 00 64 00
- * channel 6       00 06 00 00 00 64 00
- * channel 7       00 07 00 00 00 64 00
- * channel 8       00 08 00 00 00 64 00
- * channel 9       00 09 00 00 00 64 00
- * channel 10      00 0a 00 00 00 64 00
- * channel 11      00 0b 00 00 00 64 00
- * channel 12      00 0c 00 00 00 64 00
- * channel 13      00 0d 00 00 00 64 00
- *
- */
-static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
-                                    struct chanscanparamset *chan_list,
-                                    int chan_count)
-{
-       size_t size = sizeof(struct chanscanparamset) *chan_count;
-       struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
-
-       chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
-       memcpy(chan_tlv->chanscanparam, chan_list, size);
-       chan_tlv->header.len = cpu_to_le16(size);
-       return sizeof(chan_tlv->header) + size;
-}
-
-/*
- * Add RATES TLV of the form
- *
- * TLV-ID RATES    01 00
- * length          0e 00
- * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c
- *
- * The rates are in lbs_bg_rates[], but for the 802.11b
- * rates the high bit isn't set.
- */
-static int lbs_scan_add_rates_tlv(uint8_t *tlv)
-{
-       int i;
-       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
-
-       rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
-       tlv += sizeof(rate_tlv->header);
-       for (i = 0; i < MAX_RATES; i++) {
-               *tlv = lbs_bg_rates[i];
-               if (*tlv == 0)
-                       break;
-               /* This code makes sure that the 802.11b rates (1 MBit/s, 2
-                  MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.
-                  Note that the values are MBit/s * 2, to mark them as
-                  basic rates so that the firmware likes it better */
-               if (*tlv == 0x02 || *tlv == 0x04 ||
-                   *tlv == 0x0b || *tlv == 0x16)
-                       *tlv |= 0x80;
-               tlv++;
-       }
-       rate_tlv->header.len = cpu_to_le16(i);
-       return sizeof(rate_tlv->header) + i;
-}
-
-/*
- * Generate the CMD_802_11_SCAN command with the proper tlv
- * for a bunch of channels.
- */
-static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
-                      struct chanscanparamset *chan_list, int chan_count)
-{
-       int ret = -ENOMEM;
-       struct cmd_ds_802_11_scan *scan_cmd;
-       uint8_t *tlv;   /* pointer into our current, growing TLV storage area */
-
-       lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
-               bsstype, chan_list ? chan_list[0].channumber : -1,
-               chan_count);
-
-       /* create the fixed part for scan command */
-       scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
-       if (scan_cmd == NULL)
-               goto out;
-
-       tlv = scan_cmd->tlvbuffer;
-       /* TODO: do we need to scan for a specific BSSID?
-       memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */
-       scan_cmd->bsstype = bsstype;
-
-       /* add TLVs */
-       if (priv->scan_ssid_len)
-               tlv += lbs_scan_add_ssid_tlv(priv, tlv);
-       if (chan_list && chan_count)
-               tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
-       tlv += lbs_scan_add_rates_tlv(tlv);
-
-       /* This is the final data we are about to send */
-       scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);
-       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
-                   sizeof(*scan_cmd));
-       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
-                   tlv - scan_cmd->tlvbuffer);
-
-       ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
-                       le16_to_cpu(scan_cmd->hdr.size),
-                       lbs_ret_80211_scan, 0);
-
-out:
-       kfree(scan_cmd);
-       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Internal function used to start a scan based on an input config
- *
- *  Use the input user scan configuration information when provided in
- *    order to send the appropriate scan commands to firmware to populate or
- *    update the internal driver scan table
- *
- *  @param priv          A pointer to struct lbs_private structure
- *  @param full_scan     Do a full-scan (blocking)
- *
- *  @return              0 or < 0 if error
- */
-int lbs_scan_networks(struct lbs_private *priv, int full_scan)
-{
-       int ret = -ENOMEM;
-       struct chanscanparamset *chan_list;
-       struct chanscanparamset *curr_chans;
-       int chan_count;
-       uint8_t bsstype = CMD_BSS_TYPE_ANY;
-       int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
-       union iwreq_data wrqu;
-#ifdef CONFIG_LIBERTAS_DEBUG
-       struct bss_descriptor *iter;
-       int i = 0;
-       DECLARE_SSID_BUF(ssid);
-#endif
-
-       lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
-
-       /* Cancel any partial outstanding partial scans if this scan
-        * is a full scan.
-        */
-       if (full_scan && delayed_work_pending(&priv->scan_work))
-               cancel_delayed_work(&priv->scan_work);
-
-       /* User-specified bsstype or channel list
-       TODO: this can be implemented if some user-space application
-       need the feature. Formerly, it was accessible from debugfs,
-       but then nowhere used.
-       if (user_cfg) {
-               if (user_cfg->bsstype)
-               bsstype = user_cfg->bsstype;
-       } */
-
-       lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);
-
-       /* Create list of channels to scan */
-       chan_list = kzalloc(sizeof(struct chanscanparamset) *
-                           LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
-       if (!chan_list) {
-               lbs_pr_alert("SCAN: chan_list empty\n");
-               goto out;
-       }
-
-       /* We want to scan all channels */
-       chan_count = lbs_scan_create_channel_list(priv, chan_list);
-
-       netif_stop_queue(priv->dev);
-       if (priv->mesh_dev)
-               netif_stop_queue(priv->mesh_dev);
-
-       /* Prepare to continue an interrupted scan */
-       lbs_deb_scan("chan_count %d, scan_channel %d\n",
-                    chan_count, priv->scan_channel);
-       curr_chans = chan_list;
-       /* advance channel list by already-scanned-channels */
-       if (priv->scan_channel > 0) {
-               curr_chans += priv->scan_channel;
-               chan_count -= priv->scan_channel;
-       }
-
-       /* Send scan command(s)
-        * numchannels contains the number of channels we should maximally scan
-        * chan_count is the total number of channels to scan
-        */
-
-       while (chan_count) {
-               int to_scan = min(numchannels, chan_count);
-               lbs_deb_scan("scanning %d of %d channels\n",
-                            to_scan, chan_count);
-               ret = lbs_do_scan(priv, bsstype, curr_chans,
-                                 to_scan);
-               if (ret) {
-                       lbs_pr_err("SCAN_CMD failed\n");
-                       goto out2;
-               }
-               curr_chans += to_scan;
-               chan_count -= to_scan;
-
-               /* somehow schedule the next part of the scan */
-               if (chan_count && !full_scan &&
-                   !priv->surpriseremoved) {
-                       /* -1 marks just that we're currently scanning */
-                       if (priv->scan_channel < 0)
-                               priv->scan_channel = to_scan;
-                       else
-                               priv->scan_channel += to_scan;
-                       cancel_delayed_work(&priv->scan_work);
-                       queue_delayed_work(priv->work_thread, &priv->scan_work,
-                                          msecs_to_jiffies(300));
-                       /* skip over GIWSCAN event */
-                       goto out;
-               }
-
-       }
-       memset(&wrqu, 0, sizeof(union iwreq_data));
-       wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
-#ifdef CONFIG_LIBERTAS_DEBUG
-       /* Dump the scan table */
-       mutex_lock(&priv->lock);
-       lbs_deb_scan("scan table:\n");
-       list_for_each_entry(iter, &priv->network_list, list)
-               lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",
-                            i++, iter->bssid, iter->rssi,
-                            print_ssid(ssid, iter->ssid, iter->ssid_len));
-       mutex_unlock(&priv->lock);
-#endif
-
-out2:
-       priv->scan_channel = 0;
-
-out:
-       if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
-               netif_wake_queue(priv->dev);
-
-       if (priv->mesh_dev && lbs_mesh_connected(priv) &&
-           !priv->tx_pending_len)
-               netif_wake_queue(priv->mesh_dev);
-
-       kfree(chan_list);
-
-       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-       return ret;
-}
-
-void lbs_scan_worker(struct work_struct *work)
-{
-       struct lbs_private *priv =
-               container_of(work, struct lbs_private, scan_work.work);
-
-       lbs_deb_enter(LBS_DEB_SCAN);
-       lbs_scan_networks(priv, 0);
-       lbs_deb_leave(LBS_DEB_SCAN);
-}
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Result interpretation                                            */
-/*                                                                   */
-/*********************************************************************/
-
-/**
- *  @brief Interpret a BSS scan response returned from the firmware
- *
- *  Parse the various fixed fields and IEs passed back for a BSS probe
- *  response or beacon from the scan command.  Record information as needed
- *  in the scan table struct bss_descriptor for that entry.
- *
- *  @param bss  Output parameter: Pointer to the BSS Entry
- *
- *  @return             0 or -1
- */
-static int lbs_process_bss(struct bss_descriptor *bss,
-                          uint8_t **pbeaconinfo, int *bytesleft)
-{
-       struct ieee_ie_fh_param_set *fh;
-       struct ieee_ie_ds_param_set *ds;
-       struct ieee_ie_cf_param_set *cf;
-       struct ieee_ie_ibss_param_set *ibss;
-       DECLARE_SSID_BUF(ssid);
-       uint8_t *pos, *end, *p;
-       uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
-       uint16_t beaconsize = 0;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_SCAN);
-
-       if (*bytesleft >= sizeof(beaconsize)) {
-               /* Extract & convert beacon size from the command buffer */
-               beaconsize = get_unaligned_le16(*pbeaconinfo);
-               *bytesleft -= sizeof(beaconsize);
-               *pbeaconinfo += sizeof(beaconsize);
-       }
-
-       if (beaconsize == 0 || beaconsize > *bytesleft) {
-               *pbeaconinfo += *bytesleft;
-               *bytesleft = 0;
-               ret = -1;
-               goto done;
-       }
-
-       /* Initialize the current working beacon pointer for this BSS iteration */
-       pos = *pbeaconinfo;
-       end = pos + beaconsize;
-
-       /* Advance the return beacon pointer past the current beacon */
-       *pbeaconinfo += beaconsize;
-       *bytesleft -= beaconsize;
-
-       memcpy(bss->bssid, pos, ETH_ALEN);
-       lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
-       pos += ETH_ALEN;
-
-       if ((end - pos) < 12) {
-               lbs_deb_scan("process_bss: Not enough bytes left\n");
-               ret = -1;
-               goto done;
-       }
-
-       /*
-        * next 4 fields are RSSI, time stamp, beacon interval,
-        *   and capability information
-        */
-
-       /* RSSI is 1 byte long */
-       bss->rssi = *pos;
-       lbs_deb_scan("process_bss: RSSI %d\n", *pos);
-       pos++;
-
-       /* time stamp is 8 bytes long */
-       pos += 8;
-
-       /* beacon interval is 2 bytes long */
-       bss->beaconperiod = get_unaligned_le16(pos);
-       pos += 2;
-
-       /* capability information is 2 bytes long */
-       bss->capability = get_unaligned_le16(pos);
-       lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
-       pos += 2;
-
-       if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-               lbs_deb_scan("process_bss: WEP enabled\n");
-       if (bss->capability & WLAN_CAPABILITY_IBSS)
-               bss->mode = IW_MODE_ADHOC;
-       else
-               bss->mode = IW_MODE_INFRA;
-
-       /* rest of the current buffer are IE's */
-       lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
-       lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
-
-       /* process variable IE */
-       while (pos <= end - 2) {
-               if (pos + pos[1] > end) {
-                       lbs_deb_scan("process_bss: error in processing IE, "
-                                    "bytes left < IE length\n");
-                       break;
-               }
-
-               switch (pos[0]) {
-               case WLAN_EID_SSID:
-                       bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
-                       memcpy(bss->ssid, pos + 2, bss->ssid_len);
-                       lbs_deb_scan("got SSID IE: '%s', len %u\n",
-                                    print_ssid(ssid, bss->ssid, bss->ssid_len),
-                                    bss->ssid_len);
-                       break;
-
-               case WLAN_EID_SUPP_RATES:
-                       n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
-                       memcpy(bss->rates, pos + 2, n_basic_rates);
-                       got_basic_rates = 1;
-                       lbs_deb_scan("got RATES IE\n");
-                       break;
-
-               case WLAN_EID_FH_PARAMS:
-                       fh = (struct ieee_ie_fh_param_set *) pos;
-                       memcpy(&bss->phy.fh, fh, sizeof(*fh));
-                       lbs_deb_scan("got FH IE\n");
-                       break;
-
-               case WLAN_EID_DS_PARAMS:
-                       ds = (struct ieee_ie_ds_param_set *) pos;
-                       bss->channel = ds->channel;
-                       memcpy(&bss->phy.ds, ds, sizeof(*ds));
-                       lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
-                       break;
-
-               case WLAN_EID_CF_PARAMS:
-                       cf = (struct ieee_ie_cf_param_set *) pos;
-                       memcpy(&bss->ss.cf, cf, sizeof(*cf));
-                       lbs_deb_scan("got CF IE\n");
-                       break;
-
-               case WLAN_EID_IBSS_PARAMS:
-                       ibss = (struct ieee_ie_ibss_param_set *) pos;
-                       bss->atimwindow = ibss->atimwindow;
-                       memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
-                       lbs_deb_scan("got IBSS IE\n");
-                       break;
-
-               case WLAN_EID_EXT_SUPP_RATES:
-                       /* only process extended supported rate if data rate is
-                        * already found. Data rate IE should come before
-                        * extended supported rate IE
-                        */
-                       lbs_deb_scan("got RATESEX IE\n");
-                       if (!got_basic_rates) {
-                               lbs_deb_scan("... but ignoring it\n");
-                               break;
-                       }
-
-                       n_ex_rates = pos[1];
-                       if (n_basic_rates + n_ex_rates > MAX_RATES)
-                               n_ex_rates = MAX_RATES - n_basic_rates;
-
-                       p = bss->rates + n_basic_rates;
-                       memcpy(p, pos + 2, n_ex_rates);
-                       break;
-
-               case WLAN_EID_GENERIC:
-                       if (pos[1] >= 4 &&
-                           pos[2] == 0x00 && pos[3] == 0x50 &&
-                           pos[4] == 0xf2 && pos[5] == 0x01) {
-                               bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
-                               memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
-                               lbs_deb_scan("got WPA IE\n");
-                               lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
-                                           bss->wpa_ie_len);
-                       } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
-                                  pos[2] == 0x00 && pos[3] == 0x50 &&
-                                  pos[4] == 0x43 && pos[5] == 0x04) {
-                               lbs_deb_scan("got mesh IE\n");
-                               bss->mesh = 1;
-                       } else {
-                               lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
-                                       pos[2], pos[3],
-                                       pos[4], pos[5],
-                                       pos[1]);
-                       }
-                       break;
-
-               case WLAN_EID_RSN:
-                       lbs_deb_scan("got RSN IE\n");
-                       bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
-                       memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
-                       lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
-                                   bss->rsn_ie, bss->rsn_ie_len);
-                       break;
-
-               default:
-                       lbs_deb_scan("got IE 0x%04x, len %d\n",
-                                    pos[0], pos[1]);
-                       break;
-               }
-
-               pos += pos[1] + 2;
-       }
-
-       /* Timestamp */
-       bss->last_scanned = jiffies;
-       lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
-
-       ret = 0;
-
-done:
-       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Send a scan command for all available channels filtered on a spec
- *
- *  Used in association code and from debugfs
- *
- *  @param priv             A pointer to struct lbs_private structure
- *  @param ssid             A pointer to the SSID to scan for
- *  @param ssid_len         Length of the SSID
- *
- *  @return                0-success, otherwise fail
- */
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
-                               uint8_t ssid_len)
-{
-       DECLARE_SSID_BUF(ssid_buf);
-       int ret = 0;
-
-       lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
-                          print_ssid(ssid_buf, ssid, ssid_len));
-
-       if (!ssid_len)
-               goto out;
-
-       memcpy(priv->scan_ssid, ssid, ssid_len);
-       priv->scan_ssid_len = ssid_len;
-
-       lbs_scan_networks(priv, 1);
-       if (priv->surpriseremoved) {
-               ret = -1;
-               goto out;
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-       return ret;
-}
-
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Support for Wireless Extensions                                  */
-/*                                                                   */
-/*********************************************************************/
-
-
-#define MAX_CUSTOM_LEN 64
-
-static inline char *lbs_translate_scan(struct lbs_private *priv,
-                                           struct iw_request_info *info,
-                                           char *start, char *stop,
-                                           struct bss_descriptor *bss)
-{
-       struct chan_freq_power *cfp;
-       char *current_val;      /* For rates */
-       struct iw_event iwe;    /* Temporary buffer */
-       int j;
-#define PERFECT_RSSI ((uint8_t)50)
-#define WORST_RSSI   ((uint8_t)0)
-#define RSSI_DIFF    ((uint8_t)(PERFECT_RSSI - WORST_RSSI))
-       uint8_t rssi;
-
-       lbs_deb_enter(LBS_DEB_SCAN);
-
-       cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
-       if (!cfp) {
-               lbs_deb_scan("Invalid channel number %d\n", bss->channel);
-               start = NULL;
-               goto out;
-       }
-
-       /* First entry *MUST* be the BSSID */
-       iwe.cmd = SIOCGIWAP;
-       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
-       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-
-       /* SSID */
-       iwe.cmd = SIOCGIWESSID;
-       iwe.u.data.flags = 1;
-       iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
-       start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
-
-       /* Mode */
-       iwe.cmd = SIOCGIWMODE;
-       iwe.u.mode = bss->mode;
-       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
-
-       /* Frequency */
-       iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = (long)cfp->freq * 100000;
-       iwe.u.freq.e = 1;
-       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
-       /* Add quality statistics */
-       iwe.cmd = IWEVQUAL;
-       iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
-       iwe.u.qual.level = SCAN_RSSI(bss->rssi);
-
-       rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
-       iwe.u.qual.qual =
-               (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
-                (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
-               (RSSI_DIFF * RSSI_DIFF);
-       if (iwe.u.qual.qual > 100)
-               iwe.u.qual.qual = 100;
-
-       if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
-               iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
-       } else {
-               iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-       }
-
-       /* Locally created ad-hoc BSSs won't have beacons if this is the
-        * only station in the adhoc network; so get signal strength
-        * from receive statistics.
-        */
-       if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate
-           && !lbs_ssid_cmp(priv->curbssparams.ssid,
-                            priv->curbssparams.ssid_len,
-                            bss->ssid, bss->ssid_len)) {
-               int snr, nf;
-               snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
-               nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
-               iwe.u.qual.level = CAL_RSSI(snr, nf);
-       }
-       start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
-       /* Add encryption capability */
-       iwe.cmd = SIOCGIWENCODE;
-       if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
-               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-       } else {
-               iwe.u.data.flags = IW_ENCODE_DISABLED;
-       }
-       iwe.u.data.length = 0;
-       start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
-
-       current_val = start + iwe_stream_lcp_len(info);
-
-       iwe.cmd = SIOCGIWRATE;
-       iwe.u.bitrate.fixed = 0;
-       iwe.u.bitrate.disabled = 0;
-       iwe.u.bitrate.value = 0;
-
-       for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
-               /* Bit rate given in 500 kb/s units */
-               iwe.u.bitrate.value = bss->rates[j] * 500000;
-               current_val = iwe_stream_add_value(info, start, current_val,
-                                                  stop, &iwe, IW_EV_PARAM_LEN);
-       }
-       if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
-           && !lbs_ssid_cmp(priv->curbssparams.ssid,
-                            priv->curbssparams.ssid_len,
-                            bss->ssid, bss->ssid_len)) {
-               iwe.u.bitrate.value = 22 * 500000;
-               current_val = iwe_stream_add_value(info, start, current_val,
-                                                  stop, &iwe, IW_EV_PARAM_LEN);
-       }
-       /* Check if we added any event */
-       if ((current_val - start) > iwe_stream_lcp_len(info))
-               start = current_val;
-
-       memset(&iwe, 0, sizeof(iwe));
-       if (bss->wpa_ie_len) {
-               char buf[MAX_WPA_IE_LEN];
-               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(info, start, stop, &iwe, buf);
-       }
-
-       memset(&iwe, 0, sizeof(iwe));
-       if (bss->rsn_ie_len) {
-               char buf[MAX_WPA_IE_LEN];
-               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(info, start, stop, &iwe, buf);
-       }
-
-       if (bss->mesh) {
-               char custom[MAX_CUSTOM_LEN];
-               char *p = custom;
-
-               iwe.cmd = IWEVCUSTOM;
-               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(info, start, stop,
-                                                    &iwe, custom);
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
-       return start;
-}
-
-
-/**
- *  @brief Handle Scan Network ioctl
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param vwrq         A pointer to iw_param structure
- *  @param extra        A pointer to extra data buf
- *
- *  @return             0 --success, otherwise fail
- */
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
-                union iwreq_data *wrqu, char *extra)
-{
-       DECLARE_SSID_BUF(ssid);
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (!priv->radio_on) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               ret = -ENETDOWN;
-               goto out;
-       }
-
-       /* mac80211 does this:
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->type != IEEE80211_IF_TYPE_xxx) {
-               ret = -EOPNOTSUPP;
-               goto out;
-       }
-       */
-
-       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
-           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-               struct iw_scan_req *req = (struct iw_scan_req *)extra;
-               priv->scan_ssid_len = req->essid_len;
-               memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
-               lbs_deb_wext("set_scan, essid '%s'\n",
-                       print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
-       } else {
-               priv->scan_ssid_len = 0;
-       }
-
-       if (!delayed_work_pending(&priv->scan_work))
-               queue_delayed_work(priv->work_thread, &priv->scan_work,
-                                  msecs_to_jiffies(50));
-       /* set marker that currently a scan is taking place */
-       priv->scan_channel = -1;
-
-       if (priv->surpriseremoved)
-               ret = -EIO;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-
-/**
- *  @brief  Handle Retrieve scan table ioctl
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param dwrq         A pointer to iw_point structure
- *  @param extra        A pointer to extra data buf
- *
- *  @return             0 --success, otherwise fail
- */
-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
-                struct iw_point *dwrq, char *extra)
-{
-#define SCAN_ITEM_SIZE 128
-       struct lbs_private *priv = dev->ml_priv;
-       int err = 0;
-       char *ev = extra;
-       char *stop = ev + dwrq->length;
-       struct bss_descriptor *iter_bss;
-       struct bss_descriptor *safe;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /* iwlist should wait until the current scan is finished */
-       if (priv->scan_channel)
-               return -EAGAIN;
-
-       /* Update RSSI if current BSS is a locally created ad-hoc BSS */
-       if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
-               err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
-                               CMD_OPTION_WAITFORRSP, 0, NULL);
-               if (err)
-                       goto out;
-       }
-
-       mutex_lock(&priv->lock);
-       list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
-               char *next_ev;
-               unsigned long stale_time;
-
-               if (stop - ev < SCAN_ITEM_SIZE) {
-                       err = -E2BIG;
-                       break;
-               }
-
-               /* For mesh device, list only mesh networks */
-               if (dev == priv->mesh_dev && !iter_bss->mesh)
-                       continue;
-
-               /* Prune old an old scan result */
-               stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
-               if (time_after(jiffies, stale_time)) {
-                       list_move_tail(&iter_bss->list, &priv->network_free_list);
-                       clear_bss_descriptor(iter_bss);
-                       continue;
-               }
-
-               /* Translate to WE format this entry */
-               next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
-               if (next_ev == NULL)
-                       continue;
-               ev = next_ev;
-       }
-       mutex_unlock(&priv->lock);
-
-       dwrq->length = (ev - extra);
-       dwrq->flags = 0;
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
-       return err;
-}
-
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Command execution                                                */
-/*                                                                   */
-/*********************************************************************/
-
-
-/**
- *  @brief This function handles the command response of scan
- *
- *  Called from handle_cmd_response() in cmdrespc.
- *
- *   The response buffer for the scan command has the following
- *      memory layout:
- *
- *     .-----------------------------------------------------------.
- *     |  header (4 * sizeof(u16)):  Standard command response hdr |
- *     .-----------------------------------------------------------.
- *     |  bufsize (u16) : sizeof the BSS Description data          |
- *     .-----------------------------------------------------------.
- *     |  NumOfSet (u8) : Number of BSS Descs returned             |
- *     .-----------------------------------------------------------.
- *     |  BSSDescription data (variable, size given in bufsize)    |
- *     .-----------------------------------------------------------.
- *     |  TLV data (variable, size calculated using header->size,  |
- *     |            bufsize and sizeof the fixed fields above)     |
- *     .-----------------------------------------------------------.
- *
- *  @param priv    A pointer to struct lbs_private structure
- *  @param resp    A pointer to cmd_ds_command
- *
- *  @return        0 or -1
- */
-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
-                             struct cmd_header *resp)
-{
-       struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
-       struct bss_descriptor *iter_bss;
-       struct bss_descriptor *safe;
-       uint8_t *bssinfo;
-       uint16_t scanrespsize;
-       int bytesleft;
-       int idx;
-       int tlvbufsize;
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_SCAN);
-
-       /* Prune old entries from scan table */
-       list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
-               unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
-               if (time_before(jiffies, stale_time))
-                       continue;
-               list_move_tail (&iter_bss->list, &priv->network_free_list);
-               clear_bss_descriptor(iter_bss);
-       }
-
-       if (scanresp->nr_sets > MAX_NETWORK_COUNT) {
-               lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",
-                            scanresp->nr_sets, MAX_NETWORK_COUNT);
-               ret = -1;
-               goto done;
-       }
-
-       bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
-       lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
-
-       scanrespsize = le16_to_cpu(resp->size);
-       lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);
-
-       bssinfo = scanresp->bssdesc_and_tlvbuffer;
-
-       /* The size of the TLV buffer is equal to the entire command response
-        *   size (scanrespsize) minus the fixed fields (sizeof()'s), the
-        *   BSS Descriptions (bssdescriptsize as bytesLef) and the command
-        *   response header (sizeof(struct cmd_header))
-        */
-       tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
-                                    + sizeof(scanresp->nr_sets)
-                                    + sizeof(struct cmd_header));
-
-       /*
-        *  Process each scan response returned (scanresp->nr_sets). Save
-        *    the information in the newbssentry and then insert into the
-        *    driver scan table either as an update to an existing entry
-        *    or as an addition at the end of the table
-        */
-       for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {
-               struct bss_descriptor new;
-               struct bss_descriptor *found = NULL;
-               struct bss_descriptor *oldest = NULL;
-
-               /* Process the data fields and IEs returned for this BSS */
-               memset(&new, 0, sizeof (struct bss_descriptor));
-               if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {
-                       /* error parsing the scan response, skipped */
-                       lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
-                       continue;
-               }
-
-               /* Try to find this bss in the scan table */
-               list_for_each_entry (iter_bss, &priv->network_list, list) {
-                       if (is_same_network(iter_bss, &new)) {
-                               found = iter_bss;
-                               break;
-                       }
-
-                       if ((oldest == NULL) ||
-                           (iter_bss->last_scanned < oldest->last_scanned))
-                               oldest = iter_bss;
-               }
-
-               if (found) {
-                       /* found, clear it */
-                       clear_bss_descriptor(found);
-               } else if (!list_empty(&priv->network_free_list)) {
-                       /* Pull one from the free list */
-                       found = list_entry(priv->network_free_list.next,
-                                          struct bss_descriptor, list);
-                       list_move_tail(&found->list, &priv->network_list);
-               } else if (oldest) {
-                       /* If there are no more slots, expire the oldest */
-                       found = oldest;
-                       clear_bss_descriptor(found);
-                       list_move_tail(&found->list, &priv->network_list);
-               } else {
-                       continue;
-               }
-
-               lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);
-
-               /* Copy the locally created newbssentry to the scan table */
-               memcpy(found, &new, offsetof(struct bss_descriptor, list));
-       }
-
-       ret = 0;
-
-done:
-       lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-       return ret;
-}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
deleted file mode 100644 (file)
index 8fb1706..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
-  * Interface for the wlan network scan routines
-  *
-  * Driver interface functions and type declarations for the scan module
-  * implemented in scan.c.
-  */
-#ifndef _LBS_SCAN_H
-#define _LBS_SCAN_H
-
-#include <net/iw_handler.h>
-
-struct lbs_private;
-
-#define MAX_NETWORK_COUNT 128
-
-/** Chan-freq-TxPower mapping table*/
-struct chan_freq_power {
-       /** channel Number              */
-       u16 channel;
-       /** frequency of this channel   */
-       u32 freq;
-       /** Max allowed Tx power level  */
-       u16 maxtxpower;
-       /** TRUE:channel unsupported;  FLASE:supported*/
-       u8 unsupported;
-};
-
-/** region-band mapping table*/
-struct region_channel {
-       /** TRUE if this entry is valid              */
-       u8 valid;
-       /** region code for US, Japan ...            */
-       u8 region;
-       /** band B/G/A, used for BAND_CONFIG cmd             */
-       u8 band;
-       /** Actual No. of elements in the array below */
-       u8 nrcfp;
-       /** chan-freq-txpower mapping table*/
-       struct chan_freq_power *CFP;
-};
-
-/**
- *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
- */
-#define LBS_IOCTL_USER_SCAN_CHAN_MAX  50
-
-int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
-
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
-                               u8 ssid_len);
-
-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra);
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
-                        union iwreq_data *wrqu, char *extra);
-
-int lbs_scan_networks(struct lbs_private *priv, int full_scan);
-
-void lbs_scan_worker(struct work_struct *work);
-
-#endif
index a9bf658659ebae51d0fe1575b211cbfbdb0ac054..411a3bbf035eaa716393603808b8f2cb7948ac45 100644 (file)
@@ -4,13 +4,13 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
+#include <net/cfg80211.h>
 
 #include "host.h"
 #include "radiotap.h"
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
-#include "wext.h"
 
 /**
  *  @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
@@ -111,7 +111,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        p802x_hdr = skb->data;
        pkt_len = skb->len;
 
-       if (dev == priv->rtap_net_dev) {
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
                struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
 
                /* set txpd fields from the radiotap header */
@@ -147,7 +147,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
-       if (priv->monitormode) {
+       if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
                /* Keep the skb to echo it back once Tx feedback is
                   received from FW */
                skb_orphan(skb);
@@ -158,6 +158,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
  free:
                dev_kfree_skb_any(skb);
        }
+
  unlock:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
        wake_up(&priv->waitq);
@@ -179,7 +180,8 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
 {
        struct tx_radiotap_hdr *radiotap_hdr;
 
-       if (!priv->monitormode || priv->currenttxskb == NULL)
+       if (!priv->wdev->iftype == NL80211_IFTYPE_MONITOR ||
+           priv->currenttxskb == NULL)
                return;
 
        radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
@@ -188,7 +190,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
                (1 + priv->txretrycount - try_count) : 0;
 
        priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
-                                                     priv->rtap_net_dev);
+                                                     priv->dev);
        netif_rx(priv->currenttxskb);
 
        priv->currenttxskb = NULL;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
deleted file mode 100644 (file)
index f96a960..0000000
+++ /dev/null
@@ -1,2353 +0,0 @@
-/**
-  * This file contains ioctl functions
-  */
-#include <linux/ctype.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/bitops.h>
-
-#include <net/lib80211.h>
-#include <net/iw_handler.h>
-
-#include "host.h"
-#include "radiotap.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "wext.h"
-#include "scan.h"
-#include "assoc.h"
-#include "cmd.h"
-
-
-static inline void lbs_postpone_association_work(struct lbs_private *priv)
-{
-       if (priv->surpriseremoved)
-               return;
-       cancel_delayed_work(&priv->assoc_work);
-       queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
-}
-
-static inline void lbs_do_association_work(struct lbs_private *priv)
-{
-       if (priv->surpriseremoved)
-               return;
-       cancel_delayed_work(&priv->assoc_work);
-       queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
-}
-
-static inline void lbs_cancel_association_work(struct lbs_private *priv)
-{
-       cancel_delayed_work(&priv->assoc_work);
-       kfree(priv->pending_assoc_req);
-       priv->pending_assoc_req = NULL;
-}
-
-void lbs_send_disconnect_notification(struct lbs_private *priv)
-{
-       union iwreq_data wrqu;
-
-       memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
-       union iwreq_data iwrq;
-       u8 buf[50];
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       memset(&iwrq, 0, sizeof(union iwreq_data));
-       memset(buf, 0, sizeof(buf));
-
-       snprintf(buf, sizeof(buf) - 1, "%s", str);
-
-       iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
-
-       /* Send Event to upper layer */
-       lbs_deb_wext("event indication string %s\n", (char *)buf);
-       lbs_deb_wext("event indication length %d\n", iwrq.data.length);
-       lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
-
-       wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-/**
- *  @brief This function handles MIC failure event.
- *
- *  @param priv    A pointer to struct lbs_private structure
- *  @para  event   the event id
- *  @return       n/a
- */
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
-{
-       char buf[50];
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       memset(buf, 0, sizeof(buf));
-
-       sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
-
-       if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
-               strcat(buf, "unicast ");
-       else
-               strcat(buf, "multicast ");
-
-       lbs_send_iwevcustom_event(priv, buf);
-       lbs_deb_leave(LBS_DEB_CMD);
-}
-
-/**
- *  @brief Find the channel frequency power info with specific channel
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param band                it can be BAND_A, BAND_G or BAND_B
- *  @param channel      the channel for looking
- *  @return            A pointer to struct chan_freq_power structure or NULL if not find.
- */
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
-       struct lbs_private *priv,
-       u8 band,
-       u16 channel)
-{
-       struct chan_freq_power *cfp = NULL;
-       struct region_channel *rc;
-       int i, j;
-
-       for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
-               rc = &priv->region_channel[j];
-
-               if (!rc->valid || !rc->CFP)
-                       continue;
-               if (rc->band != band)
-                       continue;
-               for (i = 0; i < rc->nrcfp; i++) {
-                       if (rc->CFP[i].channel == channel) {
-                               cfp = &rc->CFP[i];
-                               break;
-                       }
-               }
-       }
-
-       if (!cfp && channel)
-               lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
-                      "cfp by band %d / channel %d\n", band, channel);
-
-       return cfp;
-}
-
-/**
- *  @brief Find the channel frequency power info with specific frequency
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param band                it can be BAND_A, BAND_G or BAND_B
- *  @param freq                the frequency for looking
- *  @return            A pointer to struct chan_freq_power structure or NULL if not find.
- */
-static struct chan_freq_power *find_cfp_by_band_and_freq(
-       struct lbs_private *priv,
-       u8 band,
-       u32 freq)
-{
-       struct chan_freq_power *cfp = NULL;
-       struct region_channel *rc;
-       int i, j;
-
-       for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
-               rc = &priv->region_channel[j];
-
-               if (!rc->valid || !rc->CFP)
-                       continue;
-               if (rc->band != band)
-                       continue;
-               for (i = 0; i < rc->nrcfp; i++) {
-                       if (rc->CFP[i].freq == freq) {
-                               cfp = &rc->CFP[i];
-                               break;
-                       }
-               }
-       }
-
-       if (!cfp && freq)
-               lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
-                      "band %d / freq %d\n", band, freq);
-
-       return cfp;
-}
-
-/**
- *  @brief Copy active data rates based on adapter mode and status
- *
- *  @param priv              A pointer to struct lbs_private structure
- *  @param rate                        The buf to return the active rates
- */
-static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
-{
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if ((priv->connect_status != LBS_CONNECTED) &&
-               !lbs_mesh_connected(priv))
-               memcpy(rates, lbs_bg_rates, MAX_RATES);
-       else
-               memcpy(rates, priv->curbssparams.rates, MAX_RATES);
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
-                        char *cwrq, char *extra)
-{
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /* We could add support for 802.11n here as needed. Jean II */
-       snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_freq *fwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       struct chan_freq_power *cfp;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
-                                          priv->channel);
-
-       if (!cfp) {
-               if (priv->channel)
-                       lbs_deb_wext("invalid channel %d\n",
-                              priv->channel);
-               return -EINVAL;
-       }
-
-       fwrq->m = (long)cfp->freq * 100000;
-       fwrq->e = 1;
-
-       lbs_deb_wext("freq %u\n", fwrq->m);
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
-                       struct sockaddr *awrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (priv->connect_status == LBS_CONNECTED) {
-               memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
-       } else {
-               memset(awrq->sa_data, 0, ETH_ALEN);
-       }
-       awrq->sa_family = ARPHRD_ETHER;
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /*
-        * Check the size of the string
-        */
-
-       if (dwrq->length > 16) {
-               return -E2BIG;
-       }
-
-       mutex_lock(&priv->lock);
-       memset(priv->nodename, 0, sizeof(priv->nodename));
-       memcpy(priv->nodename, extra, dwrq->length);
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       dwrq->length = strlen(priv->nodename);
-       memcpy(extra, priv->nodename, dwrq->length);
-       extra[dwrq->length] = '\0';
-
-       dwrq->flags = 1;        /* active */
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /* Use nickname to indicate that mesh is on */
-
-       if (lbs_mesh_connected(priv)) {
-               strncpy(extra, "Mesh", 12);
-               extra[12] = '\0';
-               dwrq->length = strlen(extra);
-       }
-
-       else {
-               extra[0] = '\0';
-               dwrq->length = 0;
-       }
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-#endif
-
-static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
-                       struct iw_param *vwrq, char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-       u32 val = vwrq->value;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (vwrq->disabled)
-               val = MRVDRV_RTS_MAX_VALUE;
-
-       if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */
-               return -EINVAL;
-
-       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
-                       struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       u16 val = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
-       if (ret)
-               goto out;
-
-       vwrq->value = val;
-       vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */
-       vwrq->fixed = 1;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       u32 val = vwrq->value;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (vwrq->disabled)
-               val = MRVDRV_FRAG_MAX_VALUE;
-
-       if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)
-               return -EINVAL;
-
-       ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
-                        struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       u16 val = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
-       if (ret)
-               goto out;
-
-       vwrq->value = val;
-       vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)
-                         || (val > MRVDRV_FRAG_MAX_VALUE));
-       vwrq->fixed = 1;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_mode(struct net_device *dev,
-                        struct iw_request_info *info, u32 * uwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       *uwrq = priv->mode;
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int mesh_wlan_get_mode(struct net_device *dev,
-                             struct iw_request_info *info, u32 * uwrq,
-                             char *extra)
-{
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       *uwrq = IW_MODE_REPEAT;
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-#endif
-
-static int lbs_get_txpow(struct net_device *dev,
-                         struct iw_request_info *info,
-                         struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       s16 curlevel = 0;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (!priv->radio_on) {
-               lbs_deb_wext("tx power off\n");
-               vwrq->value = 0;
-               vwrq->disabled = 1;
-               goto out;
-       }
-
-       ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
-       if (ret)
-               goto out;
-
-       lbs_deb_wext("tx power level %d dbm\n", curlevel);
-       priv->txpower_cur = curlevel;
-
-       vwrq->value = curlevel;
-       vwrq->fixed = 1;
-       vwrq->disabled = 0;
-       vwrq->flags = IW_TXPOW_DBM;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
-                         struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       u16 slimit = 0, llimit = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-        if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
-                return -EOPNOTSUPP;
-
-       /* The MAC has a 4-bit Total_Tx_Count register
-          Total_Tx_Count = 1 + Tx_Retry_Count */
-#define TX_RETRY_MIN 0
-#define TX_RETRY_MAX 14
-       if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
-               return -EINVAL;
-
-       /* Add 1 to convert retry count to try count */
-       if (vwrq->flags & IW_RETRY_SHORT)
-               slimit = (u16) (vwrq->value + 1);
-       else if (vwrq->flags & IW_RETRY_LONG)
-               llimit = (u16) (vwrq->value + 1);
-       else
-               slimit = llimit = (u16) (vwrq->value + 1); /* set both */
-
-       if (llimit) {
-               ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,
-                                      llimit);
-               if (ret)
-                       goto out;
-       }
-
-       if (slimit) {
-               /* txretrycount follows the short retry limit */
-               priv->txretrycount = slimit;
-               ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,
-                                      slimit);
-               if (ret)
-                       goto out;
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
-                         struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       u16 val = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       vwrq->disabled = 0;
-
-       if (vwrq->flags & IW_RETRY_LONG) {
-               ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);
-               if (ret)
-                       goto out;
-
-               /* Subtract 1 to convert try count to retry count */
-               vwrq->value = val - 1;
-               vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-       } else {
-               ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);
-               if (ret)
-                       goto out;
-
-               /* txretry count follows the short retry limit */
-               priv->txretrycount = val;
-               /* Subtract 1 to convert try count to retry count */
-               vwrq->value = val - 1;
-               vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static inline void sort_channels(struct iw_freq *freq, int num)
-{
-       int i, j;
-       struct iw_freq temp;
-
-       for (i = 0; i < num; i++)
-               for (j = i + 1; j < num; j++)
-                       if (freq[i].i > freq[j].i) {
-                               temp.i = freq[i].i;
-                               temp.m = freq[i].m;
-
-                               freq[i].i = freq[j].i;
-                               freq[i].m = freq[j].m;
-
-                               freq[j].i = temp.i;
-                               freq[j].m = temp.m;
-                       }
-}
-
-/* data rate listing
-       MULTI_BANDS:
-               abg             a       b       b/g
-   Infra       G(12)           A(8)    B(4)    G(12)
-   Adhoc       A+B(12)         A(8)    B(4)    B(4)
-
-       non-MULTI_BANDS:
-                                       b       b/g
-   Infra                               B(4)    G(12)
-   Adhoc                               B(4)    B(4)
- */
-/**
- *  @brief Get Range Info
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info                        A pointer to iw_request_info structure
- *  @param vwrq                A pointer to iw_param structure
- *  @param extra               A pointer to extra data buf
- *  @return                    0 --success, otherwise fail
- */
-static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
-                         struct iw_point *dwrq, char *extra)
-{
-       int i, j;
-       struct lbs_private *priv = dev->ml_priv;
-       struct iw_range *range = (struct iw_range *)extra;
-       struct chan_freq_power *cfp;
-       u8 rates[MAX_RATES + 1];
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       dwrq->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(struct iw_range));
-
-       range->min_nwid = 0;
-       range->max_nwid = 0;
-
-       memset(rates, 0, sizeof(rates));
-       copy_active_data_rates(priv, rates);
-       range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
-       for (i = 0; i < range->num_bitrates; i++)
-               range->bitrate[i] = rates[i] * 500000;
-       range->num_bitrates = i;
-       lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
-              range->num_bitrates);
-
-       range->num_frequency = 0;
-
-       range->scan_capa = IW_SCAN_CAPA_ESSID;
-
-       for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
-            && (j < ARRAY_SIZE(priv->region_channel)); j++) {
-               cfp = priv->region_channel[j].CFP;
-               for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
-                    && priv->region_channel[j].valid
-                    && cfp
-                    && (i < priv->region_channel[j].nrcfp); i++) {
-                       range->freq[range->num_frequency].i =
-                           (long)cfp->channel;
-                       range->freq[range->num_frequency].m =
-                           (long)cfp->freq * 100000;
-                       range->freq[range->num_frequency].e = 1;
-                       cfp++;
-                       range->num_frequency++;
-               }
-       }
-
-       lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
-              IW_MAX_FREQUENCIES, range->num_frequency);
-
-       range->num_channels = range->num_frequency;
-
-       sort_channels(&range->freq[0], range->num_frequency);
-
-       /*
-        * Set an indication of the max TCP throughput in bit/s that we can
-        * expect using this interface
-        */
-       if (i > 2)
-               range->throughput = 5000 * 1000;
-       else
-               range->throughput = 1500 * 1000;
-
-       range->min_rts = MRVDRV_RTS_MIN_VALUE;
-       range->max_rts = MRVDRV_RTS_MAX_VALUE;
-       range->min_frag = MRVDRV_FRAG_MIN_VALUE;
-       range->max_frag = MRVDRV_FRAG_MAX_VALUE;
-
-       range->encoding_size[0] = 5;
-       range->encoding_size[1] = 13;
-       range->num_encoding_sizes = 2;
-       range->max_encoding_tokens = 4;
-
-       /*
-        * Right now we support only "iwconfig ethX power on|off"
-        */
-       range->pm_capa = IW_POWER_ON;
-
-       /*
-        * Minimum version we recommend
-        */
-       range->we_version_source = 15;
-
-       /*
-        * Version we are compiled with
-        */
-       range->we_version_compiled = WIRELESS_EXT;
-
-       range->retry_capa = IW_RETRY_LIMIT;
-       range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-
-       range->min_retry = TX_RETRY_MIN;
-       range->max_retry = TX_RETRY_MAX;
-
-       /*
-        * Set the qual, level and noise range values
-        */
-       range->max_qual.qual = 100;
-       range->max_qual.level = 0;
-       range->max_qual.noise = 0;
-       range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-
-       range->avg_qual.qual = 70;
-       /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
-       range->avg_qual.level = 0;
-       range->avg_qual.noise = 0;
-       range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-
-       range->sensitivity = 0;
-
-       /* Setup the supported power level ranges */
-       memset(range->txpower, 0, sizeof(range->txpower));
-       range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
-       range->txpower[0] = priv->txpower_min;
-       range->txpower[1] = priv->txpower_max;
-       range->num_txpower = 2;
-
-       range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
-                               IW_EVENT_CAPA_MASK(SIOCGIWAP) |
-                               IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
-       range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
-       if (priv->fwcapinfo & FW_CAPINFO_WPA) {
-               range->enc_capa =   IW_ENC_CAPA_WPA
-                                 | IW_ENC_CAPA_WPA2
-                                 | IW_ENC_CAPA_CIPHER_TKIP
-                                 | IW_ENC_CAPA_CIPHER_CCMP;
-       }
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
-                         struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
-               if (vwrq->disabled)
-                       return 0;
-               else
-                       return -EINVAL;
-       }
-
-       /* PS is currently supported only in Infrastructure mode
-        * Remove this check if it is to be supported in IBSS mode also
-        */
-
-       if (vwrq->disabled) {
-               priv->psmode = LBS802_11POWERMODECAM;
-               if (priv->psstate != PS_STATE_FULL_POWER) {
-                       lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-               }
-
-               return 0;
-       }
-
-       if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-               lbs_deb_wext(
-                      "setting power timeout is not supported\n");
-               return -EINVAL;
-       } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
-               vwrq->value = vwrq->value / 1000;
-               if (!priv->enter_deep_sleep) {
-                       lbs_pr_err("deep sleep feature is not implemented "
-                                       "for this interface driver\n");
-                       return -EINVAL;
-               }
-
-               if (priv->connect_status == LBS_CONNECTED) {
-                       if ((priv->is_auto_deep_sleep_enabled) &&
-                                               (vwrq->value == -1000)) {
-                               lbs_exit_auto_deep_sleep(priv);
-                               return 0;
-                       } else {
-                               lbs_pr_err("can't use deep sleep cmd in "
-                                               "connected state\n");
-                               return -EINVAL;
-                       }
-               }
-
-               if ((vwrq->value < 0) && (vwrq->value != -1000)) {
-                       lbs_pr_err("unknown option\n");
-                       return -EINVAL;
-               }
-
-               if (vwrq->value > 0) {
-                       if (!priv->is_auto_deep_sleep_enabled) {
-                               priv->is_activity_detected = 0;
-                               priv->auto_deep_sleep_timeout = vwrq->value;
-                               lbs_enter_auto_deep_sleep(priv);
-                       } else {
-                               priv->auto_deep_sleep_timeout = vwrq->value;
-                               lbs_deb_debugfs("auto deep sleep: "
-                                               "already enabled\n");
-                       }
-                       return 0;
-               } else {
-                       if (priv->is_auto_deep_sleep_enabled) {
-                               lbs_exit_auto_deep_sleep(priv);
-                               /* Try to exit deep sleep if auto */
-                               /*deep sleep disabled */
-                               ret = lbs_set_deep_sleep(priv, 0);
-                       }
-                       if (vwrq->value == 0)
-                               ret = lbs_set_deep_sleep(priv, 1);
-                       else if (vwrq->value == -1000)
-                               ret = lbs_set_deep_sleep(priv, 0);
-                       return ret;
-               }
-       }
-
-       if (priv->psmode != LBS802_11POWERMODECAM) {
-               return 0;
-       }
-
-       priv->psmode = LBS802_11POWERMODEMAX_PSP;
-
-       if (priv->connect_status == LBS_CONNECTED) {
-               lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
-       }
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-
-       return 0;
-}
-
-static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
-                         struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       vwrq->value = 0;
-       vwrq->flags = 0;
-       vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM
-               || priv->connect_status == LBS_DISCONNECTED;
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
-{
-       enum {
-               POOR = 30,
-               FAIR = 60,
-               GOOD = 80,
-               VERY_GOOD = 90,
-               EXCELLENT = 95,
-               PERFECT = 100
-       };
-       struct lbs_private *priv = dev->ml_priv;
-       u32 rssi_qual;
-       u32 tx_qual;
-       u32 quality = 0;
-       int ret, stats_valid = 0;
-       u8 rssi;
-       u32 tx_retries;
-       struct cmd_ds_802_11_get_log log;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       priv->wstats.status = priv->mode;
-
-       /* If we're not associated, all quality values are meaningless */
-       if ((priv->connect_status != LBS_CONNECTED) &&
-           !lbs_mesh_connected(priv))
-               goto out;
-
-       /* Quality by RSSI */
-       priv->wstats.qual.level =
-           CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
-            priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
-       if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
-               priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
-       } else {
-               priv->wstats.qual.noise =
-                   CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-       }
-
-       lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
-       lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
-
-       rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
-       if (rssi < 15)
-               rssi_qual = rssi * POOR / 10;
-       else if (rssi < 20)
-               rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
-       else if (rssi < 30)
-               rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
-       else if (rssi < 40)
-               rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
-                   10 + GOOD;
-       else
-               rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
-                   10 + VERY_GOOD;
-       quality = rssi_qual;
-
-       /* Quality by TX errors */
-       priv->wstats.discard.retries = dev->stats.tx_errors;
-
-       memset(&log, 0, sizeof(log));
-       log.hdr.size = cpu_to_le16(sizeof(log));
-       ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
-       if (ret)
-               goto out;
-
-       tx_retries = le32_to_cpu(log.retry);
-
-       if (tx_retries > 75)
-               tx_qual = (90 - tx_retries) * POOR / 15;
-       else if (tx_retries > 70)
-               tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
-       else if (tx_retries > 65)
-               tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
-       else if (tx_retries > 50)
-               tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
-                   15 + GOOD;
-       else
-               tx_qual = (50 - tx_retries) *
-                   (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
-       quality = min(quality, tx_qual);
-
-       priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);
-       priv->wstats.discard.retries = tx_retries;
-       priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);
-
-       /* Calculate quality */
-       priv->wstats.qual.qual = min_t(u8, quality, 100);
-       priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-       stats_valid = 1;
-
-       /* update stats asynchronously for future calls */
-       ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
-                                       0, 0, NULL);
-       if (ret)
-               lbs_pr_err("RSSI command failed\n");
-out:
-       if (!stats_valid) {
-               priv->wstats.miss.beacon = 0;
-               priv->wstats.discard.retries = 0;
-               priv->wstats.qual.qual = 0;
-               priv->wstats.qual.level = 0;
-               priv->wstats.qual.noise = 0;
-               priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
-               priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
-                   IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
-       }
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return &priv->wstats;
-
-
-}
-
-static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
-                 struct iw_freq *fwrq, char *extra)
-{
-       int ret = -EINVAL;
-       struct lbs_private *priv = dev->ml_priv;
-       struct chan_freq_power *cfp;
-       struct assoc_request * assoc_req;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       mutex_lock(&priv->lock);
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       /* If setting by frequency, convert to a channel */
-       if (fwrq->e == 1) {
-               long f = fwrq->m / 100000;
-
-               cfp = find_cfp_by_band_and_freq(priv, 0, f);
-               if (!cfp) {
-                       lbs_deb_wext("invalid freq %ld\n", f);
-                       goto out;
-               }
-
-               fwrq->e = 0;
-               fwrq->m = (int) cfp->channel;
-       }
-
-       /* Setting by channel number */
-       if (fwrq->m > 1000 || fwrq->e > 0) {
-               goto out;
-       }
-
-       cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
-       if (!cfp) {
-               goto out;
-       }
-
-       assoc_req->channel = fwrq->m;
-       ret = 0;
-
-out:
-       if (ret == 0) {
-               set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
-               lbs_postpone_association_work(priv);
-       } else {
-               lbs_cancel_association_work(priv);
-       }
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int lbs_mesh_set_freq(struct net_device *dev,
-                            struct iw_request_info *info,
-                            struct iw_freq *fwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       struct chan_freq_power *cfp;
-       int ret = -EINVAL;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /* If setting by frequency, convert to a channel */
-       if (fwrq->e == 1) {
-               long f = fwrq->m / 100000;
-
-               cfp = find_cfp_by_band_and_freq(priv, 0, f);
-               if (!cfp) {
-                       lbs_deb_wext("invalid freq %ld\n", f);
-                       goto out;
-               }
-
-               fwrq->e = 0;
-               fwrq->m = (int) cfp->channel;
-       }
-
-       /* Setting by channel number */
-       if (fwrq->m > 1000 || fwrq->e > 0) {
-               goto out;
-       }
-
-       cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
-       if (!cfp) {
-               goto out;
-       }
-
-       if (fwrq->m != priv->channel) {
-               lbs_deb_wext("mesh channel change forces eth disconnect\n");
-               if (priv->mode == IW_MODE_INFRA)
-                       lbs_cmd_80211_deauthenticate(priv,
-                                                    priv->curbssparams.bssid,
-                                                    WLAN_REASON_DEAUTH_LEAVING);
-               else if (priv->mode == IW_MODE_ADHOC)
-                       lbs_adhoc_stop(priv);
-       }
-       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
-       lbs_update_channel(priv);
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-#endif
-
-static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
-                 struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       u8 new_rate = 0;
-       int ret = -EINVAL;
-       u8 rates[MAX_RATES + 1];
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       lbs_deb_wext("vwrq->value %d\n", vwrq->value);
-       lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
-
-       if (vwrq->fixed && vwrq->value == -1)
-               goto out;
-
-       /* Auto rate? */
-       priv->enablehwauto = !vwrq->fixed;
-
-       if (vwrq->value == -1)
-               priv->cur_rate = 0;
-       else {
-               if (vwrq->value % 100000)
-                       goto out;
-
-               new_rate = vwrq->value / 500000;
-               priv->cur_rate = new_rate;
-               /* the rest is only needed for lbs_set_data_rate() */
-               memset(rates, 0, sizeof(rates));
-               copy_active_data_rates(priv, rates);
-               if (!memchr(rates, new_rate, sizeof(rates))) {
-                       lbs_pr_alert("fixed data rate 0x%X out of range\n",
-                               new_rate);
-                       goto out;
-               }
-               if (priv->fwrelease < 0x09000000) {
-                       ret = lbs_set_power_adapt_cfg(priv, 0,
-                                       POW_ADAPT_DEFAULT_P0,
-                                       POW_ADAPT_DEFAULT_P1,
-                                       POW_ADAPT_DEFAULT_P2);
-                       if (ret)
-                               goto out;
-               }
-               ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
-                               TPC_DEFAULT_P2, 1);
-               if (ret)
-                       goto out;
-       }
-
-       /* Try the newer command first (Firmware Spec 5.1 and above) */
-       ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
-
-       /* Fallback to older version */
-       if (ret)
-               ret = lbs_set_data_rate(priv, new_rate);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
-                 struct iw_param *vwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (priv->connect_status == LBS_CONNECTED) {
-               vwrq->value = priv->cur_rate * 500000;
-
-               if (priv->enablehwauto)
-                       vwrq->fixed = 0;
-               else
-                       vwrq->fixed = 1;
-
-       } else {
-               vwrq->fixed = 0;
-               vwrq->value = 0;
-       }
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_set_mode(struct net_device *dev,
-                 struct iw_request_info *info, u32 * uwrq, char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-       struct assoc_request * assoc_req;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (   (*uwrq != IW_MODE_ADHOC)
-           && (*uwrq != IW_MODE_INFRA)
-           && (*uwrq != IW_MODE_AUTO)) {
-               lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       mutex_lock(&priv->lock);
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               ret = -ENOMEM;
-               lbs_cancel_association_work(priv);
-       } else {
-               assoc_req->mode = *uwrq;
-               set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
-               lbs_postpone_association_work(priv);
-               lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
-       }
-       mutex_unlock(&priv->lock);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-
-/**
- *  @brief Get Encryption key
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info                        A pointer to iw_request_info structure
- *  @param vwrq                A pointer to iw_param structure
- *  @param extra               A pointer to extra data buf
- *  @return                    0 --success, otherwise fail
- */
-static int lbs_get_encode(struct net_device *dev,
-                          struct iw_request_info *info,
-                          struct iw_point *dwrq, u8 * extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
-              dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
-
-       dwrq->flags = 0;
-
-       /* Authentication method */
-       switch (priv->secinfo.auth_mode) {
-       case IW_AUTH_ALG_OPEN_SYSTEM:
-               dwrq->flags = IW_ENCODE_OPEN;
-               break;
-
-       case IW_AUTH_ALG_SHARED_KEY:
-       case IW_AUTH_ALG_LEAP:
-               dwrq->flags = IW_ENCODE_RESTRICTED;
-               break;
-       default:
-               dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
-               break;
-       }
-
-       memset(extra, 0, 16);
-
-       mutex_lock(&priv->lock);
-
-       /* Default to returning current transmit key */
-       if (index < 0)
-               index = priv->wep_tx_keyidx;
-
-       if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
-               memcpy(extra, priv->wep_keys[index].key,
-                      priv->wep_keys[index].len);
-               dwrq->length = priv->wep_keys[index].len;
-
-               dwrq->flags |= (index + 1);
-               /* Return WEP enabled */
-               dwrq->flags &= ~IW_ENCODE_DISABLED;
-       } else if ((priv->secinfo.WPAenabled)
-                  || (priv->secinfo.WPA2enabled)) {
-               /* return WPA enabled */
-               dwrq->flags &= ~IW_ENCODE_DISABLED;
-               dwrq->flags |= IW_ENCODE_NOKEY;
-       } else {
-               dwrq->flags |= IW_ENCODE_DISABLED;
-       }
-
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
-              extra[0], extra[1], extra[2],
-              extra[3], extra[4], extra[5], dwrq->length);
-
-       lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-/**
- *  @brief Set Encryption key (internal)
- *
- *  @param priv                        A pointer to private card structure
- *  @param key_material                A pointer to key material
- *  @param key_length          length of key material
- *  @param index               key index to set
- *  @param set_tx_key          Force set TX key (1 = yes, 0 = no)
- *  @return                    0 --success, otherwise fail
- */
-static int lbs_set_wep_key(struct assoc_request *assoc_req,
-                           const char *key_material,
-                           u16 key_length,
-                           u16 index,
-                           int set_tx_key)
-{
-       int ret = 0;
-       struct enc_key *pkey;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /* Paranoid validation of key index */
-       if (index > 3) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* validate max key length */
-       if (key_length > KEY_LEN_WEP_104) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       pkey = &assoc_req->wep_keys[index];
-
-       if (key_length > 0) {
-               memset(pkey, 0, sizeof(struct enc_key));
-               pkey->type = KEY_TYPE_ID_WEP;
-
-               /* Standardize the key length */
-               pkey->len = (key_length > KEY_LEN_WEP_40) ?
-                               KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
-               memcpy(pkey->key, key_material, key_length);
-       }
-
-       if (set_tx_key) {
-               /* Ensure the chosen key is valid */
-               if (!pkey->len) {
-                       lbs_deb_wext("key not set, so cannot enable it\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-               assoc_req->wep_tx_keyidx = index;
-       }
-
-       assoc_req->secinfo.wep_enabled = 1;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int validate_key_index(u16 def_index, u16 raw_index,
-                             u16 *out_index, u16 *is_default)
-{
-       if (!out_index || !is_default)
-               return -EINVAL;
-
-       /* Verify index if present, otherwise use default TX key index */
-       if (raw_index > 0) {
-               if (raw_index > 4)
-                       return -EINVAL;
-               *out_index = raw_index - 1;
-       } else {
-               *out_index = def_index;
-               *is_default = 1;
-       }
-       return 0;
-}
-
-static void disable_wep(struct assoc_request *assoc_req)
-{
-       int i;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /* Set Open System auth mode */
-       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-
-       /* Clear WEP keys and mark WEP as disabled */
-       assoc_req->secinfo.wep_enabled = 0;
-       for (i = 0; i < 4; i++)
-               assoc_req->wep_keys[i].len = 0;
-
-       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-       set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static void disable_wpa(struct assoc_request *assoc_req)
-{
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
-       assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
-       set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-
-       memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
-       assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
-       set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-
-       assoc_req->secinfo.WPAenabled = 0;
-       assoc_req->secinfo.WPA2enabled = 0;
-       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-/**
- *  @brief Set Encryption key
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info                        A pointer to iw_request_info structure
- *  @param vwrq                A pointer to iw_param structure
- *  @param extra               A pointer to extra data buf
- *  @return                    0 --success, otherwise fail
- */
-static int lbs_set_encode(struct net_device *dev,
-                   struct iw_request_info *info,
-                   struct iw_point *dwrq, char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-       struct assoc_request * assoc_req;
-       u16 is_default = 0, index = 0, set_tx_key = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       mutex_lock(&priv->lock);
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       if (dwrq->flags & IW_ENCODE_DISABLED) {
-               disable_wep (assoc_req);
-               disable_wpa (assoc_req);
-               goto out;
-       }
-
-       ret = validate_key_index(assoc_req->wep_tx_keyidx,
-                                (dwrq->flags & IW_ENCODE_INDEX),
-                                &index, &is_default);
-       if (ret) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* If WEP isn't enabled, or if there is no key data but a valid
-        * index, set the TX key.
-        */
-       if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
-               set_tx_key = 1;
-
-       ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
-       if (ret)
-               goto out;
-
-       if (dwrq->length)
-               set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-       if (set_tx_key)
-               set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
-
-       if (dwrq->flags & IW_ENCODE_RESTRICTED) {
-               priv->authtype_auto = 0;
-               assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-       } else if (dwrq->flags & IW_ENCODE_OPEN) {
-               priv->authtype_auto = 0;
-               assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-       }
-
-out:
-       if (ret == 0) {
-               set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-               lbs_postpone_association_work(priv);
-       } else {
-               lbs_cancel_association_work(priv);
-       }
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info                        A pointer to iw_request_info structure
- *  @param vwrq                A pointer to iw_param structure
- *  @param extra               A pointer to extra data buf
- *  @return                    0 on success, otherwise failure
- */
-static int lbs_get_encodeext(struct net_device *dev,
-                             struct iw_request_info *info,
-                             struct iw_point *dwrq,
-                             char *extra)
-{
-       int ret = -EINVAL;
-       struct lbs_private *priv = dev->ml_priv;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       int index, max_key_len;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       max_key_len = dwrq->length - sizeof(*ext);
-       if (max_key_len < 0)
-               goto out;
-
-       index = dwrq->flags & IW_ENCODE_INDEX;
-       if (index) {
-               if (index < 1 || index > 4)
-                       goto out;
-               index--;
-       } else {
-               index = priv->wep_tx_keyidx;
-       }
-
-       if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
-           ext->alg != IW_ENCODE_ALG_WEP) {
-               if (index != 0 || priv->mode != IW_MODE_INFRA)
-                       goto out;
-       }
-
-       dwrq->flags = index + 1;
-       memset(ext, 0, sizeof(*ext));
-
-       if (   !priv->secinfo.wep_enabled
-           && !priv->secinfo.WPAenabled
-           && !priv->secinfo.WPA2enabled) {
-               ext->alg = IW_ENCODE_ALG_NONE;
-               ext->key_len = 0;
-               dwrq->flags |= IW_ENCODE_DISABLED;
-       } else {
-               u8 *key = NULL;
-
-               if (   priv->secinfo.wep_enabled
-                   && !priv->secinfo.WPAenabled
-                   && !priv->secinfo.WPA2enabled) {
-                       /* WEP */
-                       ext->alg = IW_ENCODE_ALG_WEP;
-                       ext->key_len = priv->wep_keys[index].len;
-                       key = &priv->wep_keys[index].key[0];
-               } else if (   !priv->secinfo.wep_enabled
-                          && (priv->secinfo.WPAenabled ||
-                              priv->secinfo.WPA2enabled)) {
-                       /* WPA */
-                       struct enc_key * pkey = NULL;
-
-                       if (   priv->wpa_mcast_key.len
-                           && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
-                               pkey = &priv->wpa_mcast_key;
-                       else if (   priv->wpa_unicast_key.len
-                                && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
-                               pkey = &priv->wpa_unicast_key;
-
-                       if (pkey) {
-                               if (pkey->type == KEY_TYPE_ID_AES) {
-                                       ext->alg = IW_ENCODE_ALG_CCMP;
-                               } else {
-                                       ext->alg = IW_ENCODE_ALG_TKIP;
-                               }
-                               ext->key_len = pkey->len;
-                               key = &pkey->key[0];
-                       } else {
-                               ext->alg = IW_ENCODE_ALG_TKIP;
-                               ext->key_len = 0;
-                       }
-               } else {
-                       goto out;
-               }
-
-               if (ext->key_len > max_key_len) {
-                       ret = -E2BIG;
-                       goto out;
-               }
-
-               if (ext->key_len)
-                       memcpy(ext->key, key, ext->key_len);
-               else
-                       dwrq->flags |= IW_ENCODE_NOKEY;
-               dwrq->flags |= IW_ENCODE_ENABLED;
-       }
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-/**
- *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info                        A pointer to iw_request_info structure
- *  @param vwrq                A pointer to iw_param structure
- *  @param extra               A pointer to extra data buf
- *  @return                    0 --success, otherwise fail
- */
-static int lbs_set_encodeext(struct net_device *dev,
-                             struct iw_request_info *info,
-                             struct iw_point *dwrq,
-                             char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       int alg = ext->alg;
-       struct assoc_request * assoc_req;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       mutex_lock(&priv->lock);
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
-               disable_wep (assoc_req);
-               disable_wpa (assoc_req);
-       } else if (alg == IW_ENCODE_ALG_WEP) {
-               u16 is_default = 0, index, set_tx_key = 0;
-
-               ret = validate_key_index(assoc_req->wep_tx_keyidx,
-                                        (dwrq->flags & IW_ENCODE_INDEX),
-                                        &index, &is_default);
-               if (ret)
-                       goto out;
-
-               /* If WEP isn't enabled, or if there is no key data but a valid
-                * index, or if the set-TX-key flag was passed, set the TX key.
-                */
-               if (   !assoc_req->secinfo.wep_enabled
-                   || (dwrq->length == 0 && !is_default)
-                   || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
-                       set_tx_key = 1;
-
-               /* Copy key to driver */
-               ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
-                                       set_tx_key);
-               if (ret)
-                       goto out;
-
-               if (dwrq->flags & IW_ENCODE_RESTRICTED) {
-                       priv->authtype_auto = 0;
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-               } else if (dwrq->flags & IW_ENCODE_OPEN) {
-                       priv->authtype_auto = 0;
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-               }
-
-               /* Mark the various WEP bits as modified */
-               set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-               if (dwrq->length)
-                       set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-               if (set_tx_key)
-                       set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
-       } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
-               struct enc_key * pkey;
-
-               /* validate key length */
-               if (((alg == IW_ENCODE_ALG_TKIP)
-                       && (ext->key_len != KEY_LEN_WPA_TKIP))
-                   || ((alg == IW_ENCODE_ALG_CCMP)
-                       && (ext->key_len != KEY_LEN_WPA_AES))) {
-                               lbs_deb_wext("invalid size %d for key of alg "
-                                      "type %d\n",
-                                      ext->key_len,
-                                      alg);
-                               ret = -EINVAL;
-                               goto out;
-               }
-
-               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
-                       pkey = &assoc_req->wpa_mcast_key;
-                       set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-               } else {
-                       pkey = &assoc_req->wpa_unicast_key;
-                       set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-               }
-
-               memset(pkey, 0, sizeof (struct enc_key));
-               memcpy(pkey->key, ext->key, ext->key_len);
-               pkey->len = ext->key_len;
-               if (pkey->len)
-                       pkey->flags |= KEY_INFO_WPA_ENABLED;
-
-               /* Do this after zeroing key structure */
-               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
-                       pkey->flags |= KEY_INFO_WPA_MCAST;
-               } else {
-                       pkey->flags |= KEY_INFO_WPA_UNICAST;
-               }
-
-               if (alg == IW_ENCODE_ALG_TKIP) {
-                       pkey->type = KEY_TYPE_ID_TKIP;
-               } else if (alg == IW_ENCODE_ALG_CCMP) {
-                       pkey->type = KEY_TYPE_ID_AES;
-               }
-
-               /* If WPA isn't enabled yet, do that now */
-               if (   assoc_req->secinfo.WPAenabled == 0
-                   && assoc_req->secinfo.WPA2enabled == 0) {
-                       assoc_req->secinfo.WPAenabled = 1;
-                       assoc_req->secinfo.WPA2enabled = 1;
-                       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-               }
-
-               /* Only disable wep if necessary: can't waste time here. */
-               if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
-                       disable_wep(assoc_req);
-       }
-
-out:
-       if (ret == 0) {
-               /* 802.1x and WPA rekeying must happen as quickly as possible,
-                * especially during the 4-way handshake; thus if in
-                * infrastructure mode, and either (a) 802.1x is enabled or
-                * (b) WPA is being used, set the key right away.
-                */
-               if (assoc_req->mode == IW_MODE_INFRA &&
-                   ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
-                    (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
-                     assoc_req->secinfo.WPAenabled ||
-                     assoc_req->secinfo.WPA2enabled)) {
-                       lbs_do_association_work(priv);
-               } else
-                       lbs_postpone_association_work(priv);
-       } else {
-               lbs_cancel_association_work(priv);
-       }
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-
-static int lbs_set_genie(struct net_device *dev,
-                         struct iw_request_info *info,
-                         struct iw_point *dwrq,
-                         char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       struct assoc_request * assoc_req;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       mutex_lock(&priv->lock);
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       if (dwrq->length > MAX_WPA_IE_LEN ||
-           (dwrq->length && extra == NULL)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (dwrq->length) {
-               memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
-               assoc_req->wpa_ie_len = dwrq->length;
-       } else {
-               memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
-               assoc_req->wpa_ie_len = 0;
-       }
-
-out:
-       if (ret == 0) {
-               set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
-               lbs_postpone_association_work(priv);
-       } else {
-               lbs_cancel_association_work(priv);
-       }
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_genie(struct net_device *dev,
-                         struct iw_request_info *info,
-                         struct iw_point *dwrq,
-                         char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (priv->wpa_ie_len == 0) {
-               dwrq->length = 0;
-               goto out;
-       }
-
-       if (dwrq->length < priv->wpa_ie_len) {
-               ret = -E2BIG;
-               goto out;
-       }
-
-       dwrq->length = priv->wpa_ie_len;
-       memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-
-static int lbs_set_auth(struct net_device *dev,
-                        struct iw_request_info *info,
-                        struct iw_param *dwrq,
-                        char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       struct assoc_request * assoc_req;
-       int ret = 0;
-       int updated = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       mutex_lock(&priv->lock);
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       switch (dwrq->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_PRIVACY_INVOKED:
-       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-       case IW_AUTH_TKIP_COUNTERMEASURES:
-       case IW_AUTH_CIPHER_PAIRWISE:
-       case IW_AUTH_CIPHER_GROUP:
-       case IW_AUTH_DROP_UNENCRYPTED:
-               /*
-                * libertas does not use these parameters
-                */
-               break;
-
-       case IW_AUTH_KEY_MGMT:
-               assoc_req->secinfo.key_mgmt = dwrq->value;
-               updated = 1;
-               break;
-
-       case IW_AUTH_WPA_VERSION:
-               if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
-                       assoc_req->secinfo.WPAenabled = 0;
-                       assoc_req->secinfo.WPA2enabled = 0;
-                       disable_wpa (assoc_req);
-               }
-               if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
-                       assoc_req->secinfo.WPAenabled = 1;
-                       assoc_req->secinfo.wep_enabled = 0;
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-               }
-               if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
-                       assoc_req->secinfo.WPA2enabled = 1;
-                       assoc_req->secinfo.wep_enabled = 0;
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-               }
-               updated = 1;
-               break;
-
-       case IW_AUTH_80211_AUTH_ALG:
-               if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-               } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-               } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
-                       assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
-               } else {
-                       ret = -EINVAL;
-               }
-               updated = 1;
-               break;
-
-       case IW_AUTH_WPA_ENABLED:
-               if (dwrq->value) {
-                       if (!assoc_req->secinfo.WPAenabled &&
-                           !assoc_req->secinfo.WPA2enabled) {
-                               assoc_req->secinfo.WPAenabled = 1;
-                               assoc_req->secinfo.WPA2enabled = 1;
-                               assoc_req->secinfo.wep_enabled = 0;
-                               assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-                       }
-               } else {
-                       assoc_req->secinfo.WPAenabled = 0;
-                       assoc_req->secinfo.WPA2enabled = 0;
-                       disable_wpa (assoc_req);
-               }
-               updated = 1;
-               break;
-
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-out:
-       if (ret == 0) {
-               if (updated)
-                       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-               lbs_postpone_association_work(priv);
-       } else if (ret != -EOPNOTSUPP) {
-               lbs_cancel_association_work(priv);
-       }
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_auth(struct net_device *dev,
-                        struct iw_request_info *info,
-                        struct iw_param *dwrq,
-                        char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       switch (dwrq->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_KEY_MGMT:
-               dwrq->value = priv->secinfo.key_mgmt;
-               break;
-
-       case IW_AUTH_WPA_VERSION:
-               dwrq->value = 0;
-               if (priv->secinfo.WPAenabled)
-                       dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
-               if (priv->secinfo.WPA2enabled)
-                       dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
-               if (!dwrq->value)
-                       dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
-               break;
-
-       case IW_AUTH_80211_AUTH_ALG:
-               dwrq->value = priv->secinfo.auth_mode;
-               break;
-
-       case IW_AUTH_WPA_ENABLED:
-               if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
-                       dwrq->value = 1;
-               break;
-
-       default:
-               ret = -EOPNOTSUPP;
-       }
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-
-static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
-                  struct iw_param *vwrq, char *extra)
-{
-       int ret = 0;
-       struct lbs_private *priv = dev->ml_priv;
-       s16 dbm = (s16) vwrq->value;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (vwrq->disabled) {
-               lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
-               goto out;
-       }
-
-       if (vwrq->fixed == 0) {
-               /* User requests automatic tx power control, however there are
-                * many auto tx settings.  For now use firmware defaults until
-                * we come up with a good way to expose these to the user. */
-               if (priv->fwrelease < 0x09000000) {
-                       ret = lbs_set_power_adapt_cfg(priv, 1,
-                                       POW_ADAPT_DEFAULT_P0,
-                                       POW_ADAPT_DEFAULT_P1,
-                                       POW_ADAPT_DEFAULT_P2);
-                       if (ret)
-                               goto out;
-               }
-               ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
-                               TPC_DEFAULT_P2, 1);
-               if (ret)
-                       goto out;
-               dbm = priv->txpower_max;
-       } else {
-               /* Userspace check in iwrange if it should use dBm or mW,
-                * therefore this should never happen... Jean II */
-               if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
-                       ret = -EOPNOTSUPP;
-                       goto out;
-               }
-
-               /* Validate requested power level against firmware allowed
-                * levels */
-               if (priv->txpower_min && (dbm < priv->txpower_min)) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               if (priv->txpower_max && (dbm > priv->txpower_max)) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-               if (priv->fwrelease < 0x09000000) {
-                       ret = lbs_set_power_adapt_cfg(priv, 0,
-                                       POW_ADAPT_DEFAULT_P0,
-                                       POW_ADAPT_DEFAULT_P1,
-                                       POW_ADAPT_DEFAULT_P2);
-                       if (ret)
-                               goto out;
-               }
-               ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
-                               TPC_DEFAULT_P2, 1);
-               if (ret)
-                       goto out;
-       }
-
-       /* If the radio was off, turn it on */
-       if (!priv->radio_on) {
-               ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
-               if (ret)
-                       goto out;
-       }
-
-       lbs_deb_wext("txpower set %d dBm\n", dbm);
-
-       ret = lbs_set_tx_power(priv, dbm);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
-                  struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       /*
-        * Note : if dwrq->flags != 0, we should get the relevant SSID from
-        * the SSID list...
-        */
-
-       /*
-        * Get the current SSID
-        */
-       if (priv->connect_status == LBS_CONNECTED) {
-               memcpy(extra, priv->curbssparams.ssid,
-                      priv->curbssparams.ssid_len);
-       } else {
-               memset(extra, 0, 32);
-       }
-       /*
-        * If none, we may want to get the one that was set
-        */
-
-       dwrq->length = priv->curbssparams.ssid_len;
-
-       dwrq->flags = 1;        /* active */
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
-                  struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       u8 ssid_len = 0;
-       struct assoc_request * assoc_req;
-       int in_ssid_len = dwrq->length;
-       DECLARE_SSID_BUF(ssid_buf);
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (!priv->radio_on) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* Check the size of the string */
-       if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
-               ret = -E2BIG;
-               goto out;
-       }
-
-       memset(&ssid, 0, sizeof(ssid));
-
-       if (!dwrq->flags || !in_ssid_len) {
-               /* "any" SSID requested; leave SSID blank */
-       } else {
-               /* Specific SSID requested */
-               memcpy(&ssid, extra, in_ssid_len);
-               ssid_len = in_ssid_len;
-       }
-
-       if (!ssid_len) {
-               lbs_deb_wext("requested any SSID\n");
-       } else {
-               lbs_deb_wext("requested SSID '%s'\n",
-                            print_ssid(ssid_buf, ssid, ssid_len));
-       }
-
-out:
-       mutex_lock(&priv->lock);
-       if (ret == 0) {
-               /* Get or create the current association request */
-               assoc_req = lbs_get_association_request(priv);
-               if (!assoc_req) {
-                       ret = -ENOMEM;
-               } else {
-                       /* Copy the SSID to the association request */
-                       memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
-                       assoc_req->ssid_len = ssid_len;
-                       set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-                       lbs_postpone_association_work(priv);
-               }
-       }
-
-       /* Cancel the association request if there was an error */
-       if (ret != 0) {
-               lbs_cancel_association_work(priv);
-       }
-
-       mutex_unlock(&priv->lock);
-
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int lbs_mesh_get_essid(struct net_device *dev,
-                             struct iw_request_info *info,
-                             struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
-
-       dwrq->length = priv->mesh_ssid_len;
-
-       dwrq->flags = 1;        /* active */
-
-       lbs_deb_leave(LBS_DEB_WEXT);
-       return 0;
-}
-
-static int lbs_mesh_set_essid(struct net_device *dev,
-                             struct iw_request_info *info,
-                             struct iw_point *dwrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (!priv->radio_on) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* Check the size of the string */
-       if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
-               ret = -E2BIG;
-               goto out;
-       }
-
-       if (!dwrq->flags || !dwrq->length) {
-               ret = -EINVAL;
-               goto out;
-       } else {
-               /* Specific SSID requested */
-               memcpy(priv->mesh_ssid, extra, dwrq->length);
-               priv->mesh_ssid_len = dwrq->length;
-       }
-
-       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-                       priv->channel);
- out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
-#endif
-
-/**
- *  @brief Connect to the AP or Ad-hoc Network with specific bssid
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param awrq         A pointer to iw_param structure
- *  @param extra        A pointer to extra data buf
- *  @return             0 --success, otherwise fail
- */
-static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
-                struct sockaddr *awrq, char *extra)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       struct assoc_request * assoc_req;
-       int ret = 0;
-
-       lbs_deb_enter(LBS_DEB_WEXT);
-
-       if (!priv->radio_on)
-               return -EINVAL;
-
-       if (awrq->sa_family != ARPHRD_ETHER)
-               return -EINVAL;
-
-       lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
-
-       mutex_lock(&priv->lock);
-
-       /* Get or create the current association request */
-       assoc_req = lbs_get_association_request(priv);
-       if (!assoc_req) {
-               lbs_cancel_association_work(priv);
-               ret = -ENOMEM;
-       } else {
-               /* Copy the BSSID to the association request */
-               memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
-               set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
-               lbs_postpone_association_work(priv);
-       }
-
-       mutex_unlock(&priv->lock);
-
-       return ret;
-}
-
-/*
- * iwconfig settable callbacks
- */
-static const iw_handler lbs_handler[] = {
-       (iw_handler) NULL,      /* SIOCSIWCOMMIT */
-       (iw_handler) lbs_get_name,      /* SIOCGIWNAME */
-       (iw_handler) NULL,      /* SIOCSIWNWID */
-       (iw_handler) NULL,      /* SIOCGIWNWID */
-       (iw_handler) lbs_set_freq,      /* SIOCSIWFREQ */
-       (iw_handler) lbs_get_freq,      /* SIOCGIWFREQ */
-       (iw_handler) lbs_set_mode,      /* SIOCSIWMODE */
-       (iw_handler) lbs_get_mode,      /* SIOCGIWMODE */
-       (iw_handler) NULL,      /* SIOCSIWSENS */
-       (iw_handler) NULL,      /* SIOCGIWSENS */
-       (iw_handler) NULL,      /* SIOCSIWRANGE */
-       (iw_handler) lbs_get_range,     /* SIOCGIWRANGE */
-       (iw_handler) NULL,      /* SIOCSIWPRIV */
-       (iw_handler) NULL,      /* SIOCGIWPRIV */
-       (iw_handler) NULL,      /* SIOCSIWSTATS */
-       (iw_handler) NULL,      /* SIOCGIWSTATS */
-       iw_handler_set_spy,     /* SIOCSIWSPY */
-       iw_handler_get_spy,     /* SIOCGIWSPY */
-       iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
-       iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
-       (iw_handler) lbs_set_wap,       /* SIOCSIWAP */
-       (iw_handler) lbs_get_wap,       /* SIOCGIWAP */
-       (iw_handler) NULL,      /* SIOCSIWMLME */
-       (iw_handler) NULL,      /* SIOCGIWAPLIST - deprecated */
-       (iw_handler) lbs_set_scan,      /* SIOCSIWSCAN */
-       (iw_handler) lbs_get_scan,      /* SIOCGIWSCAN */
-       (iw_handler) lbs_set_essid,     /* SIOCSIWESSID */
-       (iw_handler) lbs_get_essid,     /* SIOCGIWESSID */
-       (iw_handler) lbs_set_nick,      /* SIOCSIWNICKN */
-       (iw_handler) lbs_get_nick,      /* SIOCGIWNICKN */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) lbs_set_rate,      /* SIOCSIWRATE */
-       (iw_handler) lbs_get_rate,      /* SIOCGIWRATE */
-       (iw_handler) lbs_set_rts,       /* SIOCSIWRTS */
-       (iw_handler) lbs_get_rts,       /* SIOCGIWRTS */
-       (iw_handler) lbs_set_frag,      /* SIOCSIWFRAG */
-       (iw_handler) lbs_get_frag,      /* SIOCGIWFRAG */
-       (iw_handler) lbs_set_txpow,     /* SIOCSIWTXPOW */
-       (iw_handler) lbs_get_txpow,     /* SIOCGIWTXPOW */
-       (iw_handler) lbs_set_retry,     /* SIOCSIWRETRY */
-       (iw_handler) lbs_get_retry,     /* SIOCGIWRETRY */
-       (iw_handler) lbs_set_encode,    /* SIOCSIWENCODE */
-       (iw_handler) lbs_get_encode,    /* SIOCGIWENCODE */
-       (iw_handler) lbs_set_power,     /* SIOCSIWPOWER */
-       (iw_handler) lbs_get_power,     /* SIOCGIWPOWER */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) lbs_set_genie,     /* SIOCSIWGENIE */
-       (iw_handler) lbs_get_genie,     /* SIOCGIWGENIE */
-       (iw_handler) lbs_set_auth,      /* SIOCSIWAUTH */
-       (iw_handler) lbs_get_auth,      /* SIOCGIWAUTH */
-       (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
-       (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
-       (iw_handler) NULL,              /* SIOCSIWPMKSA */
-};
-struct iw_handler_def lbs_handler_def = {
-       .num_standard   = ARRAY_SIZE(lbs_handler),
-       .standard       = (iw_handler *) lbs_handler,
-       .get_wireless_stats = lbs_get_wireless_stats,
-};
-
-#ifdef CONFIG_LIBERTAS_MESH
-static const iw_handler mesh_wlan_handler[] = {
-       (iw_handler) NULL,      /* SIOCSIWCOMMIT */
-       (iw_handler) lbs_get_name,      /* SIOCGIWNAME */
-       (iw_handler) NULL,      /* SIOCSIWNWID */
-       (iw_handler) NULL,      /* SIOCGIWNWID */
-       (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
-       (iw_handler) lbs_get_freq,      /* SIOCGIWFREQ */
-       (iw_handler) NULL,              /* SIOCSIWMODE */
-       (iw_handler) mesh_wlan_get_mode,        /* SIOCGIWMODE */
-       (iw_handler) NULL,      /* SIOCSIWSENS */
-       (iw_handler) NULL,      /* SIOCGIWSENS */
-       (iw_handler) NULL,      /* SIOCSIWRANGE */
-       (iw_handler) lbs_get_range,     /* SIOCGIWRANGE */
-       (iw_handler) NULL,      /* SIOCSIWPRIV */
-       (iw_handler) NULL,      /* SIOCGIWPRIV */
-       (iw_handler) NULL,      /* SIOCSIWSTATS */
-       (iw_handler) NULL,      /* SIOCGIWSTATS */
-       iw_handler_set_spy,     /* SIOCSIWSPY */
-       iw_handler_get_spy,     /* SIOCGIWSPY */
-       iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
-       iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
-       (iw_handler) NULL,      /* SIOCSIWAP */
-       (iw_handler) NULL,      /* SIOCGIWAP */
-       (iw_handler) NULL,      /* SIOCSIWMLME */
-       (iw_handler) NULL,      /* SIOCGIWAPLIST - deprecated */
-       (iw_handler) lbs_set_scan,      /* SIOCSIWSCAN */
-       (iw_handler) lbs_get_scan,      /* SIOCGIWSCAN */
-       (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
-       (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
-       (iw_handler) NULL,              /* SIOCSIWNICKN */
-       (iw_handler) mesh_get_nick,     /* SIOCGIWNICKN */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) lbs_set_rate,      /* SIOCSIWRATE */
-       (iw_handler) lbs_get_rate,      /* SIOCGIWRATE */
-       (iw_handler) lbs_set_rts,       /* SIOCSIWRTS */
-       (iw_handler) lbs_get_rts,       /* SIOCGIWRTS */
-       (iw_handler) lbs_set_frag,      /* SIOCSIWFRAG */
-       (iw_handler) lbs_get_frag,      /* SIOCGIWFRAG */
-       (iw_handler) lbs_set_txpow,     /* SIOCSIWTXPOW */
-       (iw_handler) lbs_get_txpow,     /* SIOCGIWTXPOW */
-       (iw_handler) lbs_set_retry,     /* SIOCSIWRETRY */
-       (iw_handler) lbs_get_retry,     /* SIOCGIWRETRY */
-       (iw_handler) lbs_set_encode,    /* SIOCSIWENCODE */
-       (iw_handler) lbs_get_encode,    /* SIOCGIWENCODE */
-       (iw_handler) lbs_set_power,     /* SIOCSIWPOWER */
-       (iw_handler) lbs_get_power,     /* SIOCGIWPOWER */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) lbs_set_genie,     /* SIOCSIWGENIE */
-       (iw_handler) lbs_get_genie,     /* SIOCGIWGENIE */
-       (iw_handler) lbs_set_auth,      /* SIOCSIWAUTH */
-       (iw_handler) lbs_get_auth,      /* SIOCGIWAUTH */
-       (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
-       (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
-       (iw_handler) NULL,              /* SIOCSIWPMKSA */
-};
-
-struct iw_handler_def mesh_handler_def = {
-       .num_standard   = ARRAY_SIZE(mesh_wlan_handler),
-       .standard       = (iw_handler *) mesh_wlan_handler,
-       .get_wireless_stats = lbs_get_wireless_stats,
-};
-#endif
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
deleted file mode 100644 (file)
index f3f19fe..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
-  * This file contains definition for IOCTL call.
-  */
-#ifndef        _LBS_WEXT_H_
-#define        _LBS_WEXT_H_
-
-void lbs_send_disconnect_notification(struct lbs_private *priv);
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
-
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
-       struct lbs_private *priv,
-       u8 band,
-       u16 channel);
-
-extern struct iw_handler_def lbs_handler_def;
-
-#endif
index 49a7dfb4809a1e5a5f71b9551908a03b147b23ee..e7f299dc9ef5b20966bad49042e77ce228f7a3cc 100644 (file)
@@ -1291,6 +1291,11 @@ static int __init init_mac80211_hwsim(void)
                hw->wiphy->n_addresses = 2;
                hw->wiphy->addresses = data->addresses;
 
+               if (fake_hw_scan) {
+                       hw->wiphy->max_scan_ssids = 255;
+                       hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+               }
+
                hw->channel_change_time = 1;
                hw->queues = 4;
                hw->wiphy->interface_modes =
index 5e7f344b000d57741a8a789a4927cd76fccd773c..719573bbbf81fce6e21560465702cbff814847f4 100644 (file)
@@ -520,8 +520,9 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
 
 static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
 
-static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
-                               int dbm);
+static int rndis_set_tx_power(struct wiphy *wiphy,
+                             enum nl80211_tx_power_setting type,
+                             int mbm);
 static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
 
 static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
@@ -1856,20 +1857,25 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        return 0;
 }
 
-static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
-                               int dbm)
+static int rndis_set_tx_power(struct wiphy *wiphy,
+                             enum nl80211_tx_power_setting type,
+                             int mbm)
 {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
        struct usbnet *usbdev = priv->usbdev;
 
-       netdev_dbg(usbdev->net, "%s(): type:0x%x dbm:%i\n",
-                  __func__, type, dbm);
+       netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n",
+                  __func__, type, mbm);
+
+       if (mbm < 0 || (mbm % 100))
+               return -ENOTSUPP;
 
        /* Device doesn't support changing txpower after initialization, only
         * turn off/on radio. Support 'auto' mode and setting same dBm that is
         * currently used.
         */
-       if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+       if (type == NL80211_TX_POWER_AUTOMATIC ||
+           MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) {
                if (!priv->radio_on)
                        disassociate(usbdev, true); /* turn on radio */
 
index 1eb882e15fb454c325a0b5772408456527dc9aba..3bedf566c8ee95c4b8418923e357c2481efb0b10 100644 (file)
@@ -1229,7 +1229,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
                }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-               rt2x00pci_txdone(entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -1588,7 +1588,6 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
        .reset_tuner            = rt2400pci_reset_tuner,
        .link_tuner             = rt2400pci_link_tuner,
        .write_tx_desc          = rt2400pci_write_tx_desc,
-       .write_tx_data          = rt2x00pci_write_tx_data,
        .write_beacon           = rt2400pci_write_beacon,
        .kick_tx_queue          = rt2400pci_kick_tx_queue,
        .kill_tx_queue          = rt2400pci_kill_tx_queue,
index a29cb212f89ad61819ce2fd2d19c468add0b8428..69d231d83952759feb0a25c9d6ef0b6b5f64b5f6 100644 (file)
@@ -1365,7 +1365,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
                }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-               rt2x00pci_txdone(entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -1886,7 +1886,6 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
        .reset_tuner            = rt2500pci_reset_tuner,
        .link_tuner             = rt2500pci_link_tuner,
        .write_tx_desc          = rt2500pci_write_tx_desc,
-       .write_tx_data          = rt2x00pci_write_tx_data,
        .write_beacon           = rt2500pci_write_beacon,
        .kick_tx_queue          = rt2500pci_kick_tx_queue,
        .kill_tx_queue          = rt2500pci_kill_tx_queue,
index 002db646ae0b0e0c985ebc523ca60c0a7b3b736e..44205526013f78ac10a46c9c76ab307a1d430711 100644 (file)
@@ -347,6 +347,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
 {
        u32 mask;
        u16 reg;
+       enum cipher curr_cipher;
 
        if (crypto->cmd == SET_KEY) {
                /*
@@ -357,6 +358,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
                mask = TXRX_CSR0_KEY_ID.bit_mask;
 
                rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+               curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM);
                reg &= mask;
 
                if (reg && reg == mask)
@@ -365,6 +367,14 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
                reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
 
                key->hw_key_idx += reg ? ffz(reg) : 0;
+               /*
+                * Hardware requires that all keys use the same cipher
+                * (e.g. TKIP-only, AES-only, but not TKIP+AES).
+                * If this is not the first key, compare the cipher with the
+                * first one and fall back to SW crypto if not the same.
+                */
+               if (key->hw_key_idx > 0 && crypto->cipher != curr_cipher)
+                       return -EOPNOTSUPP;
 
                rt2500usb_register_multiwrite(rt2x00dev, reg,
                                              crypto->key, sizeof(crypto->key));
@@ -1769,7 +1779,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .link_stats             = rt2500usb_link_stats,
        .reset_tuner            = rt2500usb_reset_tuner,
        .write_tx_desc          = rt2500usb_write_tx_desc,
-       .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt2500usb_write_beacon,
        .get_tx_data_len        = rt2500usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
index 14c361ae87be5e15f0abef94b2b58723cd54c7bf..d3cf0cc39500159c57264cb6f51a08ba9a925c7b 100644 (file)
@@ -99,8 +99,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
                rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
                rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
                rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
-               if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-                       rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+               rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
 
                rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
        }
@@ -128,8 +127,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev,
                rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
                rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
                rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
-               if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-                       rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+               rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
 
                rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
 
@@ -432,6 +430,20 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
 }
 EXPORT_SYMBOL(rt2800_write_beacon);
 
+static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
+                                      unsigned int beacon_base)
+{
+       int i;
+
+       /*
+        * For the Beacon base registers we only need to clear
+        * the whole TXWI which (when set to 0) will invalidate
+        * the entire beacon.
+        */
+       for (i = 0; i < TXWI_DESC_SIZE; i += sizeof(__le32))
+               rt2800_register_write(rt2x00dev, beacon_base + i, 0);
+}
+
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 const struct rt2x00debug rt2800_rt2x00debug = {
        .owner  = THIS_MODULE,
@@ -733,19 +745,14 @@ EXPORT_SYMBOL_GPL(rt2800_config_filter);
 void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
                        struct rt2x00intf_conf *conf, const unsigned int flags)
 {
-       unsigned int beacon_base;
        u32 reg;
 
        if (flags & CONFIG_UPDATE_TYPE) {
                /*
                 * Clear current synchronisation setup.
-                * For the Beacon base registers we only need to clear
-                * the first byte since that byte contains the VALID and OWNER
-                * bits which (when set to 0) will invalidate the entire beacon.
                 */
-               beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-               rt2800_register_write(rt2x00dev, beacon_base, 0);
-
+               rt2800_clear_beacon(rt2x00dev,
+                                   HW_BEACON_OFFSET(intf->beacon->entry_idx));
                /*
                 * Enable synchronisation.
                 */
@@ -768,8 +775,8 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
 
        if (flags & CONFIG_UPDATE_BSSID) {
                reg = le32_to_cpu(conf->bssid[1]);
-               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 0);
-               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
+               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
                conf->bssid[1] = cpu_to_le32(reg);
 
                rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
@@ -827,14 +834,12 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
        switch ((int)ant->tx) {
        case 1:
                rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
-               if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-                       rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
                break;
        case 2:
                rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
                break;
        case 3:
-               /* Do nothing */
+               rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
                break;
        }
 
@@ -1565,18 +1570,15 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        /*
         * Clear all beacons
-        * For the Beacon base registers we only need to clear
-        * the first byte since that byte contains the VALID and OWNER
-        * bits which (when set to 0) will invalidate the entire beacon.
         */
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
-       rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6);
+       rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7);
 
        if (rt2x00_is_usb(rt2x00dev)) {
                rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
@@ -2185,6 +2187,8 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
                rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
                rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
+               rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);
+               rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);
                rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
                EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
        }
@@ -2192,6 +2196,10 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
        if ((word & 0x00ff) == 0x00ff) {
                rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+               rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+               EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+       }
+       if ((word & 0xff00) == 0xff00) {
                rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
                                   LED_MODE_TXRX_ACTIVITY);
                rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
@@ -2199,7 +2207,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
                rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
                rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
-               EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+               EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
        }
 
        /*
@@ -2499,7 +2507,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
            IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM |
            IEEE80211_HW_SUPPORTS_PS |
-           IEEE80211_HW_PS_NULLFUNC_STACK;
+           IEEE80211_HW_PS_NULLFUNC_STACK |
+           IEEE80211_HW_AMPDU_AGGREGATION;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -2559,12 +2568,15 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
            IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
            IEEE80211_HT_CAP_GRN_FLD |
            IEEE80211_HT_CAP_SGI_20 |
-           IEEE80211_HT_CAP_SGI_40 |
-           IEEE80211_HT_CAP_RX_STBC;
+           IEEE80211_HT_CAP_SGI_40;
 
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
                spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
 
+       spec->ht.cap |=
+           rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<
+               IEEE80211_HT_CAP_RX_STBC_SHIFT;
+
        spec->ht.ampdu_factor = 3;
        spec->ht.ampdu_density = 4;
        spec->ht.mcs.tx_params =
@@ -2751,6 +2763,35 @@ static u64 rt2800_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
+static int rt2800_ampdu_action(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              enum ieee80211_ampdu_mlme_action action,
+                              struct ieee80211_sta *sta,
+                              u16 tid, u16 *ssn)
+{
+       int ret = 0;
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+       case IEEE80211_AMPDU_RX_STOP:
+               /* we don't support RX aggregation yet */
+               ret = -ENOTSUPP;
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               break;
+       default:
+               WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n");
+       }
+
+       return ret;
+}
+
 const struct ieee80211_ops rt2800_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
        .start                  = rt2x00mac_start,
@@ -2768,6 +2809,7 @@ const struct ieee80211_ops rt2800_mac80211_ops = {
        .conf_tx                = rt2800_conf_tx,
        .get_tsf                = rt2800_get_tsf,
        .rfkill_poll            = rt2x00mac_rfkill_poll,
+       .ampdu_action           = rt2800_ampdu_action,
 };
 EXPORT_SYMBOL_GPL(rt2800_mac80211_ops);
 
index e5ea670a18db9c2576b0c90a8ff1d48fff1e1246..6f11760117da05fa843abe5daf4dcbee39fd2d11 100644 (file)
@@ -139,8 +139,18 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
        eeprom.data = rt2x00dev;
        eeprom.register_read = rt2800pci_eepromregister_read;
        eeprom.register_write = rt2800pci_eepromregister_write;
-       eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ?
-           PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+       switch (rt2x00_get_field32(reg, E2PROM_CSR_TYPE))
+       {
+       case 0:
+               eeprom.width = PCI_EEPROM_WIDTH_93C46;
+               break;
+       case 1:
+               eeprom.width = PCI_EEPROM_WIDTH_93C66;
+               break;
+       default:
+               eeprom.width = PCI_EEPROM_WIDTH_93C86;
+               break;
+       }
        eeprom.reg_data_in = 0;
        eeprom.reg_data_out = 0;
        eeprom.reg_data_clock = 0;
@@ -645,10 +655,12 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2800pci_write_tx_datadesc(struct queue_entry* entry,
-                                        struct txentry_desc *txdesc)
+static void rt2800pci_write_tx_data(struct queue_entry* entry,
+                                   struct txentry_desc *txdesc)
 {
-       rt2800_write_txwi((__le32 *) entry->skb->data, txdesc);
+       __le32 *txwi = (__le32 *) entry->skb->data;
+
+       rt2800_write_txwi(txwi, txdesc);
 }
 
 
@@ -905,7 +917,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
                if (txdesc.retry)
                        __set_bit(TXDONE_FALLBACK, &txdesc.flags);
 
-               rt2x00pci_txdone(entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -941,6 +953,12 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
                rt2800pci_txdone(rt2x00dev);
 
+       /*
+        * Current beacon was sent out, fetch the next one
+        */
+       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
+               rt2x00lib_beacondone(rt2x00dev);
+
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
                rt2800pci_wakeup(rt2x00dev);
 
@@ -1044,8 +1062,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
        .write_tx_desc          = rt2800pci_write_tx_desc,
-       .write_tx_data          = rt2x00pci_write_tx_data,
-       .write_tx_datadesc      = rt2800pci_write_tx_datadesc,
+       .write_tx_data          = rt2800pci_write_tx_data,
        .write_beacon           = rt2800_write_beacon,
        .kick_tx_queue          = rt2800pci_kick_tx_queue,
        .kill_tx_queue          = rt2800pci_kill_tx_queue,
index f18c12a19cc9a9d630ca3b0161b93f262ff401b0..4f85f7b4244105132c04c1161c5785703cf7b641 100644 (file)
@@ -430,20 +430,23 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
+static void rt2800usb_write_tx_data(struct queue_entry* entry,
+                                   struct txentry_desc *txdesc)
+{
+       __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
+
+       rt2800_write_txwi(txwi, txdesc);
+}
+
+
 static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        __le32 *txi = (__le32 *) skb->data;
-       __le32 *txwi = (__le32 *) (skb->data + TXINFO_DESC_SIZE);
        u32 word;
 
-       /*
-        * Initialize TXWI descriptor
-        */
-       rt2800_write_txwi(txwi, txdesc);
-
        /*
         * Initialize TXINFO descriptor
         */
@@ -652,7 +655,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
        .write_tx_desc          = rt2800usb_write_tx_desc,
-       .write_tx_data          = rt2x00usb_write_tx_data,
+       .write_tx_data          = rt2800usb_write_tx_data,
        .write_beacon           = rt2800_write_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
index e7acc6abfd891fe87df046003ad55d22dab0fc3e..788b0e452cc7a046315fddb49fbb66821ed23235 100644 (file)
@@ -550,10 +550,8 @@ struct rt2x00lib_ops {
        void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
                               struct sk_buff *skb,
                               struct txentry_desc *txdesc);
-       int (*write_tx_data) (struct queue_entry *entry,
-                             struct txentry_desc *txdesc);
-       void (*write_tx_datadesc) (struct queue_entry *entry,
-                                  struct txentry_desc *txdesc);
+       void (*write_tx_data) (struct queue_entry *entry,
+                              struct txentry_desc *txdesc);
        void (*write_beacon) (struct queue_entry *entry,
                              struct txentry_desc *txdesc);
        int (*get_tx_data_len) (struct queue_entry *entry);
index 339cc84bf4fb0f811ba2a93dd33c34374e5b4c51..12ee7bdedd02600aa61e5ee61362e47198b86151 100644 (file)
@@ -210,6 +210,21 @@ void rt2x00lib_txdone(struct queue_entry *entry,
        unsigned int i;
        bool success;
 
+       /*
+        * Unmap the skb.
+        */
+       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
+       /*
+        * Remove the extra tx headroom from the skb.
+        */
+       skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+
+       /*
+        * Signal that the TX descriptor is no longer in the skb.
+        */
+       skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
        /*
         * Remove L2 padding which was added during
         */
@@ -286,6 +301,21 @@ void rt2x00lib_txdone(struct queue_entry *entry,
                        rt2x00dev->low_level_stats.dot11ACKFailureCount++;
        }
 
+       /*
+        * Every single frame has it's own tx status, hence report
+        * every frame as ampdu of size 1.
+        *
+        * TODO: if we can find out how many frames were aggregated
+        * by the hw we could provide the real ampdu_len to mac80211
+        * which would allow the rc algorithm to better decide on
+        * which rates are suitable.
+        */
+       if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+               tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+               tx_info->status.ampdu_len = 1;
+               tx_info->status.ampdu_ack_len = success ? 1 : 0;
+       }
+
        if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                if (success)
                        rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
index 0efbf5a6c25414a6780a00ec59bde104d29044b8..2f8136cab7d8acd414b4d1e297fa0beba9ae2ece 100644 (file)
@@ -271,11 +271,11 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
 
        /*
         * Link tuning should only be performed when
-        * an active sta or master interface exists.
-        * Single monitor mode interfaces should never have
-        * work with link tuners.
+        * an active sta interface exists. AP interfaces
+        * don't need link tuning and monitor mode interfaces
+        * should never have to work with link tuners.
         */
-       if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
+       if (!rt2x00dev->intf_sta_count)
                return;
 
        rt2x00link_reset_tuner(rt2x00dev, false);
index abbd857ec7592a5ea1b1e22aff581414729d5ff9..3b838c0bf59f21d21f2a08f926edf0b1e4b3b06a 100644 (file)
@@ -282,7 +282,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
         * has been initialized. Otherwise the device can reset
         * the MAC registers.
         */
-       rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
+       rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
+                             intf->mac, intf->bssid);
 
        /*
         * Some filters depend on the current working mode. We can force
@@ -562,7 +563,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct rt2x00_intf *intf = vif_to_intf(vif);
-       int update_bssid = 0;
 
        /*
         * mac80211 might be calling this function while we are trying
@@ -577,10 +577,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
         * conf->bssid can be NULL if coming from the internal
         * beacon update routine.
         */
-       if (changes & BSS_CHANGED_BSSID) {
-               update_bssid = 1;
+       if (changes & BSS_CHANGED_BSSID)
                memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
-       }
 
        spin_unlock(&intf->lock);
 
@@ -592,7 +590,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
         */
        if (changes & BSS_CHANGED_BSSID)
                rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
-                                     update_bssid ? bss_conf->bssid : NULL);
+                                     bss_conf->bssid);
 
        /*
         * Update the beacon.
index 10eaffd12b1b9faa387748b7e9392d9294f5861d..fc9da83587840a812b4ca265b07b667b7450de4d 100644 (file)
@@ -60,80 +60,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
 
-/*
- * TX data handlers.
- */
-int rt2x00pci_write_tx_data(struct queue_entry *entry,
-                           struct txentry_desc *txdesc)
-{
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-
-       /*
-        * This should not happen, we already checked the entry
-        * was ours. When the hardware disagrees there has been
-        * a queue corruption!
-        */
-       if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) {
-               ERROR(rt2x00dev,
-                     "Corrupt queue %d, accessing entry which is not ours.\n"
-                     "Please file bug report to %s.\n",
-                     entry->queue->qid, DRV_PROJECT);
-               return -EINVAL;
-       }
-
-       /*
-        * Add the requested extra tx headroom in front of the skb.
-        */
-       skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
-       memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
-
-       /*
-        * Call the driver's write_tx_datadesc function, if it exists.
-        */
-       if (rt2x00dev->ops->lib->write_tx_datadesc)
-               rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
-
-       /*
-        * Map the skb to DMA.
-        */
-       if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
-               rt2x00queue_map_txskb(rt2x00dev, entry->skb);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
-
-/*
- * TX/RX data handlers.
- */
-void rt2x00pci_txdone(struct queue_entry *entry,
-                     struct txdone_entry_desc *txdesc)
-{
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-
-       /*
-        * Unmap the skb.
-        */
-       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
-
-       /*
-        * Remove the extra tx headroom from the skb.
-        */
-       skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
-
-       /*
-        * Signal that the TX descriptor is no longer in the skb.
-        */
-       skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
-
-       /*
-        * Pass on to rt2x00lib.
-        */
-       rt2x00lib_txdone(entry, txdesc);
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
-
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue = rt2x00dev->rx;
index 00528b8a754daf166f084c7d676fdf9ee1ab5b7c..b854d62ff99bde9e3ada5bbd4811a6797ac1c677 100644 (file)
@@ -85,16 +85,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
                           const struct rt2x00_field32 field,
                           u32 *reg);
 
-/**
- * rt2x00pci_write_tx_data - Initialize data for TX operation
- * @entry: The entry where the frame is located
- *
- * This function will initialize the DMA and skb descriptor
- * to prepare the entry for the actual TX operation.
- */
-int rt2x00pci_write_tx_data(struct queue_entry *entry,
-                           struct txentry_desc *txdesc);
-
 /**
  * struct queue_entry_priv_pci: Per entry PCI specific information
  *
@@ -108,14 +98,6 @@ struct queue_entry_priv_pci {
        dma_addr_t desc_dma;
 };
 
-/**
- * rt2x00pci_txdone - Handle TX done events.
- * @entry: The queue entry for which a TX done event was received.
- * @txdesc: The TX done descriptor for the entry.
- */
-void rt2x00pci_txdone(struct queue_entry *entry,
-                     struct txdone_entry_desc *txdesc);
-
 /**
  * rt2x00pci_rxdone - Handle RX done events
  * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
index f9163714711638b09aad259ed581cb1e45909ce3..5097fe0f9f51aad29da46a42cb39c6ede182bbb7 100644 (file)
@@ -404,6 +404,46 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
 }
 
+static int rt2x00queue_write_tx_data(struct queue_entry *entry,
+                                    struct txentry_desc *txdesc)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+       /*
+        * This should not happen, we already checked the entry
+        * was ours. When the hardware disagrees there has been
+        * a queue corruption!
+        */
+       if (unlikely(rt2x00dev->ops->lib->get_entry_state &&
+                    rt2x00dev->ops->lib->get_entry_state(entry))) {
+               ERROR(rt2x00dev,
+                     "Corrupt queue %d, accessing entry which is not ours.\n"
+                     "Please file bug report to %s.\n",
+                     entry->queue->qid, DRV_PROJECT);
+               return -EINVAL;
+       }
+
+       /*
+        * Add the requested extra tx headroom in front of the skb.
+        */
+       skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+       memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+
+       /*
+        * Call the driver's write_tx_data function, if it exists.
+        */
+       if (rt2x00dev->ops->lib->write_tx_data)
+               rt2x00dev->ops->lib->write_tx_data(entry, txdesc);
+
+       /*
+        * Map the skb to DMA.
+        */
+       if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+               rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+       return 0;
+}
+
 static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
                                            struct txentry_desc *txdesc)
 {
@@ -515,8 +555,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
         * call failed. Since we always return NETDEV_TX_OK to mac80211,
         * this frame will simply be dropped.
         */
-       if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry,
-                                                              &txdesc))) {
+       if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
                clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
                entry->skb = NULL;
                return -EIO;
index b45bc24c3daeb0ff239b8c14bcc67e7450b04f5b..a22837c560fdfda28306f1b617c55fee3cb592d9 100644 (file)
@@ -177,11 +177,6 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
            !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
-       /*
-        * Remove the descriptor from the front of the skb.
-        */
-       skb_pull(entry->skb, entry->queue->desc_size);
-
        /*
         * Obtain the status about this packet.
         * Note that when the status is 0 it does not mean the
@@ -201,48 +196,28 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        rt2x00lib_txdone(entry, &txdesc);
 }
 
-int rt2x00usb_write_tx_data(struct queue_entry *entry,
-                           struct txentry_desc *txdesc)
+static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
        u32 length;
 
-       /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memset(entry->skb->data, 0, entry->queue->desc_size);
-
-       /*
-        * USB devices cannot blindly pass the skb->len as the
-        * length of the data to usb_fill_bulk_urb. Pass the skb
-        * to the driver to determine what the length should be.
-        */
-       length = rt2x00dev->ops->lib->get_tx_data_len(entry);
-
-       usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                         usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
-                         entry->skb->data, length,
-                         rt2x00usb_interrupt_txdone, entry);
-
-       /*
-        * Call the driver's write_tx_datadesc function, if it exists.
-        */
-       if (rt2x00dev->ops->lib->write_tx_datadesc)
-               rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
+       if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {
+               /*
+                * USB devices cannot blindly pass the skb->len as the
+                * length of the data to usb_fill_bulk_urb. Pass the skb
+                * to the driver to determine what the length should be.
+                */
+               length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
-{
-       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+               usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+                                 usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
+                                 entry->skb->data, length,
+                                 rt2x00usb_interrupt_txdone, entry);
 
-       if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
                usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+       }
 }
 
 void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
index 255b81ef95308ff16a145b57d7b49af72eb2a7de..2b7a1889e72f75dcaaa8e885ef0ad09d60e08283 100644 (file)
@@ -350,16 +350,6 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
  */
 void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
 
-/**
- * rt2x00usb_write_tx_data - Initialize URB for TX operation
- * @entry: The entry where the frame is located
- *
- * This function will initialize the URB and skb descriptor
- * to prepare the entry for the actual TX operation.
- */
-int rt2x00usb_write_tx_data(struct queue_entry *entry,
-                           struct txentry_desc *txdesc);
-
 /**
  * struct queue_entry_priv_usb: Per entry USB specific information
  *
index 7ca383478eeb9a24d8d15d87968ec325619b7f4f..0123fbc22ca27580bcab8b9368d1c7a5580b83a5 100644 (file)
@@ -2108,7 +2108,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                        __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
                        txdesc.retry = 0;
 
-                       rt2x00pci_txdone(entry_done, &txdesc);
+                       rt2x00lib_txdone(entry_done, &txdesc);
                        entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                }
 
@@ -2135,7 +2135,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                if (txdesc.retry)
                        __set_bit(TXDONE_FALLBACK, &txdesc.flags);
 
-               rt2x00pci_txdone(entry, &txdesc);
+               rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
@@ -2200,6 +2200,12 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
        if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
                rt61pci_wakeup(rt2x00dev);
 
+       /*
+        * 5 - Beacon done interrupt.
+        */
+       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
+               rt2x00lib_beacondone(rt2x00dev);
+
        return IRQ_HANDLED;
 }
 
@@ -2800,7 +2806,6 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
        .reset_tuner            = rt61pci_reset_tuner,
        .link_tuner             = rt61pci_link_tuner,
        .write_tx_desc          = rt61pci_write_tx_desc,
-       .write_tx_data          = rt2x00pci_write_tx_data,
        .write_beacon           = rt61pci_write_beacon,
        .kick_tx_queue          = rt61pci_kick_tx_queue,
        .kill_tx_queue          = rt61pci_kill_tx_queue,
index d06d90f003e742453a1076498a12733231c70b16..286dd97e51d89c6beaaecdbd0689b95133618970 100644 (file)
@@ -2249,7 +2249,6 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .reset_tuner            = rt73usb_reset_tuner,
        .link_tuner             = rt73usb_link_tuner,
        .write_tx_desc          = rt73usb_write_tx_desc,
-       .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt73usb_write_beacon,
        .get_tx_data_len        = rt73usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
index 515817de29058483c25d00d7537de67fd9b8776a..42705028751d5caf7893a933fe9e5fb47b917958 100644 (file)
@@ -671,7 +671,7 @@ static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
               (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
 }
 
-void rtl8180_beacon_work(struct work_struct *work)
+static void rtl8180_beacon_work(struct work_struct *work)
 {
        struct rtl8180_vif *vif_priv =
                container_of(work, struct rtl8180_vif, beacon_work.work);
index a55c873e8b6667bcd79796b9439743fad7b655c2..c4627cbdb8e038e4f61187db301c13a6acc12742 100644 (file)
@@ -30,6 +30,7 @@
 #define PCI_EEPROM_WIDTH_93C46 6
 #define PCI_EEPROM_WIDTH_93C56 8
 #define PCI_EEPROM_WIDTH_93C66 8
+#define PCI_EEPROM_WIDTH_93C86 8
 #define PCI_EEPROM_WIDTH_OPCODE        3
 #define PCI_EEPROM_WRITE_OPCODE        0x05
 #define PCI_EEPROM_READ_OPCODE 0x06
index 64fb32b93a28d4dd667587fa64a467b4d61b1c11..2c8701687336c94327297274e6bf0502c5b3633c 100644 (file)
@@ -725,6 +725,12 @@ enum nl80211_commands {
  * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
  *     connected to this BSS.
  *
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ *      &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ *      for non-automatic settings.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -882,6 +888,9 @@ enum nl80211_attrs {
 
        NL80211_ATTR_AP_ISOLATE,
 
+       NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+       NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1659,4 +1668,17 @@ enum nl80211_cqm_rssi_threshold_event {
        NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
 };
 
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+       NL80211_TX_POWER_AUTOMATIC,
+       NL80211_TX_POWER_LIMITED,
+       NL80211_TX_POWER_FIXED,
+};
+
 #endif /* __LINUX_NL80211_H */
index 9c45b905aefc90092f38f4badc4294689c994777..168fe530b214dfd0a301017fd3988b359b55301b 100644 (file)
@@ -875,19 +875,6 @@ enum wiphy_params_flags {
        WIPHY_PARAM_COVERAGE_CLASS      = 1 << 4,
 };
 
-/**
- * enum tx_power_setting - TX power adjustment
- *
- * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
- * @TX_POWER_LIMITED: limit TX power by the dbm parameter
- * @TX_POWER_FIXED: fix TX power to the dbm parameter
- */
-enum tx_power_setting {
-       TX_POWER_AUTOMATIC,
-       TX_POWER_LIMITED,
-       TX_POWER_FIXED,
-};
-
 /*
  * cfg80211_bitrate_mask - masks for bitrate control
  */
@@ -1149,7 +1136,7 @@ struct cfg80211_ops {
        int     (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
 
        int     (*set_tx_power)(struct wiphy *wiphy,
-                               enum tx_power_setting type, int dbm);
+                               enum nl80211_tx_power_setting type, int mbm);
        int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
 
        int     (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
index fe1a3a603375a50c89cf35e57d6bd9fe2a2bbf56..7f256e23c57f5aece4a14b069790cc3b920a2d5f 100644 (file)
@@ -1271,6 +1271,15 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
  * enabled whenever user has enabled powersave.
  *
+ * Some hardware need to toggle a single shared antenna between WLAN and
+ * Bluetooth to facilitate co-existence. These types of hardware set
+ * limitations on the use of host controlled dynamic powersave whenever there
+ * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the
+ * driver may request temporarily going into full power save, in order to
+ * enable toggling the antenna between BT and WLAN. If the driver requests
+ * disabling dynamic powersave, the @dynamic_ps_timeout value will be
+ * temporarily set to zero until the driver re-enables dynamic powersave.
+ *
  * Driver informs U-APSD client support by enabling
  * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
  * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS
@@ -2446,6 +2455,36 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  */
 void ieee80211_connection_loss(struct ieee80211_vif *vif);
 
+/**
+ * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Some hardware require full power save to manage simultaneous BT traffic
+ * on the WLAN frequency. Full PSM is required periodically, whenever there are
+ * burst of BT traffic. The hardware gets information of BT traffic via
+ * hardware co-existence lines, and consequentially requests mac80211 to
+ * (temporarily) enter full psm.
+ * This function will only temporarily disable dynamic PS, not enable PSM if
+ * it was not already enabled.
+ * The driver must make sure to re-enable dynamic PS using
+ * ieee80211_enable_dyn_ps() if the driver has disabled it.
+ *
+ */
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * This function restores dynamic PS after being temporarily disabled via
+ * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must
+ * be coupled with an eventual call to this function.
+ *
+ */
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif);
+
 /**
  * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
  *     rssi threshold triggered
index 83eec7a8bd1f5f97966cc85c937ad2005c5758eb..4d6f8653ec8819a7e69cdb9cb447b77c1e7e7047 100644 (file)
@@ -69,6 +69,7 @@ endchoice
 
 config MAC80211_RC_DEFAULT
        string
+       default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT
        default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
        default "pid" if MAC80211_RC_DEFAULT_PID
        default ""
index ed8c9f5be94f7e2173ef574cf78bb8ed6a351384..9eb02a34088989d68ff9ec499b0541ed3c962c85 100644 (file)
@@ -413,9 +413,6 @@ static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       if (!local->ops->get_survey)
-               return -EOPNOTSUPP;
-
        return drv_get_survey(local, idx, survey);
 }
 
@@ -1329,28 +1326,28 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 }
 
 static int ieee80211_set_tx_power(struct wiphy *wiphy,
-                                 enum tx_power_setting type, int dbm)
+                                 enum nl80211_tx_power_setting type, int mbm)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_channel *chan = local->hw.conf.channel;
        u32 changes = 0;
 
        switch (type) {
-       case TX_POWER_AUTOMATIC:
+       case NL80211_TX_POWER_AUTOMATIC:
                local->user_power_level = -1;
                break;
-       case TX_POWER_LIMITED:
-               if (dbm < 0)
-                       return -EINVAL;
-               local->user_power_level = dbm;
+       case NL80211_TX_POWER_LIMITED:
+               if (mbm < 0 || (mbm % 100))
+                       return -EOPNOTSUPP;
+               local->user_power_level = MBM_TO_DBM(mbm);
                break;
-       case TX_POWER_FIXED:
-               if (dbm < 0)
-                       return -EINVAL;
+       case NL80211_TX_POWER_FIXED:
+               if (mbm < 0 || (mbm % 100))
+                       return -EOPNOTSUPP;
                /* TODO: move to cfg80211 when it knows the channel */
-               if (dbm > chan->max_power)
+               if (MBM_TO_DBM(mbm) > chan->max_power)
                        return -EINVAL;
-               local->user_power_level = dbm;
+               local->user_power_level = MBM_TO_DBM(mbm);
                break;
        }
 
index c33317320eeebc4a56cbe6ea706c3b1e9e865359..14123dce544bf960a57d6f06fdbda6bbcc83f88a 100644 (file)
@@ -375,9 +375,14 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx,
                                struct survey_info *survey)
 {
        int ret = -EOPNOTSUPP;
+
+       trace_drv_get_survey(local, idx, survey);
+
        if (local->ops->get_survey)
                ret = local->ops->get_survey(&local->hw, idx, survey);
-       /* trace_drv_get_survey(local, idx, survey, ret); */
+
+       trace_drv_return_int(local, ret);
+
        return ret;
 }
 
index 8da31caff9318705f9530ba3787c19507a484ce4..5d5d2a97466837b75b14961bc3b14a48bd5d488e 100644 (file)
@@ -761,6 +761,28 @@ TRACE_EVENT(drv_ampdu_action,
        )
 );
 
+TRACE_EVENT(drv_get_survey,
+       TP_PROTO(struct ieee80211_local *local, int idx,
+                struct survey_info *survey),
+
+       TP_ARGS(local, idx, survey),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, idx)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->idx = idx;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " idx:%d",
+               LOCAL_PR_ARG, __entry->idx
+       )
+);
+
 TRACE_EVENT(drv_flush,
        TP_PROTO(struct ieee80211_local *local, bool drop),
 
index 6f905f153ed7e43aa5b5c56c791946a93e81e907..a3649a86a784fc088bd6d32927e59d3eb2c288c4 100644 (file)
@@ -855,6 +855,8 @@ struct ieee80211_local {
         * this will override whatever chosen by mac80211 internally.
         */
        int dynamic_ps_forced_timeout;
+       int dynamic_ps_user_timeout;
+       bool disable_dynamic_ps;
 
        int user_power_level; /* in dBm */
        int power_constr_level; /* in dBm */
index 3cd5f7b5d693be131e75baeb8f7474fb4ab2bef3..ea13a80a476c1fe0db6dc5e0059e2014f340926e 100644 (file)
@@ -65,7 +65,6 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
 {
        atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
        mesh_accept_plinks_update(sdata);
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 static inline
@@ -73,7 +72,6 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
 {
        atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
        mesh_accept_plinks_update(sdata);
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 /**
@@ -115,7 +113,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
 }
 
 /**
- * mesh_plink_deactivate - deactivate mesh peer link
+ * __mesh_plink_deactivate - deactivate mesh peer link
  *
  * @sta: mesh peer link to deactivate
  *
@@ -123,18 +121,23 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
  *
  * Locking: the caller must hold sta->lock
  */
-static void __mesh_plink_deactivate(struct sta_info *sta)
+static bool __mesh_plink_deactivate(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       bool deactivated = false;
 
-       if (sta->plink_state == PLINK_ESTAB)
+       if (sta->plink_state == PLINK_ESTAB) {
                mesh_plink_dec_estab_count(sdata);
+               deactivated = true;
+       }
        sta->plink_state = PLINK_BLOCKED;
        mesh_path_flush_by_nexthop(sta);
+
+       return deactivated;
 }
 
 /**
- * __mesh_plink_deactivate - deactivate mesh peer link
+ * mesh_plink_deactivate - deactivate mesh peer link
  *
  * @sta: mesh peer link to deactivate
  *
@@ -142,9 +145,15 @@ static void __mesh_plink_deactivate(struct sta_info *sta)
  */
 void mesh_plink_deactivate(struct sta_info *sta)
 {
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       bool deactivated;
+
        spin_lock_bh(&sta->lock);
-       __mesh_plink_deactivate(sta);
+       deactivated = __mesh_plink_deactivate(sta);
        spin_unlock_bh(&sta->lock);
+
+       if (deactivated)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -381,10 +390,16 @@ int mesh_plink_open(struct sta_info *sta)
 
 void mesh_plink_block(struct sta_info *sta)
 {
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       bool deactivated;
+
        spin_lock_bh(&sta->lock);
-       __mesh_plink_deactivate(sta);
+       deactivated = __mesh_plink_deactivate(sta);
        sta->plink_state = PLINK_BLOCKED;
        spin_unlock_bh(&sta->lock);
+
+       if (deactivated)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 
@@ -397,6 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
        enum plink_event event;
        enum plink_frame_type ftype;
        size_t baselen;
+       bool deactivated;
        u8 ie_len;
        u8 *baseaddr;
        __le16 plid, llid, reason;
@@ -651,8 +667,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                case CNF_ACPT:
                        del_timer(&sta->plink_timer);
                        sta->plink_state = PLINK_ESTAB;
-                       mesh_plink_inc_estab_count(sdata);
                        spin_unlock_bh(&sta->lock);
+                       mesh_plink_inc_estab_count(sdata);
+                       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
                        mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
                                sta->sta.addr);
                        break;
@@ -684,8 +701,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                case OPN_ACPT:
                        del_timer(&sta->plink_timer);
                        sta->plink_state = PLINK_ESTAB;
-                       mesh_plink_inc_estab_count(sdata);
                        spin_unlock_bh(&sta->lock);
+                       mesh_plink_inc_estab_count(sdata);
+                       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
                        mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
                                sta->sta.addr);
                        mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
@@ -702,11 +720,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                case CLS_ACPT:
                        reason = cpu_to_le16(MESH_CLOSE_RCVD);
                        sta->reason = reason;
-                       __mesh_plink_deactivate(sta);
+                       deactivated = __mesh_plink_deactivate(sta);
                        sta->plink_state = PLINK_HOLDING;
                        llid = sta->llid;
                        mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
                        spin_unlock_bh(&sta->lock);
+                       if (deactivated)
+                               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
                        mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
                                            plid, reason);
                        break;
index 85c3ca33333eae4eb9277d9a14064a2ed08e7fdd..d1962650b254e4a44bf7dbf6232750ca551bd793 100644 (file)
@@ -478,6 +478,39 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
        }
 }
 
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_conf *conf = &local->hw.conf;
+
+       WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+               !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+               (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+       local->disable_dynamic_ps = false;
+       conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout;
+}
+EXPORT_SYMBOL(ieee80211_enable_dyn_ps);
+
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_conf *conf = &local->hw.conf;
+
+       WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+               !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+               (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+       local->disable_dynamic_ps = true;
+       conf->dynamic_ps_timeout = 0;
+       del_timer_sync(&local->dynamic_ps_timer);
+       ieee80211_queue_work(&local->hw,
+                            &local->dynamic_ps_enable_work);
+}
+EXPORT_SYMBOL(ieee80211_disable_dyn_ps);
+
 /* powersave */
 static void ieee80211_enable_ps(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata)
@@ -553,6 +586,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
            found->u.mgd.associated->beacon_ies &&
            !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
                                    IEEE80211_STA_CONNECTION_POLL))) {
+               struct ieee80211_conf *conf = &local->hw.conf;
                s32 beaconint_us;
 
                if (latency < 0)
@@ -575,7 +609,10 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                        else
                                timeout = 100;
                }
-               local->hw.conf.dynamic_ps_timeout = timeout;
+               local->dynamic_ps_user_timeout = timeout;
+               if (!local->disable_dynamic_ps)
+                       conf->dynamic_ps_timeout =
+                               local->dynamic_ps_user_timeout;
 
                if (beaconint_us > latency) {
                        local->ps_sdata = NULL;
index 7a04951fcb1f848e3719d67c347820f110dc2e12..52c85036660d4d1cd51c431700ccaff428a0329f 100644 (file)
@@ -328,7 +328,8 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
 }
 
 static void
-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary)
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx,
+                       bool primary)
 {
        int group, orig_group;
 
index 696c0fc6e0b72f80d74dafd0e2df286198c0d123..462d2b227ed579682e7fe64fc2556377320263fa 100644 (file)
@@ -29,6 +29,8 @@ struct mcs_group {
        unsigned int duration[MCS_GROUP_RATES];
 };
 
+extern const struct mcs_group minstrel_mcs_groups[];
+
 struct minstrel_rate_stats {
        /* current / last sampling period attempts/success counters */
        unsigned int attempts, last_attempts;
index 4fb3ccbd8b402631243e1ff982d8fc2ca3866dcf..4a5a4b3e7799f1845421843e22fee503ef62ffb4 100644 (file)
@@ -14,8 +14,6 @@
 #include "rc80211_minstrel.h"
 #include "rc80211_minstrel_ht.h"
 
-extern const struct mcs_group minstrel_mcs_groups[];
-
 static int
 minstrel_ht_stats_open(struct inode *inode, struct file *file)
 {
index a8aa0f2411a2dc60b562b88a7b55349baa3bf32e..fa0f37e4afe4901226b0ccd668ae6a88c136eeb2 100644 (file)
@@ -293,7 +293,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                        skb2 = skb_clone(skb, GFP_ATOMIC);
                        if (skb2) {
                                skb2->dev = prev_dev;
-                               netif_rx(skb2);
+                               netif_receive_skb(skb2);
                        }
                }
 
@@ -304,7 +304,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 
        if (prev_dev) {
                skb->dev = prev_dev;
-               netif_rx(skb);
+               netif_receive_skb(skb);
        } else
                dev_kfree_skb(skb);
 
@@ -1578,7 +1578,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                        /* deliver to local stack */
                        skb->protocol = eth_type_trans(skb, dev);
                        memset(skb->cb, 0, sizeof(skb->cb));
-                       netif_rx(skb);
+                       netif_receive_skb(skb);
                }
        }
 
@@ -2056,11 +2056,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
        nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
                               GFP_ATOMIC);
        if (nskb) {
-               struct ieee80211_mgmt *mgmt = (void *)nskb->data;
+               struct ieee80211_mgmt *nmgmt = (void *)nskb->data;
 
-               mgmt->u.action.category |= 0x80;
-               memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
-               memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
+               nmgmt->u.action.category |= 0x80;
+               memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN);
+               memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
 
                memset(nskb->cb, 0, sizeof(nskb->cb));
 
@@ -2244,7 +2244,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                        skb2 = skb_clone(skb, GFP_ATOMIC);
                        if (skb2) {
                                skb2->dev = prev_dev;
-                               netif_rx(skb2);
+                               netif_receive_skb(skb2);
                        }
                }
 
@@ -2255,7 +2255,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
 
        if (prev_dev) {
                skb->dev = prev_dev;
-               netif_rx(skb);
+               netif_receive_skb(skb);
                skb = NULL;
        } else
                goto out_free_skb;
index e1b0be7a57b9772ddb1c006793ca6a5929580aba..439c98d93a79cedee816fa34e1fc7e5069d2e5f5 100644 (file)
@@ -286,6 +286,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        local->scanning = 0;
        local->scan_channel = NULL;
 
+       drv_sw_scan_complete(local);
+
        /* we only have to protect scan_req and hw/sw scan */
        mutex_unlock(&local->scan_mtx);
 
@@ -295,8 +297,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
        ieee80211_configure_filter(local);
 
-       drv_sw_scan_complete(local);
-
        ieee80211_offchannel_return(local, true);
 
  done:
@@ -734,7 +734,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        int ret = -EBUSY;
-       enum nl80211_band band;
+       enum ieee80211_band band;
 
        mutex_lock(&local->scan_mtx);
 
index 10d0fcb417ae07e4d0a99ee387f2859c796bad69..54262e72376d0e662ebbb1b27b02a14e6a869cdb 100644 (file)
@@ -427,20 +427,20 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
 {
 }
 
-#define for_each_sta_info(local, _addr, sta, nxt)                      \
+#define for_each_sta_info(local, _addr, _sta, nxt)                     \
        for (   /* initialise loop */                                   \
-               sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
-               nxt = sta ? rcu_dereference(sta->hnext) : NULL;         \
+               _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+               nxt = _sta ? rcu_dereference(_sta->hnext) : NULL;       \
                /* typecheck */                                         \
-               for_each_sta_info_type_check(local, (_addr), sta, nxt), \
+               for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
                /* continue condition */                                \
-               sta;                                                    \
+               _sta;                                                   \
                /* advance loop */                                      \
-               sta = nxt,                                              \
-               nxt = sta ? rcu_dereference(sta->hnext) : NULL          \
+               _sta = nxt,                                             \
+               nxt = _sta ? rcu_dereference(_sta->hnext) : NULL        \
             )                                                          \
        /* compare address and run code only if it matches */           \
-       if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0)
+       if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0)
 
 /*
  * Get STA info by index, BROKEN!
index 34da67995d94ae91c8982776fd3e9104c161079f..10caec5ea8fa7740d9617605adf1590eefa2a730 100644 (file)
@@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                skb2 = skb_clone(skb, GFP_ATOMIC);
                                if (skb2) {
                                        skb2->dev = prev_dev;
-                                       netif_rx(skb2);
+                                       netif_receive_skb(skb2);
                                }
                        }
 
@@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
        if (prev_dev) {
                skb->dev = prev_dev;
-               netif_rx(skb);
+               netif_receive_skb(skb);
                skb = NULL;
        }
        rcu_read_unlock();
index 37d0e0ab4432c7cecac400debdaeee1e1319c94b..47fcfd0eebc2715b8be899304a3eb3b0df5aaf13 100644 (file)
@@ -894,7 +894,7 @@ out_fail_pernet:
 }
 subsys_initcall(cfg80211_init);
 
-static void cfg80211_exit(void)
+static void __exit cfg80211_exit(void)
 {
        debugfs_remove(ieee80211_debugfs_dir);
        nl80211_exit();
index 6b41d15c4a05b354b1e571e6132a4e6c3904bc3f..85285b43d3744c5abeef766ba86a6558f974b477 100644 (file)
@@ -153,6 +153,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
        [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
        [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
+
+       [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
+       [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
 };
 
 /* policy for the attributes */
@@ -869,6 +872,34 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        goto bad_res;
        }
 
+       if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
+               enum nl80211_tx_power_setting type;
+               int idx, mbm = 0;
+
+               if (!rdev->ops->set_tx_power) {
+                       return -EOPNOTSUPP;
+                       goto bad_res;
+               }
+
+               idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
+               type = nla_get_u32(info->attrs[idx]);
+
+               if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
+                   (type != NL80211_TX_POWER_AUTOMATIC)) {
+                       result = -EINVAL;
+                       goto bad_res;
+               }
+
+               if (type != NL80211_TX_POWER_AUTOMATIC) {
+                       idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
+                       mbm = nla_get_u32(info->attrs[idx]);
+               }
+
+               result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
+               if (result)
+                       goto bad_res;
+       }
+
        changed = 0;
 
        if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
index 8f0d97dd3109c54cd85fe01095308171d34d9f01..1ac2bdd46ecf9c4710f8d51128a6e9a7fd815be1 100644 (file)
@@ -80,7 +80,7 @@ static const struct ieee80211_regdomain *country_ie_regdomain;
  *     - country_ie_regdomain
  *     - last_request
  */
-DEFINE_MUTEX(reg_mutex);
+static DEFINE_MUTEX(reg_mutex);
 #define assert_reg_lock() WARN_ON(!mutex_is_locked(&reg_mutex))
 
 /* Used to queue up regulatory hints */
@@ -2630,7 +2630,7 @@ out:
        mutex_unlock(&reg_mutex);
 }
 
-int regulatory_init(void)
+int __init regulatory_init(void)
 {
        int err = 0;
 
@@ -2676,7 +2676,7 @@ int regulatory_init(void)
        return 0;
 }
 
-void regulatory_exit(void)
+void /* __init_or_exit */ regulatory_exit(void)
 {
        struct regulatory_request *reg_request, *tmp;
        struct reg_beacon *reg_beacon, *btmp;
index b26224a9f3bc2ab2ea28d19a3a2ebbc2f5b2a765..c4695d07af23fd3852e8398787205d46a7b0d54c 100644 (file)
@@ -10,7 +10,7 @@ int regulatory_hint_user(const char *alpha2);
 
 void reg_device_remove(struct wiphy *wiphy);
 
-int regulatory_init(void);
+int __init regulatory_init(void);
 void regulatory_exit(void);
 
 int set_regdom(const struct ieee80211_regdomain *rd);
index 96342993cf933237d76c33595497d938ed86ec3c..1ff1e9f491369b2a8a460192b14d6485633051a6 100644 (file)
@@ -829,7 +829,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-       enum tx_power_setting type;
+       enum nl80211_tx_power_setting type;
        int dbm = 0;
 
        if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
@@ -852,7 +852,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
                        if (data->txpower.value < 0)
                                return -EINVAL;
                        dbm = data->txpower.value;
-                       type = TX_POWER_FIXED;
+                       type = NL80211_TX_POWER_FIXED;
                        /* TODO: do regulatory check! */
                } else {
                        /*
@@ -860,10 +860,10 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
                         * passed in from userland.
                         */
                        if (data->txpower.value < 0) {
-                               type = TX_POWER_AUTOMATIC;
+                               type = NL80211_TX_POWER_AUTOMATIC;
                        } else {
                                dbm = data->txpower.value;
-                               type = TX_POWER_LIMITED;
+                               type = NL80211_TX_POWER_LIMITED;
                        }
                }
        } else {
@@ -872,7 +872,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
                return 0;
        }
 
-       return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);
+       return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm));
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);