Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Sun, 26 Jul 2009 17:01:25 +0000 (10:01 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 26 Jul 2009 17:01:25 +0000 (10:01 -0700)
134 files changed:
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/adm8211.c
drivers/net/wireless/arlan-main.c
drivers/net/wireless/ath/ar9170/ar9170.h
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/initvals.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/virtual.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
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-rs.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debug.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-helpers.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/iwmc3200wifi/commands.c
drivers/net/wireless/iwmc3200wifi/hal.c
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/main.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/iwmc3200wifi/umac.h
drivers/net/wireless/iwmc3200wifi/wext.c
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/p54/eeprom.c
drivers/net/wireless/p54/fwio.c
drivers/net/wireless/p54/lmac.h
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2400pci.h
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500pci.h
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2500usb.h
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2800usb.h
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00crypto.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00reg.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt61pci.h
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rt2x00/rt73usb.h
drivers/net/wireless/wl12xx/wl1251_acx.c
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_netlink.c [deleted file]
drivers/net/wireless/wl12xx/wl1251_ops.c
drivers/net/wireless/wl12xx/wl1251_rx.h
drivers/net/wireless/zd1211rw/zd_usb.c
include/linux/nl80211.h
include/linux/skbuff.h
include/net/cfg80211.h
include/net/mac80211.h
net/core/dev.c
net/core/skbuff.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.c [new file with mode: 0644]
net/mac80211/driver-trace.h [new file with mode: 0644]
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_pid_algo.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac80211/wep.h
net/mac80211/wme.c
net/mac80211/wme.h
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/sme.c
net/wireless/util.c
net/wireless/wext-compat.c
net/wireless/wext-sme.c

index d119ba9..df55d24 100644 (file)
@@ -4984,7 +4984,7 @@ L:        linux-wireless@vger.kernel.org
 W:     http://linuxwireless.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
-F:     drivers/net/wireless/rtl818*
+F:     drivers/net/wireless/rtl818x/rtl8180*
 
 RTL8187 WIRELESS DRIVER
 P:     Herton Ronaldo Krzesinski
@@ -6466,6 +6466,15 @@ M:       mitr@volny.cz
 S:     Maintained
 F:     drivers/input/misc/wistron_btns.c
 
+WL1251 WIRELESS DRIVER
+P:     Kalle Valo
+M:     kalle.valo@nokia.com
+L:     linux-wireless@vger.kernel.org
+W:     http://wireless.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
+S:     Maintained
+F:     drivers/net/wireless/wl12xx/wl1251*
+
 WL3501 WIRELESS PCMCIA CARD DRIVER
 P:     Arnaldo Carvalho de Melo
 M:     acme@ghostprotocols.net
index 5bc00db..ca7a8a3 100644 (file)
@@ -428,10 +428,12 @@ config RTL8187
          Micronet SP907GK V5
          Encore ENUWI-G2
          Trendnet TEW-424UB
-         ASUS P5B Deluxe
+         ASUS P5B Deluxe/P5K Premium motherboards
          Toshiba Satellite Pro series of laptops
          Asus Wireless Link
-         Linksys WUSB54GC-EU
+         Linksys WUSB54GC-EU v2
+           (v1 = rt73usb; v3 is rt2070-based,
+            use staging/rt3070 or try rt2800usb)
 
          Thanks to Realtek for their support!
 
index ecc9383..5695911 100644 (file)
@@ -1964,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
 #ifdef CONFIG_PM
 static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-       struct adm8211_priv *priv = dev->priv;
-
-       if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
-               ieee80211_stop_queues(dev);
-               adm8211_stop(dev);
-       }
-
        pci_save_state(pdev);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
        return 0;
@@ -1979,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
 
 static int adm8211_resume(struct pci_dev *pdev)
 {
-       struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-       struct adm8211_priv *priv = dev->priv;
-
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
-
-       if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
-               adm8211_start(dev);
-               ieee80211_wake_queues(dev);
-       }
-
        return 0;
 }
 #endif /* CONFIG_PM */
index d479f47..f96c634 100644 (file)
@@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p)
        ARLAN_DEBUG_ENTRY("arlan_mac_addr");
        return -EINVAL;
 
-       if (!netif_running(dev))
+       if (netif_running(dev))
                return -EBUSY;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
index bb97981..e6c3ee3 100644 (file)
@@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge {
        bool has_plcp;
 };
 
+#define AR9170_NUM_MAX_BA_RETRY        5
+#define AR9170_NUM_TID 16
+#define WME_BA_BMP_SIZE         64
+#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
+
+#define WME_AC_BE   2
+#define WME_AC_BK   3
+#define WME_AC_VI   1
+#define WME_AC_VO   0
+
+#define TID_TO_WME_AC(_tid)                            \
+       ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+        (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+        (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+        WME_AC_VO)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+       ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
+
+enum ar9170_tid_state {
+       AR9170_TID_STATE_INVALID,
+       AR9170_TID_STATE_SHUTDOWN,
+       AR9170_TID_STATE_PROGRESS,
+       AR9170_TID_STATE_COMPLETE,
+};
+
+struct ar9170_sta_tid {
+       struct list_head list;
+       struct sk_buff_head queue;
+       u8 addr[ETH_ALEN];
+       u16 ssn;
+       u16 tid;
+       enum ar9170_tid_state state;
+       bool active;
+       u8 retry;
+};
+
 #define AR9170_QUEUE_TIMEOUT           64
 #define AR9170_TX_TIMEOUT              8
+#define AR9170_BA_TIMEOUT              4
 #define AR9170_JANITOR_DELAY           128
 #define AR9170_TX_INVALID_RATE         0xffffffff
 
+#define AR9170_NUM_TX_STATUS           128
+#define AR9170_NUM_TX_AGG_MAX          30
+
 struct ar9170 {
        struct ieee80211_hw *hw;
        struct mutex mutex;
@@ -187,14 +228,25 @@ struct ar9170 {
        struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
        struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
        struct delayed_work tx_janitor;
+       /* tx ampdu */
+       struct sk_buff_head tx_status_ampdu;
+       spinlock_t tx_ampdu_list_lock;
+       struct list_head tx_ampdu_list;
+       unsigned int tx_ampdu_pending;
 
        /* rxstream mpdu merge */
        struct ar9170_rxstream_mpdu_merge rx_mpdu;
        struct sk_buff *rx_failover;
        int rx_failover_missing;
+
+       /* (cached) HW A-MPDU settings */
+       u8 global_ampdu_density;
+       u8 global_ampdu_factor;
 };
 
 struct ar9170_sta_info {
+       struct ar9170_sta_tid agg[AR9170_NUM_TID];
+       unsigned int ampdu_max_len;
 };
 
 #define AR9170_TX_FLAG_WAIT_FOR_ACK    BIT(0)
index 51753ed..c7287a8 100644 (file)
@@ -49,6 +49,10 @@ static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
+static int modparam_ht;
+module_param_named(ht, modparam_ht, bool, S_IRUGO);
+MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
+
 #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {    \
        .bitrate        = (_bitrate),                   \
        .flags          = (_flags),                     \
@@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
        .cap            = IEEE80211_HT_CAP_MAX_AMSDU |                  \
                          IEEE80211_HT_CAP_SUP_WIDTH_20_40 |            \
                          IEEE80211_HT_CAP_SGI_40 |                     \
+                         IEEE80211_HT_CAP_GRN_FLD |                    \
                          IEEE80211_HT_CAP_DSSSCCK40 |                  \
                          IEEE80211_HT_CAP_SM_PS,                       \
        .ampdu_factor   = 3,                                            \
        .ampdu_density  = 6,                                            \
        .mcs            = {                                             \
-               .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, },     \
+               .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, },   \
+               .rx_highest = cpu_to_le16(300),                         \
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED,               \
        },                                                              \
 }
 
@@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
 };
 
 static void ar9170_tx(struct ar9170 *ar);
+static bool ar9170_tx_ampdu(struct ar9170 *ar);
 
-#ifdef AR9170_QUEUE_DEBUG
+static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
+{
+       return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 ar9170_get_seq(struct sk_buff *skb)
+{
+       struct ar9170_tx_control *txc = (void *) skb->data;
+       return ar9170_get_seq_h((void *) txc->frame_data);
+}
+
+static inline u16 ar9170_get_tid(struct sk_buff *skb)
+{
+       struct ar9170_tx_control *txc = (void *) skb->data;
+       struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+#define GET_NEXT_SEQ(seq)      ((seq + 1) & 0x0fff)
+#define GET_NEXT_SEQ_FROM_SKB(skb)     (GET_NEXT_SEQ(ar9170_get_seq(skb)))
+
+#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
 static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ar9170_tx_control *txc = (void *) skb->data;
@@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
        struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
        struct ieee80211_hdr *hdr = (void *) txc->frame_data;
 
-       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
                          "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
               wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
-              ieee80211_get_DA(hdr), arinfo->flags,
+              ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
               le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
               jiffies_to_msecs(arinfo->timeout - jiffies));
 }
@@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
                       "mismatch %d != %d\n", skb_queue_len(queue), i);
        printk(KERN_DEBUG "---[ end ]---\n");
 }
+#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
 
+#ifdef AR9170_QUEUE_DEBUG
 static void ar9170_dump_txqueue(struct ar9170 *ar,
                                struct sk_buff_head *queue)
 {
@@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
        __ar9170_dump_txqueue(ar, queue);
        spin_unlock_irqrestore(&queue->lock, flags);
 }
+#endif /* AR9170_QUEUE_DEBUG */
 
+#ifdef AR9170_QUEUE_STOP_DEBUG
 static void __ar9170_dump_txstats(struct ar9170 *ar)
 {
        int i;
@@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
               wiphy_name(ar->hw->wiphy));
 
        for (i = 0; i < __AR9170_NUM_TXQ; i++)
-               printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
-                      wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
-                      ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+               printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
+                      " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
+                      ar->tx_stats[i].limit, ar->tx_stats[i].len,
+                      skb_queue_len(&ar->tx_status[i]),
+                      ieee80211_queue_stopped(ar->hw, i));
 }
+#endif /* AR9170_QUEUE_STOP_DEBUG */
 
-static void ar9170_dump_txstats(struct ar9170 *ar)
+#ifdef AR9170_TXAGG_DEBUG
+static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&ar->tx_stats_lock, flags);
-       __ar9170_dump_txstats(ar);
-       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+       spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
+       printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
+              wiphy_name(ar->hw->wiphy));
+       __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
+       spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
 }
-#endif /* AR9170_QUEUE_DEBUG */
+
+#endif /* AR9170_TXAGG_DEBUG */
 
 /* caller must guarantee exclusive access for _bin_ queue. */
 static void ar9170_recycle_expired(struct ar9170 *ar,
@@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
        ieee80211_tx_status_irqsafe(ar->hw, skb);
 }
 
+static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
+{
+       struct sk_buff_head success;
+       struct sk_buff *skb;
+       unsigned int i;
+       unsigned long queue_bitmap = 0;
+
+       skb_queue_head_init(&success);
+
+       while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
+               __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
+
+       ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
+
+#ifdef AR9170_TXAGG_DEBUG
+       printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
+              wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
+       __ar9170_dump_txqueue(ar, &success);
+#endif /* AR9170_TXAGG_DEBUG */
+
+       while ((skb = __skb_dequeue(&success))) {
+               struct ieee80211_tx_info *txinfo;
+
+               queue_bitmap |= BIT(skb_get_queue_mapping(skb));
+
+               txinfo = IEEE80211_SKB_CB(skb);
+               ieee80211_tx_info_clear_status(txinfo);
+
+               txinfo->flags |= IEEE80211_TX_STAT_ACK;
+               txinfo->status.rates[0].count = 1;
+
+               skb_pull(skb, sizeof(struct ar9170_tx_control));
+               ieee80211_tx_status_irqsafe(ar->hw, skb);
+       }
+
+       for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+               printk(KERN_DEBUG "%s: wake queue %d\n",
+                      wiphy_name(ar->hw->wiphy), i);
+               __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+               ieee80211_wake_queue(ar->hw, i);
+       }
+
+       if (queue_bitmap)
+               ar9170_tx(ar);
+}
+
+static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+       struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+
+       arinfo->timeout = jiffies +
+                         msecs_to_jiffies(AR9170_BA_TIMEOUT);
+
+       skb_queue_tail(&ar->tx_status_ampdu, skb);
+       ar9170_tx_fake_ampdu_status(ar);
+       ar->tx_ampdu_pending--;
+
+       if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+               ar9170_tx_ampdu(ar);
+}
+
 void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
        spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
 
        if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
-               dev_kfree_skb_any(skb);
+               ar9170_tx_ampdu_callback(ar, skb);
        } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
                arinfo->timeout = jiffies +
                                  msecs_to_jiffies(AR9170_TX_TIMEOUT);
@@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
        return NULL;
 }
 
+static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
+{
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *txinfo;
+
+       while (count) {
+               skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
+               if (!skb)
+                       break;
+
+               txinfo = IEEE80211_SKB_CB(skb);
+               ieee80211_tx_info_clear_status(txinfo);
+
+               /* FIXME: maybe more ? */
+               txinfo->status.rates[0].count = 1;
+
+               skb_pull(skb, sizeof(struct ar9170_tx_control));
+               ieee80211_tx_status_irqsafe(ar->hw, skb);
+               count--;
+       }
+
+#ifdef AR9170_TXAGG_DEBUG
+       if (count) {
+               printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
+                      "suitable frames left in tx_status queue.\n",
+                      wiphy_name(ar->hw->wiphy), count);
+
+               ar9170_dump_tx_status_ampdu(ar);
+       }
+#endif /* AR9170_TXAGG_DEBUG */
+}
+
 /*
  * This worker tries to keeps an maintain tx_status queues.
  * So we can guarantee that incoming tx_status reports are
@@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
                        resched = true;
        }
 
+       ar9170_tx_fake_ampdu_status(ar);
+
        if (resched)
                queue_delayed_work(ar->hw->workqueue,
                                   &ar->tx_janitor,
@@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
                break;
 
        case 0xc4:
+               /* BlockACK bitmap */
+               break;
+
        case 0xc5:
                /* BlockACK events */
+               ar9170_handle_block_ack(ar,
+                                       le16_to_cpu(cmd->ba_fail_cnt.failed),
+                                       le16_to_cpu(cmd->ba_fail_cnt.rate));
+               ar9170_tx_fake_ampdu_status(ar);
                break;
 
        case 0xc6:
@@ -1098,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
        AR9170_FILL_QUEUE(ar->edcf[3], 2, 3,     7, 47); /* VOICE */
        AR9170_FILL_QUEUE(ar->edcf[4], 2, 3,     7,  0); /* SPECIAL */
 
+       /* set sane AMPDU defaults */
+       ar->global_ampdu_density = 6;
+       ar->global_ampdu_factor = 3;
+
        ar->bad_hw_nagger = jiffies;
 
        err = ar->open(ar);
@@ -1143,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
        flush_workqueue(ar->hw->workqueue);
 
        cancel_delayed_work_sync(&ar->tx_janitor);
+       cancel_delayed_work_sync(&ar->led_work);
        cancel_work_sync(&ar->filter_config_work);
        cancel_work_sync(&ar->beacon_work);
        mutex_lock(&ar->mutex);
@@ -1159,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
                skb_queue_purge(&ar->tx_pending[i]);
                skb_queue_purge(&ar->tx_status[i]);
        }
+       skb_queue_purge(&ar->tx_status_ampdu);
+
        mutex_unlock(&ar->mutex);
 }
 
+static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
+{
+       struct ar9170_tx_control *txc = (void *) skb->data;
+
+       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
+}
+
+static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
+                              struct sk_buff *src)
+{
+       struct ar9170_tx_control *dst_txc, *src_txc;
+       struct ieee80211_tx_info *dst_info, *src_info;
+       struct ar9170_tx_info *dst_arinfo, *src_arinfo;
+
+       src_txc = (void *) src->data;
+       src_info = IEEE80211_SKB_CB(src);
+       src_arinfo = (void *) src_info->rate_driver_data;
+
+       dst_txc = (void *) dst->data;
+       dst_info = IEEE80211_SKB_CB(dst);
+       dst_arinfo = (void *) dst_info->rate_driver_data;
+
+       dst_txc->phy_control = src_txc->phy_control;
+
+       /* same MCS for the whole aggregate */
+       memcpy(dst_info->driver_rates, src_info->driver_rates,
+              sizeof(dst_info->driver_rates));
+}
+
 static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
@@ -1230,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 
                        txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
                        arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+
                        goto out;
                }
 
@@ -1360,6 +1543,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
        txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
 }
 
+static bool ar9170_tx_ampdu(struct ar9170 *ar)
+{
+       struct sk_buff_head agg;
+       struct ar9170_sta_tid *tid_info = NULL, *tmp;
+       struct sk_buff *skb, *first = NULL;
+       unsigned long flags, f2;
+       unsigned int i = 0;
+       u16 seq, queue, tmpssn;
+       bool run = false;
+
+       skb_queue_head_init(&agg);
+
+       spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+       if (list_empty(&ar->tx_ampdu_list)) {
+#ifdef AR9170_TXAGG_DEBUG
+               printk(KERN_DEBUG "%s: aggregation list is empty.\n",
+                      wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+               goto out_unlock;
+       }
+
+       list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
+               if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
+#ifdef AR9170_TXAGG_DEBUG
+                       printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
+                              wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+                       continue;
+               }
+
+               if (++i > 64) {
+#ifdef AR9170_TXAGG_DEBUG
+                       printk(KERN_DEBUG "%s: enough frames aggregated.\n",
+                              wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+                       break;
+               }
+
+               queue = TID_TO_WME_AC(tid_info->tid);
+
+               if (skb_queue_len(&ar->tx_pending[queue]) >=
+                   AR9170_NUM_TX_AGG_MAX) {
+#ifdef AR9170_TXAGG_DEBUG
+                       printk(KERN_DEBUG "%s: queue %d full.\n",
+                              wiphy_name(ar->hw->wiphy), queue);
+#endif /* AR9170_TXAGG_DEBUG */
+                       continue;
+               }
+
+               list_del_init(&tid_info->list);
+
+               spin_lock_irqsave(&tid_info->queue.lock, f2);
+               tmpssn = seq = tid_info->ssn;
+               first = skb_peek(&tid_info->queue);
+
+               if (likely(first))
+                       tmpssn = ar9170_get_seq(first);
+
+               if (unlikely(tmpssn != seq)) {
+#ifdef AR9170_TXAGG_DEBUG
+                       printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
+                              wiphy_name(ar->hw->wiphy), seq, tmpssn);
+#endif /* AR9170_TXAGG_DEBUG */
+                       tid_info->ssn = tmpssn;
+               }
+
+#ifdef AR9170_TXAGG_DEBUG
+               printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
+                      "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
+                      tid_info->tid, tid_info->ssn,
+                      skb_queue_len(&tid_info->queue));
+               __ar9170_dump_txqueue(ar, &tid_info->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+               while ((skb = skb_peek(&tid_info->queue))) {
+                       if (unlikely(ar9170_get_seq(skb) != seq))
+                               break;
+
+                       __skb_unlink(skb, &tid_info->queue);
+                       tid_info->ssn = seq = GET_NEXT_SEQ(seq);
+
+                       if (unlikely(skb_get_queue_mapping(skb) != queue)) {
+#ifdef AR9170_TXAGG_DEBUG
+                               printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
+                                      "!match.\n", wiphy_name(ar->hw->wiphy),
+                                      tid_info->tid,
+                                      TID_TO_WME_AC(tid_info->tid),
+                                      skb_get_queue_mapping(skb));
+#endif /* AR9170_TXAGG_DEBUG */
+                                       dev_kfree_skb_any(skb);
+                                       continue;
+                       }
+
+                       if (unlikely(first == skb)) {
+                               ar9170_tx_prepare_phy(ar, skb);
+                               __skb_queue_tail(&agg, skb);
+                               first = skb;
+                       } else {
+                               ar9170_tx_copy_phy(ar, skb, first);
+                               __skb_queue_tail(&agg, skb);
+                       }
+
+                       if (unlikely(skb_queue_len(&agg) ==
+                           AR9170_NUM_TX_AGG_MAX))
+                               break;
+               }
+
+               if (skb_queue_empty(&tid_info->queue))
+                       tid_info->active = false;
+               else
+                       list_add_tail(&tid_info->list,
+                                     &ar->tx_ampdu_list);
+
+               spin_unlock_irqrestore(&tid_info->queue.lock, f2);
+
+               if (unlikely(skb_queue_empty(&agg))) {
+#ifdef AR9170_TXAGG_DEBUG
+                       printk(KERN_DEBUG "%s: queued empty list!\n",
+                              wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+                       continue;
+               }
+
+               /*
+                * tell the FW/HW that this is the last frame,
+                * that way it will wait for the immediate block ack.
+                */
+               if (likely(skb_peek_tail(&agg)))
+                       ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+
+#ifdef AR9170_TXAGG_DEBUG
+               printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
+                      wiphy_name(ar->hw->wiphy));
+               __ar9170_dump_txqueue(ar, &agg);
+#endif /* AR9170_TXAGG_DEBUG */
+
+               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+
+               spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
+               skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
+               spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
+               run = true;
+
+               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+       }
+
+out_unlock:
+       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+       __skb_queue_purge(&agg);
+
+       return run;
+}
+
 static void ar9170_tx(struct ar9170 *ar)
 {
        struct sk_buff *skb;
@@ -1384,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar)
                        printk(KERN_DEBUG "%s: queue %d full\n",
                               wiphy_name(ar->hw->wiphy), i);
 
-                       __ar9170_dump_txstats(ar);
-                       printk(KERN_DEBUG "stuck frames: ===> \n");
+                       printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+                              wiphy_name(ar->hw->wiphy));
                        ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
                        ar9170_dump_txqueue(ar, &ar->tx_status[i]);
 #endif /* AR9170_QUEUE_DEBUG */
+
+#ifdef AR9170_QUEUE_STOP_DEBUG
+                       printk(KERN_DEBUG "%s: stop queue %d\n",
+                              wiphy_name(ar->hw->wiphy), i);
+                       __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
                        ieee80211_stop_queue(ar->hw, i);
                        spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
                        continue;
@@ -1403,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar)
                               "remaining slots:%d, needed:%d\n",
                               wiphy_name(ar->hw->wiphy), i, remaining_space,
                               frames);
-
-                       ar9170_dump_txstats(ar);
 #endif /* AR9170_QUEUE_DEBUG */
                        frames = remaining_space;
                }
@@ -1432,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar)
                        arinfo->timeout = jiffies +
                                          msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
+                       if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+                               ar->tx_ampdu_pending++;
+
 #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: send frame q:%d =>\n",
                               wiphy_name(ar->hw->wiphy), i);
@@ -1440,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar)
 
                        err = ar->tx(ar, skb);
                        if (unlikely(err)) {
+                               if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+                                       ar->tx_ampdu_pending--;
+
                                frames_failed++;
                                dev_kfree_skb_any(skb);
                        } else {
@@ -1461,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar)
 
                if (unlikely(frames_failed)) {
 #ifdef AR9170_QUEUE_DEBUG
-                       printk(KERN_DEBUG "%s: frames failed =>\n",
+                       printk(KERN_DEBUG "%s: frames failed %d =>\n",
                               wiphy_name(ar->hw->wiphy), frames_failed);
 #endif /* AR9170_QUEUE_DEBUG */
 
                        spin_lock_irqsave(&ar->tx_stats_lock, flags);
                        ar->tx_stats[i].len -= frames_failed;
                        ar->tx_stats[i].count -= frames_failed;
+#ifdef AR9170_QUEUE_STOP_DEBUG
+                       printk(KERN_DEBUG "%s: wake queue %d\n",
+                              wiphy_name(ar->hw->wiphy), i);
+                       __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
                        ieee80211_wake_queue(ar->hw, i);
                        spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
                }
@@ -1479,6 +1830,90 @@ static void ar9170_tx(struct ar9170 *ar)
                                   msecs_to_jiffies(AR9170_JANITOR_DELAY));
 }
 
+static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *txinfo;
+       struct ar9170_sta_info *sta_info;
+       struct ar9170_sta_tid *agg;
+       struct sk_buff *iter;
+       unsigned long flags, f2;
+       unsigned int max;
+       u16 tid, seq, qseq;
+       bool run = false, queue = false;
+
+       tid = ar9170_get_tid(skb);
+       seq = ar9170_get_seq(skb);
+       txinfo = IEEE80211_SKB_CB(skb);
+       sta_info = (void *) txinfo->control.sta->drv_priv;
+       agg = &sta_info->agg[tid];
+       max = sta_info->ampdu_max_len;
+
+       spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+
+       if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
+#ifdef AR9170_TXAGG_DEBUG
+               printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
+                      "for ESS:%pM tid:%d state:%d.\n",
+                      wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
+                      agg->state);
+#endif /* AR9170_TXAGG_DEBUG */
+               goto err_unlock;
+       }
+
+       if (!agg->active) {
+               agg->active = true;
+               agg->ssn = seq;
+               queue = true;
+       }
+
+       /* check if seq is within the BA window */
+       if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
+#ifdef AR9170_TXAGG_DEBUG
+               printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
+                      "fit into BA window (%d - %d)\n",
+                      wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
+                      (agg->ssn + max) & 0xfff);
+#endif /* AR9170_TXAGG_DEBUG */
+               goto err_unlock;
+       }
+
+       spin_lock_irqsave(&agg->queue.lock, f2);
+
+       skb_queue_reverse_walk(&agg->queue, iter) {
+               qseq = ar9170_get_seq(iter);
+
+               if (GET_NEXT_SEQ(qseq) == seq) {
+                       __skb_queue_after(&agg->queue, iter, skb);
+                       goto queued;
+               }
+       }
+
+       __skb_queue_head(&agg->queue, skb);
+
+queued:
+       spin_unlock_irqrestore(&agg->queue.lock, f2);
+
+#ifdef AR9170_TXAGG_DEBUG
+       printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
+              wiphy_name(ar->hw->wiphy), skb);
+       __ar9170_dump_txqueue(ar, &agg->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+       if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
+               run = true;
+
+       if (queue)
+               list_add_tail(&agg->list, &ar->tx_ampdu_list);
+
+       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+       return run;
+
+err_unlock:
+       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+       dev_kfree_skb_irq(skb);
+       return false;
+}
+
 int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ar9170 *ar = hw->priv;
@@ -1492,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        info = IEEE80211_SKB_CB(skb);
        if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-               /* drop frame, we do not allow TX A-MPDU aggregation yet. */
-               goto err_free;
+               bool run = ar9170_tx_ampdu_queue(ar, skb);
+
+               if (run || !ar->tx_ampdu_pending)
+                       ar9170_tx_ampdu(ar);
        } else {
                unsigned int queue = skb_get_queue_mapping(skb);
 
@@ -1931,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
                              enum sta_notify_cmd cmd,
                              struct ieee80211_sta *sta)
 {
+       struct ar9170 *ar = hw->priv;
+       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+       unsigned int i;
+
+       switch (cmd) {
+       case STA_NOTIFY_ADD:
+               memset(sta_info, 0, sizeof(*sta_info));
+
+               if (!sta->ht_cap.ht_supported)
+                       break;
+
+               if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
+                       ar->global_ampdu_density = sta->ht_cap.ampdu_density;
+
+               if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
+                       ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
+
+               for (i = 0; i < AR9170_NUM_TID; i++) {
+                       sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
+                       sta_info->agg[i].active = false;
+                       sta_info->agg[i].ssn = 0;
+                       sta_info->agg[i].retry = 0;
+                       sta_info->agg[i].tid = i;
+                       INIT_LIST_HEAD(&sta_info->agg[i].list);
+                       skb_queue_head_init(&sta_info->agg[i].queue);
+               }
+
+               sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+               break;
+
+       case STA_NOTIFY_REMOVE:
+               if (!sta->ht_cap.ht_supported)
+                       break;
+
+               for (i = 0; i < AR9170_NUM_TID; i++) {
+                       sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
+                       skb_queue_purge(&sta_info->agg[i].queue);
+               }
+
+               break;
+
+       default:
+               break;
+       }
+
+       if (IS_STARTED(ar) && ar->filter_changed)
+               queue_work(ar->hw->workqueue, &ar->filter_config_work);
 }
 
 static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1985,18 +2469,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
                               enum ieee80211_ampdu_mlme_action action,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
+       struct ar9170 *ar = hw->priv;
+       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+       struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
+       unsigned long flags;
+
+       if (!modparam_ht)
+               return -EOPNOTSUPP;
+
        switch (action) {
+       case IEEE80211_AMPDU_TX_START:
+               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+               if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
+                   !list_empty(&tid_info->list)) {
+                       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+#ifdef AR9170_TXAGG_DEBUG
+                       printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
+                              "is in a very bad state!\n",
+                              wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+                       return -EBUSY;
+               }
+
+               *ssn = tid_info->ssn;
+               tid_info->state = AR9170_TID_STATE_PROGRESS;
+               tid_info->active = false;
+               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+               ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+               break;
+
+       case IEEE80211_AMPDU_TX_STOP:
+               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+               tid_info->state = AR9170_TID_STATE_SHUTDOWN;
+               list_del_init(&tid_info->list);
+               tid_info->active = false;
+               skb_queue_purge(&tid_info->queue);
+               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+               ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+               break;
+
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+#ifdef AR9170_TXAGG_DEBUG
+               printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
+                      wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+               sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
+               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+               break;
+
        case IEEE80211_AMPDU_RX_START:
        case IEEE80211_AMPDU_RX_STOP:
-               /*
-                * Something goes wrong -- RX locks up
-                * after a while of receiving aggregated
-                * frames -- not enabling for now.
-                */
-               return -EOPNOTSUPP;
+               /* Handled by firmware */
+               break;
+
        default:
                return -EOPNOTSUPP;
        }
+
+       return 0;
 }
 
 static const struct ieee80211_ops ar9170_ops = {
@@ -2045,6 +2576,8 @@ void *ar9170_alloc(size_t priv_size)
        mutex_init(&ar->mutex);
        spin_lock_init(&ar->cmdlock);
        spin_lock_init(&ar->tx_stats_lock);
+       spin_lock_init(&ar->tx_ampdu_list_lock);
+       skb_queue_head_init(&ar->tx_status_ampdu);
        for (i = 0; i < __AR9170_NUM_TXQ; i++) {
                skb_queue_head_init(&ar->tx_status[i]);
                skb_queue_head_init(&ar->tx_pending[i]);
@@ -2053,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size)
        INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
        INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
        INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
+       INIT_LIST_HEAD(&ar->tx_ampdu_list);
 
        /* all hw supports 2.4 GHz, so set channel to 1 by default */
        ar->channel = &ar9170_2ghz_chantable[0];
@@ -2066,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size)
                         IEEE80211_HW_SIGNAL_DBM |
                         IEEE80211_HW_NOISE_DBM;
 
+       if (modparam_ht) {
+               ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+       } else {
+               ar9170_band_2GHz.ht_cap.ht_supported = false;
+               ar9170_band_5GHz.ht_cap.ht_supported = false;
+       }
+
        ar->hw->queues = __AR9170_NUM_TXQ;
        ar->hw->extra_tx_headroom = 8;
        ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@@ -2087,10 +2628,10 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
 {
 #define RW     8       /* number of words to read at once */
 #define RB     (sizeof(u32) * RW)
-       DECLARE_MAC_BUF(mbuf);
        u8 *eeprom = (void *)&ar->eeprom;
        u8 *addr = ar->eeprom.mac_address;
        __le32 offsets[RW];
+       unsigned int rx_streams, tx_streams, tx_params = 0;
        int i, j, err, bands = 0;
 
        BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@@ -2127,6 +2668,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
                ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
                bands++;
        }
+
+       rx_streams = hweight8(ar->eeprom.rx_mask);
+       tx_streams = hweight8(ar->eeprom.tx_mask);
+
+       if (rx_streams != tx_streams)
+               tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+       if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
+               tx_params = (tx_streams - 1) <<
+                           IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+       ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+       ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+
        /*
         * I measured this, a bandswitch takes roughly
         * 135 ms and a frequency switch about 80.
index 6809b54..debad07 100644 (file)
 #define AR5K_SISR2             0x008c                  /* Register Address [5211+] */
 #define AR5K_SISR2_QCU_TXURN   0x000003ff      /* Mask for QCU_TXURN */
 #define        AR5K_SISR2_QCU_TXURN_S  0
-#define        AR5K_SISR2_MCABT        0x00100000      /* Master Cycle Abort */
-#define        AR5K_SISR2_SSERR        0x00200000      /* Signaled System Error */
-#define        AR5K_SISR2_DPERR        0x00400000      /* Bus parity error */
+#define        AR5K_SISR2_MCABT        0x00010000      /* Master Cycle Abort */
+#define        AR5K_SISR2_SSERR        0x00020000      /* Signaled System Error */
+#define        AR5K_SISR2_DPERR        0x00040000      /* Bus parity error */
 #define        AR5K_SISR2_TIM          0x01000000      /* [5212+] */
 #define        AR5K_SISR2_CAB_END      0x02000000      /* [5212+] */
 #define        AR5K_SISR2_DTIM_SYNC    0x04000000      /* DTIM sync lost [5212+] */
 #define AR5K_SIMR2             0x00ac                  /* Register Address [5211+] */
 #define AR5K_SIMR2_QCU_TXURN   0x000003ff      /* Mask for QCU_TXURN */
 #define AR5K_SIMR2_QCU_TXURN_S 0
-#define        AR5K_SIMR2_MCABT        0x00100000      /* Master Cycle Abort */
-#define        AR5K_SIMR2_SSERR        0x00200000      /* Signaled System Error */
-#define        AR5K_SIMR2_DPERR        0x00400000      /* Bus parity error */
+#define        AR5K_SIMR2_MCABT        0x00010000      /* Master Cycle Abort */
+#define        AR5K_SIMR2_SSERR        0x00020000      /* Signaled System Error */
+#define        AR5K_SIMR2_DPERR        0x00040000      /* Bus parity error */
 #define        AR5K_SIMR2_TIM          0x01000000      /* [5212+] */
 #define        AR5K_SIMR2_CAB_END      0x02000000      /* [5212+] */
 #define        AR5K_SIMR2_DTIM_SYNC    0x04000000      /* DTIM Sync lost [5212+] */
index eb9d522..751885a 100644 (file)
@@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 #define WME_NUM_TID             16
 #define ATH_TXBUF               512
 #define ATH_TXMAXTRY            13
-#define ATH_11N_TXMAXTRY        10
 #define ATH_MGT_TXMAXTRY        4
 #define WME_BA_BMP_SIZE         64
 #define WME_MAX_BA              WME_BA_BMP_SIZE
@@ -226,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 #define ATH_DS_TX_BA(_ds)          ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
 #define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
 
+#define ATH_TX_COMPLETE_POLL_INT       1000
+
 enum ATH_AGGR_STATUS {
        ATH_AGGR_DONE,
        ATH_AGGR_BAW_CLOSED,
@@ -241,6 +242,7 @@ struct ath_txq {
        u8 axq_aggr_depth;
        u32 axq_totalqueued;
        bool stopped;
+       bool axq_tx_inprogress;
        struct ath_buf *axq_linkbuf;
 
        /* first desc of the last descriptor that contains CTS */
@@ -291,12 +293,28 @@ struct ath_tx_control {
 #define ATH_TX_XRETRY       0x02
 #define ATH_TX_BAR          0x04
 
+#define ATH_RSSI_LPF_LEN               10
+#define RSSI_LPF_THRESHOLD             -20
+#define ATH9K_RSSI_BAD                 0x80
+#define ATH_RSSI_EP_MULTIPLIER     (1<<7)
+#define ATH_EP_MUL(x, mul)         ((x) * (mul))
+#define ATH_RSSI_IN(x)             (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+    ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do {                                        \
+    if ((y) >= RSSI_LPF_THRESHOLD)                                     \
+       x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN);      \
+} while (0)
+#define ATH_EP_RND(x, mul)                                             \
+       ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
 struct ath_node {
        struct ath_softc *an_sc;
        struct ath_atx_tid tid[WME_NUM_TID];
        struct ath_atx_ac ac[WME_NUM_AC];
        u16 maxampdu;
        u8 mpdudensity;
+       int last_rssi;
 };
 
 struct ath_tx {
@@ -541,6 +559,7 @@ struct ath_softc {
        spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
        spinlock_t ani_lock;
+       spinlock_t sc_pm_lock;
        struct mutex mutex;
 
        u8 curbssid[ETH_ALEN];
@@ -557,7 +576,7 @@ struct ath_softc {
        u32 keymax;
        DECLARE_BITMAP(keymap, ATH_KEYMAX);
        u8 splitmic;
-       atomic_t ps_usecount;
+       unsigned long ps_usecount;
        enum ath9k_int imask;
        enum ath9k_ht_extprotspacing ht_extprotspacing;
        enum ath9k_ht_macmode tx_chan_width;
@@ -590,6 +609,7 @@ struct ath_softc {
 #endif
        struct ath_bus_ops *bus_ops;
        struct ath_beacon_config cur_beacon_conf;
+       struct delayed_work tx_complete_work;
 };
 
 struct ath_wiphy {
@@ -654,27 +674,8 @@ static inline int ath_ahb_init(void) { return 0; };
 static inline void ath_ahb_exit(void) {};
 #endif
 
-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
-{
-       if (atomic_inc_return(&sc->ps_usecount) == 1)
-               if (sc->sc_ah->power_mode !=  ATH9K_PM_AWAKE) {
-                       sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
-                       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
-               }
-}
-
-static inline void ath9k_ps_restore(struct ath_softc *sc)
-{
-       if (atomic_dec_and_test(&sc->ps_usecount))
-               if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
-                   !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
-                                     SC_OP_WAIT_FOR_CAB |
-                                     SC_OP_WAIT_FOR_PSPOLL_DATA |
-                                     SC_OP_WAIT_FOR_TX_ACK)))
-                       ath9k_hw_setpower(sc->sc_ah,
-                                         sc->sc_ah->restore_mode);
-}
-
+void ath9k_ps_wakeup(struct ath_softc *sc);
+void ath9k_ps_restore(struct ath_softc *sc);
 
 void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
 int ath9k_wiphy_add(struct ath_softc *sc);
@@ -690,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
                                  struct ath_wiphy *selected);
 bool ath9k_wiphy_scanning(struct ath_softc *sc);
 void ath9k_wiphy_work(struct work_struct *work);
+bool ath9k_all_wiphys_idle(struct ath_softc *sc);
 
 void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
 unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
index a32d7e7..1f0c5fe 100644 (file)
@@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
 {
        int i, j;
+       s16 noise_floor;
+
+       if (AR_SREV_9280(ah))
+               noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+       else if (AR_SREV_9285(ah))
+               noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+       else
+               noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
 
        for (i = 0; i < NUM_NF_READINGS; i++) {
                ah->nfCalHist[i].currIndex = 0;
-               ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+               ah->nfCalHist[i].privNF = noise_floor;
                ah->nfCalHist[i].invalidNFcount =
                        AR_PHY_CCA_FILTERWINDOW_LENGTH;
                for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-                       ah->nfCalHist[i].nfCalBuffer[j] =
-                               AR_PHY_CCA_MAX_GOOD_VALUE;
+                       ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
                }
        }
 }
index fe5367f..547e697 100644 (file)
@@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
 extern const struct ath9k_percal_data adc_dc_cal_single_sample;
 extern const struct ath9k_percal_data adc_init_dc_cal;
 
-#define AR_PHY_CCA_MAX_GOOD_VALUE                      -85
+#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE       -85
+#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE       -112
+#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE       -118
 #define AR_PHY_CCA_MAX_HIGH_VALUE                      -62
 #define AR_PHY_CCA_MIN_BAD_VALUE                       -140
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
index d82a0f9..df41ed5 100644 (file)
@@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
                              pModal->xatten2Margin[0]);
                REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
                              AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+               /* Set the block 1 value to block 0 value */
+               REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+                             AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+                             pModal->bswMargin[0]);
+               REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+                             AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+               REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+                             AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+                             pModal->xatten2Margin[0]);
+               REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+                             AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+                             pModal->xatten2Db[0]);
        }
 
        REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
@@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
        REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
                      AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
 
+       REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+                     AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+       REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+                     AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
        if (AR_SREV_9285_11(ah))
                REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
 }
@@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
        ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);
 
        /* Initialize Ant Diversity settings from EEPROM */
-       if (pModal->version == 3) {
+       if (pModal->version >= 3) {
                ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
                ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
                regVal = REG_READ(ah, 0x99ac);
index cffb078..605803a 100644 (file)
@@ -2728,7 +2728,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
        return true;
 }
 
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+                                    enum ath9k_power_mode mode)
 {
        int status = true, setChip = true;
        static const char *modes[] = {
@@ -2762,6 +2763,55 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
        return status;
 }
 
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
+       ret = ath9k_hw_setpower_nolock(ah, mode);
+       spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
+
+       return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (++sc->ps_usecount != 1)
+               goto unlock;
+
+       if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
+               sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+               ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+       }
+
+ unlock:
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (--sc->ps_usecount != 0)
+               goto unlock;
+
+       if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
+               !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+                               SC_OP_WAIT_FOR_CAB |
+                               SC_OP_WAIT_FOR_PSPOLL_DATA |
+                               SC_OP_WAIT_FOR_TX_ACK)))
+               ath9k_hw_setpower_nolock(sc->sc_ah,
+                                     sc->sc_ah->restore_mode);
+
+ unlock:
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
 /*
  * Helper for ASPM support.
  *
@@ -3305,7 +3355,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        if (eeval & AR5416_OPFLAGS_11G) {
-               set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
                set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
                if (ah->config.ht_enable) {
                        if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3791,19 +3840,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
 
 void ath9k_hw_reset_tsf(struct ath_hw *ah)
 {
-       int count;
+       ath9k_ps_wakeup(ah->ah_sc);
+       if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
+                          AH_TSF_WRITE_TIMEOUT))
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
 
-       count = 0;
-       while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
-               count++;
-               if (count > 10) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                               "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
-                       break;
-               }
-               udelay(10);
-       }
        REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+       ath9k_ps_restore(ah->ah_sc);
 }
 
 bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
index 9d0b31a..28bffdb 100644 (file)
@@ -95,6 +95,7 @@
 
 #define MAX_RATE_POWER              63
 #define AH_WAIT_TIMEOUT             100000 /* (us) */
+#define AH_TSF_WRITE_TIMEOUT        100    /* (us) */
 #define AH_TIME_QUANTUM             10
 #define AR_KEYTABLE_SIZE            128
 #define POWER_UP_TIME               200000
 
 enum wireless_mode {
        ATH9K_MODE_11A = 0,
-       ATH9K_MODE_11B = 2,
-       ATH9K_MODE_11G = 3,
-       ATH9K_MODE_11NA_HT20 = 6,
-       ATH9K_MODE_11NG_HT20 = 7,
-       ATH9K_MODE_11NA_HT40PLUS = 8,
-       ATH9K_MODE_11NA_HT40MINUS = 9,
-       ATH9K_MODE_11NG_HT40PLUS = 10,
-       ATH9K_MODE_11NG_HT40MINUS = 11,
-       ATH9K_MODE_MAX
+       ATH9K_MODE_11G,
+       ATH9K_MODE_11NA_HT20,
+       ATH9K_MODE_11NG_HT20,
+       ATH9K_MODE_11NA_HT40PLUS,
+       ATH9K_MODE_11NA_HT40MINUS,
+       ATH9K_MODE_11NG_HT40PLUS,
+       ATH9K_MODE_11NG_HT40MINUS,
+       ATH9K_MODE_MAX,
 };
 
 enum ath9k_hw_caps {
index e2f0a34..f67a2a9 100644 (file)
@@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00008338, 0x00ff0000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
-    { 0x00008344, 0x00581043 },
+    { 0x00008344, 0x00481043 },
     { 0x00009808, 0x00000000 },
     { 0x0000980c, 0xafa68e30 },
     { 0x00009810, 0xfd14e000 },
@@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
     {0x00004044,  0x00000000 },
 };
 
-/* AR9285 */
+/* AR9285 Revsion 10*/
 static const u_int32_t ar9285Modes_9285[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
     { 0x00008338, 0x00000000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x00010380 },
-    { 0x00008344, 0x00581043 },
+    { 0x00008344, 0x00481043 },
     { 0x00009808, 0x00000000 },
     { 0x0000980c, 0xafe68e30 },
     { 0x00009810, 0xfd14e000 },
@@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
     {0x00004044,  0x00000000 },
 };
 
-/* AR9285 v1_2 PCI Register Writes.  Created: 03/04/09 */
+/* AR9285 v1_2 PCI Register Writes.  Created: 04/13/09 */
 static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
     { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
     { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
     { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
     { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
     { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
     { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
     { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
     { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+    { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
     { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
     { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
     { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00008338, 0x00ff0000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x00010380 },
-    { 0x00008344, 0x00581043 },
+    { 0x00008344, 0x00481043 },
     { 0x00009808, 0x00000000 },
     { 0x0000980c, 0xafe68e30 },
     { 0x00009810, 0xfd14e000 },
@@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
 static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
     { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
     { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
     { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
     { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
     { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
@@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
     { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
     { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
     { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
-    { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
-    { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
-    { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+    { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+    { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
 };
 
 static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
index 8ae4ec2..6f923e3 100644 (file)
@@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
        ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
        ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
 
-       ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-       ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
-       ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
-       ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
-       ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
-       ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
-       ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+       if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
+               ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
+               ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+               ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+               ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+               ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
+               ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
+               ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
+       } else {
+               ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+               ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+                                               AR_RxRSSIAnt00);
+               ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+                                               AR_RxRSSIAnt01);
+               ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+                                               AR_RxRSSIAnt02);
+               ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+                                               AR_RxRSSIAnt10);
+               ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+                                               AR_RxRSSIAnt11);
+               ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+                                               AR_RxRSSIAnt12);
+       }
        if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
                ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
        else
index 961b0ce..3436295 100644 (file)
@@ -465,6 +465,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
                an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
                                     sta->ht_cap.ampdu_factor);
                an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+               an->last_rssi = ATH_RSSI_DUMMY_MARKER;
        }
 }
 
@@ -1258,6 +1259,7 @@ void ath_detach(struct ath_softc *sc)
        ath_deinit_leds(sc);
        cancel_work_sync(&sc->chan_work);
        cancel_delayed_work_sync(&sc->wiphy_work);
+       cancel_delayed_work_sync(&sc->tx_complete_work);
 
        for (i = 0; i < sc->num_sec_wiphy; i++) {
                struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1284,7 +1286,6 @@ void ath_detach(struct ath_softc *sc)
 
        ath9k_hw_detach(sc->sc_ah);
        ath9k_exit_debug(sc);
-       ath9k_ps_restore(sc);
 }
 
 static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1315,6 +1316,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
        spin_lock_init(&sc->sc_resetlock);
        spin_lock_init(&sc->sc_serial_rw);
        spin_lock_init(&sc->ani_lock);
+       spin_lock_init(&sc->sc_pm_lock);
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
        tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -1540,7 +1542,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        hw->max_rates = 4;
        hw->channel_change_time = 5000;
        hw->max_listen_interval = 10;
-       hw->max_rate_tries = ATH_11N_TXMAXTRY;
+       /* Hardware supports 10 but we use 4 */
+       hw->max_rate_tries = 4;
        hw->sta_data_size = sizeof(struct ath_node);
        hw->vif_data_size = sizeof(struct ath_vif);
 
@@ -1977,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        ieee80211_wake_queues(hw);
 
+       queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
+
 mutex_unlock:
        mutex_unlock(&sc->mutex);
 
@@ -2096,8 +2101,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        mutex_lock(&sc->mutex);
 
-       ieee80211_stop_queues(hw);
-
        if (ath9k_wiphy_started(sc)) {
                mutex_unlock(&sc->mutex);
                return; /* another wiphy still in use */
@@ -2255,9 +2258,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        struct ath_softc *sc = aphy->sc;
        struct ieee80211_conf *conf = &hw->conf;
        struct ath_hw *ah = sc->sc_ah;
+       bool all_wiphys_idle = false, disable_radio = false;
 
        mutex_lock(&sc->mutex);
 
+       /* Leave this as the first check */
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+
+               spin_lock_bh(&sc->wiphy_lock);
+               all_wiphys_idle =  ath9k_all_wiphys_idle(sc);
+               spin_unlock_bh(&sc->wiphy_lock);
+
+               if (conf->flags & IEEE80211_CONF_IDLE){
+                       if (all_wiphys_idle)
+                               disable_radio = true;
+               }
+               else if (all_wiphys_idle) {
+                       ath_radio_enable(sc);
+                       DPRINTF(sc, ATH_DBG_CONFIG,
+                               "not-idle: enabling radio\n");
+               }
+       }
+
        if (changed & IEEE80211_CONF_CHANGE_PS) {
                if (conf->flags & IEEE80211_CONF_PS) {
                        if (!(ah->caps.hw_caps &
@@ -2325,6 +2347,11 @@ skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER)
                sc->config.txpowlimit = 2 * conf->power_level;
 
+       if (disable_radio) {
+               DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+               ath_radio_disable(sc);
+       }
+
        mutex_unlock(&sc->mutex);
 
        return 0;
index ba06e78..a07efa2 100644 (file)
@@ -22,133 +22,132 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
        {
                { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
                        5400, 0x0b, 0x00, 12,
-                       0, 2, 1, 0, 0, 0, 0, 0 },
+                       0, 0, 0, 0, 0, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
                        7800,  0x0f, 0x00, 18,
-                       0, 3, 1, 1, 1, 1, 1, 0 },
+                       0, 1, 1, 1, 1, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
                        10000, 0x0a, 0x00, 24,
-                       2, 4, 2, 2, 2, 2, 2, 0 },
+                       2, 2, 2, 2, 2, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
                        13900, 0x0e, 0x00, 36,
-                       2, 6,  2, 3, 3, 3, 3, 0 },
+                       2,  3, 3, 3, 3, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
                        17300, 0x09, 0x00, 48,
-                       4, 10, 3, 4, 4, 4, 4, 0 },
+                       4,  4, 4, 4, 4, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
                        23000, 0x0d, 0x00, 72,
-                       4, 14, 3, 5, 5, 5, 5, 0 },
+                       4,  5, 5, 5, 5, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
                        27400, 0x08, 0x00, 96,
-                       4, 20, 3, 6, 6, 6, 6, 0 },
+                       4,  6, 6, 6, 6, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
                        29300, 0x0c, 0x00, 108,
-                       4, 23, 3, 7, 7, 7, 7, 0 },
+                       4,  7, 7, 7, 7, 0 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
                        6400, 0x80, 0x00, 0,
-                       0, 2, 3, 8, 24, 8, 24, 3216 },
+                       0, 8, 24, 8, 24, 3216 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
                        12700, 0x81, 0x00, 1,
-                       2, 4, 3, 9, 25, 9, 25, 6434 },
+                       2, 9, 25, 9, 25, 6434 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
                        18800, 0x82, 0x00, 2,
-                       2, 6, 3, 10, 26, 10, 26, 9650 },
+                       2, 10, 26, 10, 26, 9650 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
                        25000, 0x83, 0x00, 3,
-                       4, 10, 3, 11, 27, 11, 27, 12868 },
+                       4,  11, 27, 11, 27, 12868 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
                        36700, 0x84, 0x00, 4,
-                       4, 14, 3, 12, 28, 12, 28, 19304 },
+                       4,  12, 28, 12, 28, 19304 },
                { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
                        48100, 0x85, 0x00, 5,
-                       4, 20, 3, 13, 29, 13, 29, 25740 },
+                       4,  13, 29, 13, 29, 25740 },
                { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
                        53500, 0x86, 0x00, 6,
-                       4, 23, 3, 14, 30, 14, 30,  28956 },
+                       4,  14, 30, 14, 30,  28956 },
                { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
                        59000, 0x87, 0x00, 7,
-                       4, 25, 3, 15, 31, 15, 32, 32180 },
+                       4,  15, 31, 15, 32, 32180 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
                        12700, 0x88, 0x00,
-                       8, 0, 2, 3, 16, 33, 16, 33, 6430 },
+                       8, 3, 16, 33, 16, 33, 6430 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
                        24800, 0x89, 0x00, 9,
-                       2, 4, 3, 17, 34, 17, 34, 12860 },
+                       2, 17, 34, 17, 34, 12860 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
                        36600, 0x8a, 0x00, 10,
-                       2, 6, 3, 18, 35, 18, 35, 19300 },
+                       2, 18, 35, 18, 35, 19300 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
                        48100, 0x8b, 0x00, 11,
-                       4, 10, 3, 19, 36, 19, 36, 25736 },
+                       4,  19, 36, 19, 36, 25736 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
                        69500, 0x8c, 0x00, 12,
-                       4, 14, 3, 20, 37, 20, 37, 38600 },
+                       4,  20, 37, 20, 37, 38600 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
                        89500, 0x8d, 0x00, 13,
-                       4, 20, 3, 21, 38, 21, 38, 51472 },
+                       4,  21, 38, 21, 38, 51472 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
                        98900, 0x8e, 0x00, 14,
-                       4, 23, 3, 22, 39, 22, 39, 57890 },
+                       4,  22, 39, 22, 39, 57890 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
                        108300, 0x8f, 0x00, 15,
-                       4, 25, 3, 23, 40, 23, 41, 64320 },
+                       4,  23, 40, 23, 41, 64320 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
                        13200, 0x80, 0x00, 0,
-                       0, 2, 3, 8, 24, 24, 24, 6684 },
+                       0, 8, 24, 24, 24, 6684 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
                        25900, 0x81, 0x00, 1,
-                       2, 4, 3, 9, 25, 25, 25, 13368 },
+                       2, 9, 25, 25, 25, 13368 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
                        38600, 0x82, 0x00, 2,
-                       2, 6, 3, 10, 26, 26, 26, 20052 },
+                       2, 10, 26, 26, 26, 20052 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
                        49800, 0x83, 0x00, 3,
-                       4, 10, 3, 11, 27, 27, 27, 26738 },
+                       4,  11, 27, 27, 27, 26738 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
                        72200, 0x84, 0x00, 4,
-                       4, 14, 3, 12, 28, 28, 28, 40104 },
+                       4,  12, 28, 28, 28, 40104 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
                        92900, 0x85, 0x00, 5,
-                       4, 20, 3, 13, 29, 29, 29, 53476 },
+                       4,  13, 29, 29, 29, 53476 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
                        102700, 0x86, 0x00, 6,
-                       4, 23, 3, 14, 30, 30, 30, 60156 },
+                       4,  14, 30, 30, 30, 60156 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
                        112000, 0x87, 0x00, 7,
-                       4, 25, 3, 15, 31, 32, 32, 66840 },
+                       4,  15, 31, 32, 32, 66840 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
                        122000, 0x87, 0x00, 7,
-                       4, 25, 3, 15, 31, 32, 32, 74200 },
+                       4,  15, 31, 32, 32, 74200 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
                        25800, 0x88, 0x00, 8,
-                       0, 2, 3, 16, 33, 33, 33, 13360 },
+                       0, 16, 33, 33, 33, 13360 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
                        49800, 0x89, 0x00, 9,
-                       2, 4, 3, 17, 34, 34, 34, 26720 },
+                       2, 17, 34, 34, 34, 26720 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
                        71900, 0x8a, 0x00, 10,
-                       2, 6, 3, 18, 35, 35, 35, 40080 },
+                       2, 18, 35, 35, 35, 40080 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
                        92500, 0x8b, 0x00, 11,
-                       4, 10, 3, 19, 36, 36, 36, 53440 },
+                       4,  19, 36, 36, 36, 53440 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
                        130300, 0x8c, 0x00, 12,
-                       4, 14, 3, 20, 37, 37, 37, 80160 },
+                       4,  20, 37, 37, 37, 80160 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
                        162800, 0x8d, 0x00, 13,
-                       4, 20, 3, 21, 38, 38, 38, 106880 },
+                       4,  21, 38, 38, 38, 106880 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
                        178200, 0x8e, 0x00, 14,
-                       4, 23, 3, 22, 39, 39, 39, 120240 },
+                       4,  22, 39, 39, 39, 120240 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
                        192100, 0x8f, 0x00, 15,
-                       4, 25, 3, 23, 40, 41, 41, 133600 },
+                       4,  23, 40, 41, 41, 133600 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
                        207000, 0x8f, 0x00, 15,
-                       4, 25, 3, 23, 40, 41, 41, 148400 },
+                       4,  23, 40, 41, 41, 148400 },
        },
        50,  /* probe interval */
-       50,  /* rssi reduce interval */
        WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
 };
 
@@ -160,145 +159,144 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
        {
                { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
                        900, 0x1b, 0x00, 2,
-                       0, 0, 1, 0, 0, 0, 0, 0 },
+                       0, 0, 0, 0, 0, 0 },
                { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
                        1900, 0x1a, 0x04, 4,
-                       1, 1, 1, 1, 1, 1, 1, 0 },
+                       1, 1, 1, 1, 1, 0 },
                { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
                        4900, 0x19, 0x04, 11,
-                       2, 2, 2, 2, 2, 2, 2, 0 },
+                       2, 2, 2, 2, 2, 0 },
                { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
                        8100, 0x18, 0x04, 22,
-                       3, 3, 2, 3, 3, 3, 3, 0 },
+                       3, 3, 3, 3, 3, 0 },
                { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
                        5400, 0x0b, 0x00, 12,
-                       4, 2, 1, 4, 4, 4, 4, 0 },
+                       4, 4, 4, 4, 4, 0 },
                { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
                        7800, 0x0f, 0x00, 18,
-                       4, 3, 1, 5, 5, 5, 5, 0 },
+                       4, 5, 5, 5, 5, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
                        10100, 0x0a, 0x00, 24,
-                       6, 4, 1, 6, 6, 6, 6, 0 },
+                       6, 6, 6, 6, 6, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
                        14100,  0x0e, 0x00, 36,
-                       6, 6, 2, 7, 7, 7, 7, 0 },
+                       6, 7, 7, 7, 7, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
                        17700, 0x09, 0x00, 48,
-                       8, 10, 3, 8, 8, 8, 8, 0 },
+                       8,  8, 8, 8, 8, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
                        23700, 0x0d, 0x00, 72,
-                       8, 14, 3, 9, 9, 9, 9, 0 },
+                       8,  9, 9, 9, 9, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
                        27400, 0x08, 0x00, 96,
-                       8, 20, 3, 10, 10, 10, 10, 0 },
+                       8,  10, 10, 10, 10, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
                        30900, 0x0c, 0x00, 108,
-                       8, 23, 3, 11, 11, 11, 11, 0 },
+                       8,  11, 11, 11, 11, 0 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
                        6400, 0x80, 0x00, 0,
-                       4, 2, 3, 12, 28, 12, 28, 3216 },
+                       4, 12, 28, 12, 28, 3216 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
                        12700, 0x81, 0x00, 1,
-                       6, 4, 3, 13, 29, 13, 29, 6434 },
+                       6, 13, 29, 13, 29, 6434 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
                        18800, 0x82, 0x00, 2,
-                       6, 6, 3, 14, 30, 14, 30, 9650 },
+                       6, 14, 30, 14, 30, 9650 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
                        25000, 0x83, 0x00, 3,
-                       8, 10, 3, 15, 31, 15, 31, 12868 },
+                       8,  15, 31, 15, 31, 12868 },
                { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
                        36700, 0x84, 0x00, 4,
-                       8, 14, 3, 16, 32, 16, 32, 19304 },
+                       8,  16, 32, 16, 32, 19304 },
                { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
                        48100, 0x85, 0x00, 5,
-                       8, 20, 3, 17, 33, 17, 33, 25740 },
+                       8,  17, 33, 17, 33, 25740 },
                { INVALID,  VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
                        53500, 0x86, 0x00, 6,
-                       8, 23, 3, 18, 34, 18, 34, 28956 },
+                       8,  18, 34, 18, 34, 28956 },
                { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
                        59000, 0x87, 0x00, 7,
-                       8, 25, 3, 19, 35, 19, 36, 32180 },
+                       8,  19, 35, 19, 36, 32180 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
                        12700, 0x88, 0x00, 8,
-                       4, 2, 3, 20, 37, 20, 37, 6430 },
+                       4, 20, 37, 20, 37, 6430 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
                        24800, 0x89, 0x00, 9,
-                       6, 4, 3, 21, 38, 21, 38, 12860 },
+                       6, 21, 38, 21, 38, 12860 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
                        36600, 0x8a, 0x00, 10,
-                       6, 6, 3, 22, 39, 22, 39, 19300 },
+                       6, 22, 39, 22, 39, 19300 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
                        48100, 0x8b, 0x00, 11,
-                       8, 10, 3, 23, 40, 23, 40, 25736 },
+                       8,  23, 40, 23, 40, 25736 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
                        69500, 0x8c, 0x00, 12,
-                       8, 14, 3, 24, 41, 24, 41, 38600 },
+                       8,  24, 41, 24, 41, 38600 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
                        89500, 0x8d, 0x00, 13,
-                       8, 20, 3, 25, 42, 25, 42, 51472 },
+                       8,  25, 42, 25, 42, 51472 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
                        98900, 0x8e, 0x00, 14,
-                       8, 23, 3, 26, 43, 26, 44, 57890 },
+                       8,  26, 43, 26, 44, 57890 },
                { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
                        108300, 0x8f, 0x00, 15,
-                       8, 25, 3, 27, 44, 27, 45, 64320 },
+                       8,  27, 44, 27, 45, 64320 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
                        13200, 0x80, 0x00, 0,
-                       8, 2, 3, 12, 28, 28, 28, 6684 },
+                       8, 12, 28, 28, 28, 6684 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
                        25900, 0x81, 0x00, 1,
-                       8, 4, 3, 13, 29, 29, 29, 13368 },
+                       8, 13, 29, 29, 29, 13368 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
                        38600, 0x82, 0x00, 2,
-                       8, 6, 3, 14, 30, 30, 30, 20052 },
+                       8, 14, 30, 30, 30, 20052 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
                        49800, 0x83, 0x00, 3,
-                       8, 10, 3, 15, 31, 31, 31, 26738 },
+                       8,  15, 31, 31, 31, 26738 },
                { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
                        72200, 0x84, 0x00, 4,
-                       8, 14, 3, 16, 32, 32, 32, 40104 },
+                       8,  16, 32, 32, 32, 40104 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
                        92900, 0x85, 0x00, 5,
-                       8, 20, 3, 17, 33, 33, 33, 53476 },
+                       8,  17, 33, 33, 33, 53476 },
                { INVALID,  VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
                        102700, 0x86, 0x00, 6,
-                       8, 23, 3, 18, 34, 34, 34, 60156 },
+                       8,  18, 34, 34, 34, 60156 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
                        112000, 0x87, 0x00, 7,
-                       8, 23, 3, 19, 35, 36, 36, 66840 },
+                       8,  19, 35, 36, 36, 66840 },
                { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
                        122000, 0x87, 0x00, 7,
-                       8, 25, 3, 19, 35, 36, 36, 74200 },
+                       8,  19, 35, 36, 36, 74200 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
                        25800, 0x88, 0x00, 8,
-                       8, 2, 3, 20, 37, 37, 37, 13360 },
+                       8, 20, 37, 37, 37, 13360 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
                        49800, 0x89, 0x00, 9,
-                       8, 4, 3, 21, 38, 38, 38, 26720 },
+                       8, 21, 38, 38, 38, 26720 },
                { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
                        71900, 0x8a, 0x00, 10,
-                       8, 6, 3, 22, 39, 39, 39, 40080 },
+                       8, 22, 39, 39, 39, 40080 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
                        92500, 0x8b, 0x00, 11,
-                       8, 10, 3, 23, 40, 40, 40, 53440 },
+                       8,  23, 40, 40, 40, 53440 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
                        130300, 0x8c, 0x00, 12,
-                       8, 14, 3, 24, 41, 41, 41, 80160 },
+                       8,  24, 41, 41, 41, 80160 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
                        162800, 0x8d, 0x00, 13,
-                       8, 20, 3, 25, 42, 42, 42, 106880 },
+                       8,  25, 42, 42, 42, 106880 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
                        178200, 0x8e, 0x00, 14,
-                       8, 23, 3, 26, 43, 43, 43, 120240 },
+                       8,  26, 43, 43, 43, 120240 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
                        192100, 0x8f, 0x00, 15,
-                       8, 23, 3, 27, 44, 45, 45, 133600 },
+                       8,  27, 44, 45, 45, 133600 },
                { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
                        207000, 0x8f, 0x00, 15,
-                       8, 25, 3, 27, 44, 45, 45, 148400 },
+                       8,  27, 44, 45, 45, 148400 },
                },
        50,  /* probe interval */
-       50,  /* rssi reduce interval */
        WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
 };
 
@@ -307,31 +305,30 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
        {
                { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
                        5400, 0x0b, 0x00, (0x80|12),
-                       0, 2, 1, 0, 0 },
+                       0, 0, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
                        7800, 0x0f, 0x00, 18,
-                       0, 3, 1, 1, 0 },
+                       0, 1, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
                        10000, 0x0a, 0x00, (0x80|24),
-                       2, 4, 2, 2, 0 },
+                       2, 2, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
                        13900, 0x0e, 0x00, 36,
-                       2, 6, 2, 3, 0 },
+                       2, 3, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
                        17300, 0x09, 0x00, (0x80|48),
-                       4, 10, 3, 4, 0 },
+                       4,  4, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
                        23000, 0x0d, 0x00, 72,
-                       4, 14, 3, 5, 0 },
+                       4,  5, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
                        27400, 0x08, 0x00, 96,
-                       4, 19, 3, 6, 0 },
+                       4,  6, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
                        29300, 0x0c, 0x00, 108,
-                       4, 23, 3, 7, 0 },
+                       4,  7, 0 },
        },
        50,  /* probe interval */
-       50,  /* rssi reduce interval */
        0,   /* Phy rates allowed initially */
 };
 
@@ -340,64 +337,42 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
        {
                { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
                        900, 0x1b, 0x00, 2,
-                       0, 0, 1, 0, 0 },
+                       0, 0, 0 },
                { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
                        1900, 0x1a, 0x04, 4,
-                       1, 1, 1, 1, 0 },
+                       1, 1, 0 },
                { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
                        4900, 0x19, 0x04, 11,
-                       2, 2, 2, 2, 0 },
+                       2, 2, 0 },
                { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
                        8100, 0x18, 0x04, 22,
-                       3, 3, 2, 3, 0 },
+                       3, 3, 0 },
                { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
                        5400, 0x0b, 0x00, 12,
-                       4, 2, 1, 4, 0 },
+                       4, 4, 0 },
                { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
                        7800, 0x0f, 0x00, 18,
-                       4, 3, 1, 5, 0 },
+                       4, 5, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
                        10000, 0x0a, 0x00, 24,
-                       6, 4, 1, 6, 0 },
+                       6, 6, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
                        13900, 0x0e, 0x00, 36,
-                       6, 6, 2, 7, 0 },
+                       6, 7, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
                        17300, 0x09, 0x00, 48,
-                       8, 10, 3, 8, 0 },
+                       8,  8, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
                        23000, 0x0d, 0x00, 72,
-                       8, 14, 3, 9, 0 },
+                       8,  9, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
                        27400, 0x08, 0x00, 96,
-                       8, 19, 3, 10, 0 },
+                       8,  10, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
                        29300, 0x0c, 0x00, 108,
-                       8, 23, 3, 11, 0 },
+                       8,  11, 0 },
        },
        50,  /* probe interval */
-       50,  /* rssi reduce interval */
-       0,   /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11b_ratetable = {
-       4,
-       {
-               { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
-                       900, 0x1b,  0x00, (0x80|2),
-                       0, 0, 1, 0, 0 },
-               { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
-                       1800, 0x1a, 0x04, (0x80|4),
-                       1, 1, 1, 1, 0 },
-               { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
-                       4300, 0x19, 0x04, (0x80|11),
-                       1, 2, 2, 2, 0 },
-               { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
-                       7100, 0x18, 0x04, (0x80|22),
-                       1, 4, 100, 3, 0 },
-       },
-       100, /* probe interval */
-       100, /* rssi reduce interval */
        0,   /* Phy rates allowed initially */
 };
 
@@ -454,13 +429,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
        ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
 }
 
-static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
-                                       u8 index)
-{
-       ASSERT(index <= ath_rc_priv->rate_table_size);
-       return ath_rc_priv->valid_rate_index[index];
-}
-
 static inline
 int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
                                struct ath_rate_priv *ath_rc_priv,
@@ -501,9 +469,9 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
 }
 
 static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
-                                struct ath_rate_priv *ath_rc_priv,
-                                u8 cur_valid_txrate, u8 *next_idx)
+ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
+                    struct ath_rate_priv *ath_rc_priv,
+                    u8 cur_valid_txrate, u8 *next_idx)
 {
        int8_t i;
 
@@ -629,52 +597,20 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
        return hi;
 }
 
-static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
-                            struct ath_rate_priv *ath_rc_priv,
-                            const struct ath_rate_table *rate_table,
-                            int *is_probing)
+/* Finds the highest rate index we can use */
+static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
+                                struct ath_rate_priv *ath_rc_priv,
+                                const struct ath_rate_table *rate_table,
+                                int *is_probing)
 {
-       u32 dt, best_thruput, this_thruput, now_msec;
+       u32 best_thruput, this_thruput, now_msec;
        u8 rate, next_rate, best_rate, maxindex, minindex;
-       int8_t  rssi_last, rssi_reduce = 0, index = 0;
-
-       *is_probing = 0;
-
-       rssi_last = median(ath_rc_priv->rssi_last,
-                          ath_rc_priv->rssi_last_prev,
-                          ath_rc_priv->rssi_last_prev2);
-
-       /*
-        * Age (reduce) last ack rssi based on how old it is.
-        * The bizarre numbers are so the delta is 160msec,
-        * meaning we divide by 16.
-        *   0msec   <= dt <= 25msec:   don't derate
-        *   25msec  <= dt <= 185msec:  derate linearly from 0 to 10dB
-        *   185msec <= dt:             derate by 10dB
-        */
+       int8_t index = 0;
 
        now_msec = jiffies_to_msecs(jiffies);
-       dt = now_msec - ath_rc_priv->rssi_time;
-
-       if (dt >= 185)
-               rssi_reduce = 10;
-       else if (dt >= 25)
-               rssi_reduce = (u8)((dt - 25) >> 4);
-
-       /* Now reduce rssi_last by rssi_reduce */
-       if (rssi_last < rssi_reduce)
-               rssi_last = 0;
-       else
-               rssi_last -= rssi_reduce;
-
-       /*
-        * Now look up the rate in the rssi table and return it.
-        * If no rates match then we return 0 (lowest rate)
-        */
-
+       *is_probing = 0;
        best_thruput = 0;
        maxindex = ath_rc_priv->max_valid_rate-1;
-
        minindex = 0;
        best_rate = minindex;
 
@@ -700,7 +636,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
                 * 10-15 and we would be worse off then staying
                 * at the current rate.
                 */
-               per_thres = ath_rc_priv->state[rate].per;
+               per_thres = ath_rc_priv->per[rate];
                if (per_thres < 12)
                        per_thres = 12;
 
@@ -714,7 +650,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
        }
 
        rate = best_rate;
-       ath_rc_priv->rssi_last_lookup = rssi_last;
 
        /*
         * Must check the actual rate (ratekbps) to account for
@@ -741,10 +676,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
        if (rate > (ath_rc_priv->rate_table_size - 1))
                rate = ath_rc_priv->rate_table_size - 1;
 
-       ASSERT((rate_table->info[rate].valid &&
-               (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
-              (rate_table->info[rate].valid_single_stream &&
-               !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
+       if (rate_table->info[rate].valid &&
+           (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+               return rate;
+
+       if (rate_table->info[rate].valid_single_stream &&
+           !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG));
+               return rate;
+
+       /* This should not happen */
+       WARN_ON(1);
+
+       rate = ath_rc_priv->valid_rate_index[0];
 
        return rate;
 }
@@ -796,7 +739,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
         * just CTS.  Note that this is only done for OFDM/HT unicast frames.
         */
        if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) &&
-           !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
            (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
             WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
                rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
@@ -806,50 +748,37 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
        tx_info->control.rts_cts_rate_idx = cix;
 }
 
-static u8 ath_rc_rate_getidx(struct ath_softc *sc,
-                            struct ath_rate_priv *ath_rc_priv,
-                            const struct ath_rate_table *rate_table,
-                            u8 rix, u16 stepdown,
-                            u16 min_rate)
-{
-       u32 j;
-       u8 nextindex = 0;
-
-       if (min_rate) {
-               for (j = RATE_TABLE_SIZE; j > 0; j--) {
-                       if (ath_rc_get_nextlowervalid_txrate(rate_table,
-                                               ath_rc_priv, rix, &nextindex))
-                               rix = nextindex;
-                       else
-                               break;
-               }
-       } else {
-               for (j = stepdown; j > 0; j--) {
-                       if (ath_rc_get_nextlowervalid_txrate(rate_table,
-                                               ath_rc_priv, rix, &nextindex))
-                               rix = nextindex;
-                       else
-                               break;
-               }
-       }
-       return rix;
-}
-
-static void ath_rc_ratefind(struct ath_softc *sc,
-                           struct ath_rate_priv *ath_rc_priv,
-                           struct ieee80211_tx_rate_control *txrc)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+                        struct ieee80211_tx_rate_control *txrc)
 {
+       struct ath_softc *sc = priv;
+       struct ath_rate_priv *ath_rc_priv = priv_sta;
        const struct ath_rate_table *rate_table;
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *rates = tx_info->control.rates;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
-       u8 try_per_rate = 0, i = 0, rix, nrix;
+       u8 try_per_rate, i = 0, rix, nrix;
        int is_probe = 0;
 
+       if (rate_control_send_low(sta, priv_sta, txrc))
+               return;
+
+       /*
+        * For Multi Rate Retry we use a different number of
+        * retry attempt counts. This ends up looking like this:
+        *
+        * MRR[0] = 2
+        * MRR[1] = 2
+        * MRR[2] = 2
+        * MRR[3] = 4
+        *
+        */
+       try_per_rate = sc->hw->max_rate_tries;
+
        rate_table = sc->cur_rate_table;
-       rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe);
+       rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
        nrix = rix;
 
        if (is_probe) {
@@ -858,18 +787,15 @@ static void ath_rc_ratefind(struct ath_softc *sc,
                ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       1, nrix, 0);
 
-               try_per_rate = (ATH_11N_TXMAXTRY/4);
                /* Get the next tried/allowed rate. No RTS for the next series
                 * after the probe rate
                 */
-               nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
-                                         rate_table, nrix, 1, 0);
+               ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
                ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       try_per_rate, nrix, 0);
 
                tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
        } else {
-               try_per_rate = (ATH_11N_TXMAXTRY/4);
                /* Set the choosen rate. No RTS for first series entry. */
                ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       try_per_rate, nrix, 0);
@@ -877,18 +803,14 @@ static void ath_rc_ratefind(struct ath_softc *sc,
 
        /* Fill in the other rates for multirate retry */
        for ( ; i < 4; i++) {
-               u8 try_num;
-               u8 min_rate;
-
-               try_num = ((i + 1) == 4) ?
-                       ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ;
-               min_rate = (((i + 1) == 4) && 0);
+               /* Use twice the number of tries for the last MRR segment. */
+               if (i + 1 == 4)
+                       try_per_rate = 4;
 
-               nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
-                                         rate_table, nrix, 1, min_rate);
+               ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
                /* All other rates in the series have RTS enabled */
                ath_rc_rate_set_series(rate_table, &rates[i], txrc,
-                                      try_num, nrix, 1);
+                                      try_per_rate, nrix, 1);
        }
 
        /*
@@ -925,9 +847,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
         *
         * FIXME: Fix duration
         */
-       if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-           (ieee80211_has_morefrags(fc) ||
-            (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) {
+       if (ieee80211_has_morefrags(fc) ||
+           (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
                rates[1].count = rates[2].count = rates[3].count = 0;
                rates[1].idx = rates[2].idx = rates[3].idx = 0;
                rates[0].count = ATH_TXMAXTRY;
@@ -960,13 +881,13 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                100 * 9 / 10
        };
 
-       last_per = ath_rc_priv->state[tx_rate].per;
+       last_per = ath_rc_priv->per[tx_rate];
 
        if (xretries) {
                if (xretries == 1) {
-                       ath_rc_priv->state[tx_rate].per += 30;
-                       if (ath_rc_priv->state[tx_rate].per > 100)
-                               ath_rc_priv->state[tx_rate].per = 100;
+                       ath_rc_priv->per[tx_rate] += 30;
+                       if (ath_rc_priv->per[tx_rate] > 100)
+                               ath_rc_priv->per[tx_rate] = 100;
                } else {
                        /* xretries == 2 */
                        count = ARRAY_SIZE(nretry_to_per_lookup);
@@ -974,7 +895,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                                retries = count - 1;
 
                        /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
-                       ath_rc_priv->state[tx_rate].per =
+                       ath_rc_priv->per[tx_rate] =
                                (u8)(last_per - (last_per >> 3) + (100 >> 3));
                }
 
@@ -1010,18 +931,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                                n_frames = tx_info_priv->n_frames * (retries + 1);
                                cur_per = (100 * n_bad_frames / n_frames) >> 3;
                                new_per = (u8)(last_per - (last_per >> 3) + cur_per);
-                               ath_rc_priv->state[tx_rate].per = new_per;
+                               ath_rc_priv->per[tx_rate] = new_per;
                        }
                } else {
-                       ath_rc_priv->state[tx_rate].per =
+                       ath_rc_priv->per[tx_rate] =
                                (u8)(last_per - (last_per >> 3) +
                                     (nretry_to_per_lookup[retries] >> 3));
                }
 
-               ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
-               ath_rc_priv->rssi_last_prev  = ath_rc_priv->rssi_last;
-               ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
-               ath_rc_priv->rssi_time = now_msec;
 
                /*
                 * If we got at most one retry then increase the max rate if
@@ -1045,8 +962,8 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                                        ath_rc_priv->probe_rate;
                                probe_rate = ath_rc_priv->probe_rate;
 
-                               if (ath_rc_priv->state[probe_rate].per > 30)
-                                       ath_rc_priv->state[probe_rate].per = 20;
+                               if (ath_rc_priv->per[probe_rate] > 30)
+                                       ath_rc_priv->per[probe_rate] = 20;
 
                                ath_rc_priv->probe_rate = 0;
 
@@ -1065,18 +982,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                        /*
                         * Don't update anything.  We don't know if
                         * this was because of collisions or poor signal.
-                        *
-                        * Later: if rssi_ack is close to
-                        * ath_rc_priv->state[txRate].rssi_thres and we see lots
-                        * of retries, then we could increase
-                        * ath_rc_priv->state[txRate].rssi_thres.
                         */
                        ath_rc_priv->hw_maxretry_pktcnt = 0;
                } else {
-                       int32_t rssi_ackAvg;
-                       int8_t rssi_thres;
-                       int8_t rssi_ack_vmin;
-
                        /*
                         * It worked with no retries. First ignore bogus (small)
                         * rssi_ack values.
@@ -1086,43 +994,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
                                ath_rc_priv->hw_maxretry_pktcnt++;
                        }
 
-                       if (tx_info_priv->tx.ts_rssi <
-                           rate_table->info[tx_rate].rssi_ack_validmin)
-                               goto exit;
-
-                       /* Average the rssi */
-                       if (tx_rate != ath_rc_priv->rssi_sum_rate) {
-                               ath_rc_priv->rssi_sum_rate = tx_rate;
-                               ath_rc_priv->rssi_sum =
-                                       ath_rc_priv->rssi_sum_cnt = 0;
-                       }
-
-                       ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
-                       ath_rc_priv->rssi_sum_cnt++;
-
-                       if (ath_rc_priv->rssi_sum_cnt < 4)
-                               goto exit;
-
-                       rssi_ackAvg =
-                               (ath_rc_priv->rssi_sum + 2) / 4;
-                       rssi_thres =
-                               ath_rc_priv->state[tx_rate].rssi_thres;
-                       rssi_ack_vmin =
-                               rate_table->info[tx_rate].rssi_ack_validmin;
-
-                       ath_rc_priv->rssi_sum =
-                               ath_rc_priv->rssi_sum_cnt = 0;
-
-                       /* Now reduce the current rssi threshold */
-                       if ((rssi_ackAvg < rssi_thres + 2) &&
-                           (rssi_thres > rssi_ack_vmin)) {
-                               ath_rc_priv->state[tx_rate].rssi_thres--;
-                       }
-
-                       state_change = true;
                }
        }
-exit:
+
        return state_change;
 }
 
@@ -1134,11 +1008,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
                             struct ath_tx_info_priv *tx_info_priv,
                             int tx_rate, int xretries, int retries)
 {
-#define CHK_RSSI(rate)                                 \
-       ((ath_rc_priv->state[(rate)].rssi_thres +       \
-         rate_table->info[(rate)].rssi_ack_deltamin) > \
-        ath_rc_priv->state[(rate)+1].rssi_thres)
-
        u32 now_msec = jiffies_to_msecs(jiffies);
        int rate;
        u8 last_per;
@@ -1149,14 +1018,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
        if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
                return;
 
-       /* To compensate for some imbalance between ctrl and ext. channel */
-
-       if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
-               tx_info_priv->tx.ts_rssi =
-                       tx_info_priv->tx.ts_rssi < 3 ? 0 :
-                       tx_info_priv->tx.ts_rssi - 3;
-
-       last_per = ath_rc_priv->state[tx_rate].per;
+       last_per = ath_rc_priv->per[tx_rate];
 
        /* Update PER first */
        state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
@@ -1167,114 +1029,55 @@ static void ath_rc_update_ht(struct ath_softc *sc,
         * If this rate looks bad (high PER) then stop using it for
         * a while (except if we are probing).
         */
-       if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
+       if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
            rate_table->info[tx_rate].ratekbps <=
            rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
-               ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
-                                (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+               ath_rc_get_lower_rix(rate_table, ath_rc_priv,
+                                    (u8)tx_rate, &ath_rc_priv->rate_max_phy);
 
                /* Don't probe for a little while. */
                ath_rc_priv->probe_time = now_msec;
        }
 
-       if (state_change) {
-               /*
-                * Make sure the rates above this have higher rssi thresholds.
-                * (Note:  Monotonicity is kept within the OFDM rates and
-                *         within the CCK rates. However, no adjustment is
-                *         made to keep the rssi thresholds monotonically
-                *         increasing between the CCK and OFDM rates.)
-                */
-               for (rate = tx_rate; rate < size - 1; rate++) {
-                       if (rate_table->info[rate+1].phy !=
-                           rate_table->info[tx_rate].phy)
-                               break;
-
-                       if (CHK_RSSI(rate)) {
-                               ath_rc_priv->state[rate+1].rssi_thres =
-                                       ath_rc_priv->state[rate].rssi_thres +
-                                       rate_table->info[rate].rssi_ack_deltamin;
-                       }
-               }
-
-               /* Make sure the rates below this have lower rssi thresholds. */
-               for (rate = tx_rate - 1; rate >= 0; rate--) {
-                       if (rate_table->info[rate].phy !=
-                           rate_table->info[tx_rate].phy)
-                               break;
-
-                       if (CHK_RSSI(rate)) {
-                               if (ath_rc_priv->state[rate+1].rssi_thres <
-                                   rate_table->info[rate].rssi_ack_deltamin)
-                                       ath_rc_priv->state[rate].rssi_thres = 0;
-                               else {
-                                       ath_rc_priv->state[rate].rssi_thres =
-                                       ath_rc_priv->state[rate+1].rssi_thres -
-                                       rate_table->info[rate].rssi_ack_deltamin;
-                               }
-
-                               if (ath_rc_priv->state[rate].rssi_thres <
-                                   rate_table->info[rate].rssi_ack_validmin) {
-                                       ath_rc_priv->state[rate].rssi_thres =
-                                       rate_table->info[rate].rssi_ack_validmin;
-                               }
-                       }
-               }
-       }
-
        /* Make sure the rates below this have lower PER */
        /* Monotonicity is kept only for rates below the current rate. */
-       if (ath_rc_priv->state[tx_rate].per < last_per) {
+       if (ath_rc_priv->per[tx_rate] < last_per) {
                for (rate = tx_rate - 1; rate >= 0; rate--) {
                        if (rate_table->info[rate].phy !=
                            rate_table->info[tx_rate].phy)
                                break;
 
-                       if (ath_rc_priv->state[rate].per >
-                           ath_rc_priv->state[rate+1].per) {
-                               ath_rc_priv->state[rate].per =
-                                       ath_rc_priv->state[rate+1].per;
+                       if (ath_rc_priv->per[rate] >
+                           ath_rc_priv->per[rate+1]) {
+                               ath_rc_priv->per[rate] =
+                                       ath_rc_priv->per[rate+1];
                        }
                }
        }
 
        /* Maintain monotonicity for rates above the current rate */
        for (rate = tx_rate; rate < size - 1; rate++) {
-               if (ath_rc_priv->state[rate+1].per <
-                   ath_rc_priv->state[rate].per)
-                       ath_rc_priv->state[rate+1].per =
-                               ath_rc_priv->state[rate].per;
-       }
-
-       /* Every so often, we reduce the thresholds and
-        * PER (different for CCK and OFDM). */
-       if (now_msec - ath_rc_priv->rssi_down_time >=
-           rate_table->rssi_reduce_interval) {
-
-               for (rate = 0; rate < size; rate++) {
-                       if (ath_rc_priv->state[rate].rssi_thres >
-                           rate_table->info[rate].rssi_ack_validmin)
-                               ath_rc_priv->state[rate].rssi_thres -= 1;
-               }
-               ath_rc_priv->rssi_down_time = now_msec;
+               if (ath_rc_priv->per[rate+1] <
+                   ath_rc_priv->per[rate])
+                       ath_rc_priv->per[rate+1] =
+                               ath_rc_priv->per[rate];
        }
 
        /* Every so often, we reduce the thresholds
         * and PER (different for CCK and OFDM). */
        if (now_msec - ath_rc_priv->per_down_time >=
-           rate_table->rssi_reduce_interval) {
+           rate_table->probe_interval) {
                for (rate = 0; rate < size; rate++) {
-                       ath_rc_priv->state[rate].per =
-                               7 * ath_rc_priv->state[rate].per / 8;
+                       ath_rc_priv->per[rate] =
+                               7 * ath_rc_priv->per[rate] / 8;
                }
 
                ath_rc_priv->per_down_time = now_msec;
        }
 
        ath_debug_stat_retries(sc, tx_rate, xretries, retries,
-                              ath_rc_priv->state[tx_rate].per);
+                              ath_rc_priv->per[tx_rate]);
 
-#undef CHK_RSSI
 }
 
 static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
@@ -1410,9 +1213,7 @@ static void ath_rc_init(struct ath_softc *sc,
 
        /* Initialize thresholds according to the global rate table */
        for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
-               ath_rc_priv->state[i].rssi_thres =
-                       rate_table->info[i].rssi_ack_validmin;
-               ath_rc_priv->state[i].per = 0;
+               ath_rc_priv->per[i] = 0;
        }
 
        /* Determine the valid rates */
@@ -1521,7 +1322,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
        /*
         * If underrun error is seen assume it as an excessive retry only
         * if prefetch trigger level have reached the max (0x3f for 5416)
-        * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+        * Adjust the long retry as if the frame was tried hw->max_rate_tries
         * times. This affects how ratectrl updates PER for the failed rate.
         */
        if (tx_info_priv->tx.ts_flags &
@@ -1536,7 +1337,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                tx_status = 1;
 
        ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
-                        (is_underrun) ? ATH_11N_TXMAXTRY :
+                        (is_underrun) ? sc->hw->max_rate_tries :
                         tx_info_priv->tx.ts_longretry);
 
        /* Check if aggregation has to be enabled for this tid */
@@ -1560,31 +1361,6 @@ exit:
        kfree(tx_info_priv);
 }
 
-static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
-                        struct ieee80211_tx_rate_control *txrc)
-{
-       struct ieee80211_supported_band *sband = txrc->sband;
-       struct sk_buff *skb = txrc->skb;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_softc *sc = priv;
-       struct ath_rate_priv *ath_rc_priv = priv_sta;
-       __le16 fc = hdr->frame_control;
-
-       /* lowest rate for management and NO_ACK frames */
-       if (!ieee80211_is_data(fc) ||
-           tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) {
-               tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
-               tx_info->control.rates[0].count =
-                       (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
-                               1 : ATH_MGT_TXMAXTRY;
-               return;
-       }
-
-       /* Find tx rate for unicast frames */
-       ath_rc_ratefind(sc, ath_rc_priv, txrc);
-}
-
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
                           struct ieee80211_sta *sta, void *priv_sta)
 {
@@ -1697,7 +1473,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
                return NULL;
        }
 
-       rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
        rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
 
        return rate_priv;
@@ -1725,8 +1500,6 @@ static struct rate_control_ops ath_rate_ops = {
 
 void ath_rate_attach(struct ath_softc *sc)
 {
-       sc->hw_rate_table[ATH9K_MODE_11B] =
-               &ar5416_11b_ratetable;
        sc->hw_rate_table[ATH9K_MODE_11A] =
                &ar5416_11a_ratetable;
        sc->hw_rate_table[ATH9K_MODE_11G] =
index e3abd76..fa21a62 100644 (file)
@@ -112,8 +112,6 @@ struct ath_rate_table {
                u8 short_preamble;
                u8 dot11rate;
                u8 ctrl_rate;
-               int8_t rssi_ack_validmin;
-               int8_t rssi_ack_deltamin;
                u8 base_index;
                u8 cw40index;
                u8 sgi_index;
@@ -121,15 +119,9 @@ struct ath_rate_table {
                u32 max_4ms_framelen;
        } info[RATE_TABLE_SIZE];
        u32 probe_interval;
-       u32 rssi_reduce_interval;
        u8 initial_ratemax;
 };
 
-struct ath_tx_ratectrl_state {
-       int8_t rssi_thres;      /* required rssi for this rate (dB) */
-       u8 per;                 /* recent estimate of packet error rate (%) */
-};
-
 struct ath_rateset {
        u8 rs_nrates;
        u8 rs_rates[ATH_RATE_MAX];
@@ -138,22 +130,14 @@ struct ath_rateset {
 /**
  * struct ath_rate_priv - Rate Control priv data
  * @state: RC state
- * @rssi_last: last ACK rssi
- * @rssi_last_lookup: last ACK rssi used for lookup
- * @rssi_last_prev: previous last ACK rssi
- * @rssi_last_prev2: 2nd previous last ACK rssi
- * @rssi_sum_cnt: count of rssi_sum for averaging
- * @rssi_sum_rate: rate that we are averaging
- * @rssi_sum: running sum of rssi for averaging
  * @probe_rate: rate we are probing at
- * @rssi_time: msec timestamp for last ack rssi
- * @rssi_down_time: msec timestamp for last down step
  * @probe_time: msec timestamp for last probe
  * @hw_maxretry_pktcnt: num of packets since we got HW max retry error
  * @max_valid_rate: maximum number of valid rate
  * @per_down_time: msec timestamp for last PER down step
  * @valid_phy_ratecnt: valid rate count
  * @rate_max_phy: phy index for the max rate
+ * @per: PER for every valid rate in %
  * @probe_interval: interval for ratectrl to probe for other rates
  * @prev_data_rix: rate idx of last data frame
  * @ht_cap: HT capabilities
@@ -161,13 +145,6 @@ struct ath_rateset {
  * @neg_ht_rates: Negotiated HT rates
  */
 struct ath_rate_priv {
-       int8_t rssi_last;
-       int8_t rssi_last_lookup;
-       int8_t rssi_last_prev;
-       int8_t rssi_last_prev2;
-       int32_t rssi_sum_cnt;
-       int32_t rssi_sum_rate;
-       int32_t rssi_sum;
        u8 rate_table_size;
        u8 probe_rate;
        u8 hw_maxretry_pktcnt;
@@ -177,14 +154,12 @@ struct ath_rate_priv {
        u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
        u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
        u8 rate_max_phy;
-       u32 rssi_time;
-       u32 rssi_down_time;
+       u8 per[RATE_TABLE_SIZE];
        u32 probe_time;
        u32 per_down_time;
        u32 probe_interval;
        u32 prev_data_rix;
        u32 tx_triglevel_max;
-       struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
        struct ath_rateset neg_rates;
        struct ath_rateset neg_ht_rates;
        struct ath_rate_softc *asc;
index b3da81d..61edfab 100644 (file)
@@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
        u8 ratecode;
        __le16 fc;
        struct ieee80211_hw *hw;
+       struct ieee80211_sta *sta;
+       struct ath_node *an;
+       int last_rssi = ATH_RSSI_DUMMY_MARKER;
+
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
@@ -229,11 +233,30 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
                }
        }
 
+       rcu_read_lock();
+       sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+       if (sta) {
+               an = (struct ath_node *) sta->drv_priv;
+               if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
+                  !ds->ds_rxstat.rs_moreaggr)
+                       ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+               last_rssi = an->last_rssi;
+       }
+       rcu_read_unlock();
+
+       if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+               ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
+                                       ATH_RSSI_EP_MULTIPLIER);
+       if (ds->ds_rxstat.rs_rssi < 0)
+               ds->ds_rxstat.rs_rssi = 0;
+       else if (ds->ds_rxstat.rs_rssi > 127)
+               ds->ds_rxstat.rs_rssi = 127;
+
        rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
        rx_status->band = hw->conf.channel->band;
        rx_status->freq = hw->conf.channel->center_freq;
        rx_status->noise = sc->ani.noise_floor;
-       rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+       rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
        rx_status->antenna = ds->ds_rxstat.rs_antenna;
 
        /*
index 5260524..8302aeb 100644 (file)
 
 #define AR_D_GBL_IFS_SIFS         0x1030
 #define AR_D_GBL_IFS_SIFS_M       0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
 #define AR_D_GBL_IFS_SIFS_RESV0   0xFFFFFFFF
 
 #define AR_D_TXBLK_BASE            0x1038
 #define AR_D_GBL_IFS_SLOT         0x1070
 #define AR_D_GBL_IFS_SLOT_M       0x0000FFFF
 #define AR_D_GBL_IFS_SLOT_RESV0   0xFFFF0000
+#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR   0x00000420
 
 #define AR_D_GBL_IFS_EIFS         0x10b0
 #define AR_D_GBL_IFS_EIFS_M       0x0000FFFF
 #define AR_D_GBL_IFS_EIFS_RESV0   0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR   0x0000A5EB
 
 #define AR_D_GBL_IFS_MISC        0x10f0
 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL        0x00000007
 #define AR_SREV_REVISION_9285_10              0
 #define AR_SREV_REVISION_9285_11              1
 #define AR_SREV_REVISION_9285_12              2
+#define AR_SREV_VERSION_9287                  0x180
+#define AR_SREV_REVISION_9287_10              0
+#define AR_SREV_REVISION_9287_11              1
 
 #define AR_SREV_5416(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
         (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
                               AR_SREV_REVISION_9285_12)))
 
+#define AR_SREV_9287(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10_OR_LATER(_ah) \
+       (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
+#define AR_SREV_9287_11(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
+#define AR_SREV_9287_11_OR_LATER(_ah) \
+       (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
+
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
 #define AR_RAD2133_SREV_MAJOR                 0xd0
 #define AR_AHB_PAGE_SIZE_1K                   0x00000000
 #define AR_AHB_PAGE_SIZE_2K                   0x00000008
 #define AR_AHB_PAGE_SIZE_4K                   0x00000010
+#define AR_AHB_CUSTOM_BURST_EN                0x000000C0
+#define AR_AHB_CUSTOM_BURST_EN_S              6
+#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL    3
 
 #define AR_INTR_RTC_IRQ                       0x00000001
 #define AR_INTR_MAC_IRQ                       0x00000002
@@ -885,6 +909,7 @@ enum {
 #define AR_NUM_GPIO                              14
 #define AR928X_NUM_GPIO                          10
 #define AR9285_NUM_GPIO                          12
+#define AR9287_NUM_GPIO                          11
 
 #define AR_GPIO_IN_OUT                           0x4048
 #define AR_GPIO_IN_VAL                           0x0FFFC000
@@ -893,6 +918,8 @@ enum {
 #define AR928X_GPIO_IN_VAL_S                     10
 #define AR9285_GPIO_IN_VAL                       0x00FFF000
 #define AR9285_GPIO_IN_VAL_S                     12
+#define AR9287_GPIO_IN_VAL                       0x003FF800
+#define AR9287_GPIO_IN_VAL_S                     11
 
 #define AR_GPIO_OE_OUT                           0x404c
 #define AR_GPIO_OE_OUT_DRV                       0x3
@@ -1154,6 +1181,33 @@ enum {
 #define AR9285_AN_TOP4           0x7870
 #define AR9285_AN_TOP4_DEFAULT   0x10142c00
 
+#define AR9287_AN_RF2G3_CH0             0x7808
+#define AR9287_AN_RF2G3_CH1             0x785c
+#define AR9287_AN_RF2G3_DB1             0xE0000000
+#define AR9287_AN_RF2G3_DB1_S           29
+#define AR9287_AN_RF2G3_DB2             0x1C000000
+#define AR9287_AN_RF2G3_DB2_S           26
+#define AR9287_AN_RF2G3_OB_CCK          0x03800000
+#define AR9287_AN_RF2G3_OB_CCK_S        23
+#define AR9287_AN_RF2G3_OB_PSK          0x00700000
+#define AR9287_AN_RF2G3_OB_PSK_S        20
+#define AR9287_AN_RF2G3_OB_QAM          0x000E0000
+#define AR9287_AN_RF2G3_OB_QAM_S        17
+#define AR9287_AN_RF2G3_OB_PAL_OFF      0x0001C000
+#define AR9287_AN_RF2G3_OB_PAL_OFF_S    14
+
+#define AR9287_AN_TXPC0                 0x7898
+#define AR9287_AN_TXPC0_TXPCMODE        0x0000C000
+#define AR9287_AN_TXPC0_TXPCMODE_S      14
+#define AR9287_AN_TXPC0_TXPCMODE_NORMAL    0
+#define AR9287_AN_TXPC0_TXPCMODE_TEST      1
+#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
+#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST   3
+
+#define AR9287_AN_TOP2                  0x78b4
+#define AR9287_AN_TOP2_XPABIAS_LVL      0xC0000000
+#define AR9287_AN_TOP2_XPABIAS_LVL_S    30
+
 #define AR_STA_ID0                 0x8000
 #define AR_STA_ID1                 0x8004
 #define AR_STA_ID1_SADH_MASK       0x0000FFFF
@@ -1188,6 +1242,7 @@ enum {
 #define AR_TIME_OUT_ACK_S    0
 #define AR_TIME_OUT_CTS      0x3FFF0000
 #define AR_TIME_OUT_CTS_S    16
+#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR    0x16001D56
 
 #define AR_RSSI_THR          0x8018
 #define AR_RSSI_THR_MASK     0x000000FF
@@ -1203,6 +1258,7 @@ enum {
 #define AR_USEC_TX_LAT_S     14
 #define AR_USEC_RX_LAT       0x1F800000
 #define AR_USEC_RX_LAT_S     23
+#define AR_USEC_ASYNC_FIFO_DUR    0x12e00074
 
 #define AR_RESET_TSF        0x8020
 #define AR_RESET_TSF_ONCE   0x01000000
@@ -1468,6 +1524,10 @@ enum {
 #define AR_SLP_MIB_CLEAR   0x00000001
 #define AR_SLP_MIB_PENDING 0x00000002
 
+#define AR_MAC_PCU_LOGIC_ANALYZER               0x8264
+#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768   0x20000000
+
+
 #define AR_2040_MODE                0x8318
 #define AR_2040_JOINED_RX_CLEAR 0x00000001
 
@@ -1485,6 +1545,39 @@ enum {
 #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE           0x00000002
 #define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT   0x00000004
 
+#define AR_PCU_MISC_MODE2_RESERVED                     0x00000038
+#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE     0x00000040
+#define AR_PCU_MISC_MODE2_CFP_IGNORE                   0x00000080
+#define AR_PCU_MISC_MODE2_MGMT_QOS                     0x0000FF00
+#define AR_PCU_MISC_MODE2_MGMT_QOS_S                   8
+#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
+#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP                0x00020000
+#define AR_PCU_MISC_MODE2_HWWAR1                       0x00100000
+#define AR_PCU_MISC_MODE2_HWWAR2                       0x02000000
+#define AR_PCU_MISC_MODE2_RESERVED2                    0xFFFE0000
+
+#define AR_MAC_PCU_ASYNC_FIFO_REG3                     0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL        0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET          0x80000000
+
+
+#define AR_AES_MUTE_MASK0       0x805c
+#define AR_AES_MUTE_MASK0_FC    0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS   0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1              0x8060
+#define AR_AES_MUTE_MASK1_SEQ          0x0000FFFF
+#define AR_AES_MUTE_MASK1_SEQ_S        0
+#define AR_AES_MUTE_MASK1_FC_MGMT      0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S    16
+
+#define AR_RATE_DURATION_0      0x8700
+#define AR_RATE_DURATION_31     0x87CC
+#define AR_RATE_DURATION_32     0x8780
+#define AR_RATE_DURATION(_n)    (AR_RATE_DURATION_0 + ((_n)<<2))
+
+
 #define AR_KEYTABLE_0           0x8800
 #define AR_KEYTABLE(_n)         (AR_KEYTABLE_0 + ((_n)*32))
 #define AR_KEY_CACHE_SIZE       128
index 1ff429b..e1d419e 100644 (file)
@@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
                queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
                                   sc->wiphy_scheduler_int);
 }
+
+/* caller must hold wiphy_lock */
+bool ath9k_all_wiphys_idle(struct ath_softc *sc)
+{
+       unsigned int i;
+       if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+               return false;
+       }
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (!aphy)
+                       continue;
+               if (aphy->state != ATH_WIPHY_INACTIVE)
+                       return false;
+       }
+       return true;
+}
index 5de9878..4ff155e 100644 (file)
@@ -242,7 +242,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
                spin_unlock_bh(&sc->tx.txbuflock);
                return NULL;
        }
-       ASSERT(!list_empty((&sc->tx.txbuf)));
        tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
        list_del(&tbf->list);
        spin_unlock_bh(&sc->tx.txbuflock);
@@ -383,8 +382,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                struct ath_buf *tbf;
 
                                tbf = ath_clone_txbuf(sc, bf_last);
-                               if (!tbf)
+                               /*
+                                * Update tx baw and complete the frame with
+                                * failed status if we run out of tx buf
+                                */
+                               if (!tbf) {
+                                       spin_lock_bh(&txq->axq_lock);
+                                       ath_tx_update_baw(sc, tid,
+                                                         bf->bf_seqno);
+                                       spin_unlock_bh(&txq->axq_lock);
+
+                                       bf->bf_state.bf_type |= BUF_XRETRY;
+                                       ath_tx_rc_status(bf, ds, nbad,
+                                                        0, false);
+                                       ath_tx_complete_buf(sc, bf, &bf_head,
+                                                           0, 0);
                                        break;
+                               }
+
                                ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
                                list_add_tail(&tbf->list, &bf_head);
                        } else {
@@ -857,6 +872,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
                txq->axq_aggr_depth = 0;
                txq->axq_totalqueued = 0;
                txq->axq_linkbuf = NULL;
+               txq->axq_tx_inprogress = false;
                sc->tx.txqsetup |= 1<<qnum;
        }
        return &sc->tx.txq[qnum];
@@ -1023,6 +1039,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
                        ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
        }
 
+       spin_lock_bh(&txq->axq_lock);
+       txq->axq_tx_inprogress = false;
+       spin_unlock_bh(&txq->axq_lock);
+
        /* flush any pending frames if aggregation is enabled */
        if (sc->sc_flags & SC_OP_TXAGGR) {
                if (!retry_tx) {
@@ -1103,8 +1123,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
                if (tid->paused)
                        continue;
 
-               if ((txq->axq_depth % 2) == 0)
-                       ath_tx_sched_aggr(sc, txq, tid);
+               ath_tx_sched_aggr(sc, txq, tid);
 
                /*
                 * add tid to round-robin queue if more frames
@@ -1947,19 +1966,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                if (bf->bf_stale) {
                        bf_held = bf;
                        if (list_is_last(&bf_held->list, &txq->axq_q)) {
-                               txq->axq_link = NULL;
-                               txq->axq_linkbuf = NULL;
                                spin_unlock_bh(&txq->axq_lock);
-
-                               /*
-                                * The holding descriptor is the last
-                                * descriptor in queue. It's safe to remove
-                                * the last holding descriptor in BH context.
-                                */
-                               spin_lock_bh(&sc->tx.txbuflock);
-                               list_move_tail(&bf_held->list, &sc->tx.txbuf);
-                               spin_unlock_bh(&sc->tx.txbuflock);
-
                                break;
                        } else {
                                bf = list_entry(bf_held->list.next,
@@ -1996,6 +2003,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                        txq->axq_aggr_depth--;
 
                txok = (ds->ds_txstat.ts_status == 0);
+               txq->axq_tx_inprogress = false;
                spin_unlock_bh(&txq->axq_lock);
 
                if (bf_held) {
@@ -2029,6 +2037,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
        }
 }
 
+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                       tx_complete_work.work);
+       struct ath_txq *txq;
+       int i;
+       bool needreset = false;
+
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i)) {
+                       txq = &sc->tx.txq[i];
+                       spin_lock_bh(&txq->axq_lock);
+                       if (txq->axq_depth) {
+                               if (txq->axq_tx_inprogress) {
+                                       needreset = true;
+                                       spin_unlock_bh(&txq->axq_lock);
+                                       break;
+                               } else {
+                                       txq->axq_tx_inprogress = true;
+                               }
+                       }
+                       spin_unlock_bh(&txq->axq_lock);
+               }
+
+       if (needreset) {
+               DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+               ath_reset(sc, false);
+       }
+
+       queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+                       msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+
 
 void ath_tx_tasklet(struct ath_softc *sc)
 {
@@ -2069,6 +2111,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
                goto err;
        }
 
+       INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+
 err:
        if (error != 0)
                ath_tx_cleanup(sc);
index e71c8d9..3f4360a 100644 (file)
@@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
 static void b43_dump_keymemory(struct b43_wldev *dev)
 {
        unsigned int i, index, offset;
-       DECLARE_MAC_BUF(macbuf);
        u8 mac[ETH_ALEN];
        u16 algo;
        u32 rcmta0;
@@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
                                                ((index - 4) * 2) + 1);
                        *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
                        *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
-                       printk("   MAC: %s",
-                              print_mac(macbuf, mac));
+                       printk("   MAC: %pM", mac);
                } else
                        printk("   DEFAULT KEY");
                printk("\n");
index 6337402..ad8eab4 100644 (file)
@@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link)
         * irq structure is initialized.
         */
        if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-               link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+               link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING |
+                                      IRQ_HANDLE_PRESENT;
                link->irq.IRQInfo1 = IRQ_LEVEL_ID;
                link->irq.Handler = prism2_interrupt;
                link->irq.Instance = dev;
index d726b3c..2dc1cdb 100644 (file)
@@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work)
        struct ipw_priv *priv =
                container_of(work, struct ipw_priv, qos_activate);
 
-       if (priv == NULL)
-               return;
-
        mutex_lock(&priv->mutex);
 
        if (priv->status & STATUS_ASSOCIATED)
index 7da52f1..a899be9 100644 (file)
@@ -46,7 +46,7 @@
 #include "iwl-5000-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 3
 
 /* Lowest firmware API version supported */
 #define IWL1000_UCODE_API_MIN 1
index 73f93a0..b569c6f 100644 (file)
@@ -232,9 +232,8 @@ struct iwl3945_eeprom {
 #define PCI_CFG_REV_ID_BIT_BASIC_SKU                (0x40)     /* bit 6    */
 #define PCI_CFG_REV_ID_BIT_RTP                      (0x80)     /* bit 7    */
 
-#define TFD_QUEUE_MIN           0
-#define TFD_QUEUE_MAX           5      /* 4 DATA + 1 CMD */
-
+/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
+#define IWL39_NUM_QUEUES        5
 #define IWL_NUM_SCAN_RATES         (2)
 
 #define IWL_DEFAULT_TX_RETRY  15
@@ -280,8 +279,6 @@ struct iwl3945_eeprom {
 /* Size of uCode instruction memory in bootstrap state machine */
 #define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE
 
-#define IWL39_MAX_NUM_QUEUES   8
-
 static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
 {
        return (addr >= IWL39_RTC_DATA_LOWER_BOUND) &&
index 5eb538d..a16bd41 100644 (file)
@@ -673,33 +673,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
        s8 scale_action = 0;
        unsigned long flags;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       u16 fc;
-       u16 rate_mask = 0;
+       u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
        s8 max_rate_idx = -1;
        struct iwl_priv *priv = (struct iwl_priv *)priv_r;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        IWL_DEBUG_RATE(priv, "enter\n");
 
-       if (sta)
-               rate_mask = sta->supp_rates[sband->band];
-
-       /* Send management frames and NO_ACK data using lowest rate. */
-       fc = le16_to_cpu(hdr->frame_control);
-       if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           info->flags & IEEE80211_TX_CTL_NO_ACK ||
-           !sta || !priv_sta) {
-               IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n");
-               if (!rate_mask)
-                       info->control.rates[0].idx =
-                                       rate_lowest_index(sband, NULL);
-               else
-                       info->control.rates[0].idx =
-                                       rate_lowest_index(sband, sta);
-               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
-                       info->control.rates[0].count = 1;
+       if (rate_control_send_low(sta, priv_sta, txrc))
                return;
-       }
+
+       rate_mask = sta->supp_rates[sband->band];
 
        /* get user max rate if set */
        max_rate_idx = txrc->max_rate_idx;
index b0246db..8ee403c 100644 (file)
@@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
                }
        }
        if (print_dump)
-               iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
+               iwl_print_hex_dump(IWL_DL_RX, data, length);
 }
 
 static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
                      struct iwl_rx_packet *pkt,
                      struct ieee80211_hdr *header, int group100)
 {
-       if (priv->debug_level & IWL_DL_RX)
+       if (iwl_debug_level & IWL_DL_RX)
                _iwl3945_dbg_report_frame(priv, pkt, header, group100);
 }
 
@@ -963,7 +963,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
                goto error;
 
        /* Tx queue(s) */
-       for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
                slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
                                TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@@ -1140,7 +1140,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
        int txq_id;
 
        /* Tx queues */
-       for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++)
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
                if (txq_id == IWL_CMD_QUEUE_NUM)
                        iwl_cmd_queue_free(priv);
                else
@@ -1156,7 +1156,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
        iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
 
        /* reset TFD queues */
-       for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
                iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
                iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
                                FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
@@ -2552,7 +2552,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        }
 
        /* Assign number of Usable TX queues */
-       priv->hw_params.max_txq_num = TFD_QUEUE_MAX;
+       priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
 
        priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
        priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
@@ -2786,11 +2786,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
        return 0;
 }
 
+#define IWL3945_UCODE_GET(item)                                                \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+                                   u32 api_ver)                        \
+{                                                                      \
+       return le32_to_cpu(ucode->u.v1.item);                           \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+       return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
+                                  u32 api_ver)
+{
+       return 0;
+}
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
+                                 u32 api_ver)
+{
+       return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
 static struct iwl_hcmd_ops iwl3945_hcmd = {
        .rxon_assoc = iwl3945_send_rxon_assoc,
        .commit_rxon = iwl3945_commit_rxon,
 };
 
+static struct iwl_ucode_ops iwl3945_ucode = {
+       .get_header_size = iwl3945_ucode_get_header_size,
+       .get_build = iwl3945_ucode_get_build,
+       .get_inst_size = iwl3945_ucode_get_inst_size,
+       .get_data_size = iwl3945_ucode_get_data_size,
+       .get_init_size = iwl3945_ucode_get_init_size,
+       .get_init_data_size = iwl3945_ucode_get_init_data_size,
+       .get_boot_size = iwl3945_ucode_get_boot_size,
+       .get_data = iwl3945_ucode_get_data,
+};
+
 static struct iwl_lib_ops iwl3945_lib = {
        .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2831,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
 };
 
 static struct iwl_ops iwl3945_ops = {
+       .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
        .utils = &iwl3945_hcmd_utils,
index fbb3a57..f2ffc48 100644 (file)
@@ -111,9 +111,6 @@ enum iwl3945_antenna {
 #define IWL_TX_FIFO_HCCA_2     6
 #define IWL_TX_FIFO_NONE       7
 
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES     4
-
 #define IEEE80211_DATA_LEN              2304
 #define IEEE80211_4ADDR_LEN             30
 #define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
index edbb0bf..c30a1b9 100644 (file)
@@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
 
        IWL_DEBUG_INFO(priv, "Begin load bsm\n");
 
-       priv->ucode_type = UCODE_RT;
+       priv->ucode_type = UCODE_INIT;
 
        /* make sure bootstrap program is no larger than BSM's SRAM size */
        if (len > IWL49_MAX_BSM_SIZE)
@@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
 */
 static void iwl4965_init_alive_start(struct iwl_priv *priv)
 {
+       int ret;
+
        /* Check alive response for "valid" sign from uCode */
        if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
                /* We had an error bringing up the hardware, so take it
@@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
                IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
                goto restart;
        }
+       priv->ucode_type = UCODE_RT;
+       if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+               IWL_WARN(priv, "Runtime uCode already alive? "
+                       "Waiting for alive anyway\n");
+               clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+       }
+       ret = wait_event_interruptible_timeout(
+                       priv->wait_command_queue,
+                       test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
+                       UCODE_ALIVE_TIMEOUT);
+       if (!ret) {
+               /* FIXME: if STATUS_RT_UCODE_ALIVE timeout
+                * go back to restart the download Init uCode again
+                * this might cause to trap in the restart loop
+                */
+               priv->ucode_type = UCODE_NONE;
+               if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+                       IWL_ERR(priv, "Runtime timeout after %dms\n",
+                               jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+                       goto restart;
+               }
+       }
        return;
 
 restart:
@@ -2221,12 +2245,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
        cancel_work_sync(&priv->txpower_work);
 }
 
+#define IWL4965_UCODE_GET(item)                                                \
+static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+                                   u32 api_ver)                        \
+{                                                                      \
+       return le32_to_cpu(ucode->u.v1.item);                           \
+}
+
+static u32 iwl4965_ucode_get_header_size(u32 api_ver)
+{
+       return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
+                                  u32 api_ver)
+{
+       return 0;
+}
+static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
+                                 u32 api_ver)
+{
+       return (u8 *) ucode->u.v1.data;
+}
+
+IWL4965_UCODE_GET(inst_size);
+IWL4965_UCODE_GET(data_size);
+IWL4965_UCODE_GET(init_size);
+IWL4965_UCODE_GET(init_data_size);
+IWL4965_UCODE_GET(boot_size);
+
 static struct iwl_hcmd_ops iwl4965_hcmd = {
        .rxon_assoc = iwl4965_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
        .set_rxon_chain = iwl_set_rxon_chain,
 };
 
+static struct iwl_ucode_ops iwl4965_ucode = {
+       .get_header_size = iwl4965_ucode_get_header_size,
+       .get_build = iwl4965_ucode_get_build,
+       .get_inst_size = iwl4965_ucode_get_inst_size,
+       .get_data_size = iwl4965_ucode_get_data_size,
+       .get_init_size = iwl4965_ucode_get_init_size,
+       .get_init_data_size = iwl4965_ucode_get_init_data_size,
+       .get_boot_size = iwl4965_ucode_get_boot_size,
+       .get_data = iwl4965_ucode_get_data,
+};
 static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
        .get_hcmd_size = iwl4965_get_hcmd_size,
        .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2287,6 +2349,7 @@ static struct iwl_lib_ops iwl4965_lib = {
 };
 
 static struct iwl_ops iwl4965_ops = {
+       .ucode = &iwl4965_ucode,
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
        .utils = &iwl4965_hcmd_utils,
@@ -2313,8 +2376,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
 module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
 MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
 module_param_named(
        disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
index 85e8bac..702db07 100644 (file)
@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
                                APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
                                ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
 
+       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
+               /* Setting digital SVR for 1000 card to 1.32V */
+               iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+                                       APMG_SVR_DIGITAL_VOLTAGE_1_32,
+                                       ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+       }
+
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
@@ -1449,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
        return max_rssi - agc - IWL49_RSSI_OFFSET;
 }
 
+#define IWL5000_UCODE_GET(item)                                                \
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+                                   u32 api_ver)                        \
+{                                                                      \
+       if (api_ver <= 2)                                               \
+               return le32_to_cpu(ucode->u.v1.item);                   \
+       return le32_to_cpu(ucode->u.v2.item);                           \
+}
+
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
+{
+       if (api_ver <= 2)
+               return UCODE_HEADER_SIZE(1);
+       return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
+                                  u32 api_ver)
+{
+       if (api_ver <= 2)
+               return 0;
+       return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
+                                 u32 api_ver)
+{
+       if (api_ver <= 2)
+               return (u8 *) ucode->u.v1.data;
+       return (u8 *) ucode->u.v2.data;
+}
+
+IWL5000_UCODE_GET(inst_size);
+IWL5000_UCODE_GET(data_size);
+IWL5000_UCODE_GET(init_size);
+IWL5000_UCODE_GET(init_data_size);
+IWL5000_UCODE_GET(boot_size);
+
 struct iwl_hcmd_ops iwl5000_hcmd = {
        .rxon_assoc = iwl5000_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
@@ -1464,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
        .calc_rssi = iwl5000_calc_rssi,
 };
 
+struct iwl_ucode_ops iwl5000_ucode = {
+       .get_header_size = iwl5000_ucode_get_header_size,
+       .get_build = iwl5000_ucode_get_build,
+       .get_inst_size = iwl5000_ucode_get_inst_size,
+       .get_data_size = iwl5000_ucode_get_data_size,
+       .get_init_size = iwl5000_ucode_get_init_size,
+       .get_init_data_size = iwl5000_ucode_get_init_data_size,
+       .get_boot_size = iwl5000_ucode_get_boot_size,
+       .get_data = iwl5000_ucode_get_data,
+};
+
 struct iwl_lib_ops iwl5000_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
        .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1565,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = {
 };
 
 struct iwl_ops iwl5000_ops = {
+       .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl5000_hcmd_utils,
 };
 
 static struct iwl_ops iwl5150_ops = {
+       .ucode = &iwl5000_ucode,
        .lib = &iwl5150_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl5000_hcmd_utils,
@@ -1687,8 +1745,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
 module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
 MODULE_PARM_DESC(swcrypto50,
                  "using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug50, "50XX debug output mask");
 module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
 MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
 module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
index bd438d8..26c5d4a 100644 (file)
@@ -46,8 +46,8 @@
 #include "iwl-5000-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 2
-#define IWL6050_UCODE_API_MAX 2
+#define IWL6000_UCODE_API_MAX 3
+#define IWL6050_UCODE_API_MAX 3
 
 /* Lowest firmware API version supported */
 #define IWL6000_UCODE_API_MIN 1
@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
 };
 
 static struct iwl_ops iwl6000_ops = {
+       .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl6000_hcmd_utils,
index ff20e50..6328041 100644 (file)
@@ -2466,7 +2466,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = priv_sta;
        int rate_idx;
-       u64 mask_bit = 0;
 
        IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
 
@@ -2481,22 +2480,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
                        lq_sta->max_rate_idx = -1;
        }
 
-       if (sta)
-               mask_bit = sta->supp_rates[sband->band];
-
        /* Send management frames and NO_ACK data using lowest rate. */
-       if (!ieee80211_is_data(hdr->frame_control) ||
-           info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
-               if (!mask_bit)
-                       info->control.rates[0].idx =
-                                       rate_lowest_index(sband, NULL);
-               else
-                       info->control.rates[0].idx =
-                                       rate_lowest_index(sband, sta);
-               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
-                       info->control.rates[0].count = 1;
+       if (rate_control_send_low(sta, priv_sta, txrc))
                return;
-       }
 
        rate_idx  = lq_sta->last_txrate_idx;
 
index e2cc599..44c7f23 100644 (file)
@@ -533,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 
        if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
                IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
+               set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
+               wake_up_interruptible(&priv->wait_command_queue);
                memcpy(&priv->card_alive_init,
                       &pkt->u.alive_frame,
                       sizeof(struct iwl_init_alive_resp));
                pwork = &priv->init_alive_start;
        } else {
                IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+               set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+               wake_up_interruptible(&priv->wait_command_queue);
                memcpy(&priv->card_alive, &pkt->u.alive_frame,
                       sizeof(struct iwl_alive_resp));
                pwork = &priv->alive_start;
@@ -900,7 +904,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
        iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & IWL_DL_ISR) {
+       if (iwl_debug_level & IWL_DL_ISR) {
                /* just for debug */
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -919,7 +923,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
-               IWL_ERR(priv, "Microcode HW error detected.  Restarting.\n");
+               IWL_ERR(priv, "Hardware error detected.  Restarting.\n");
 
                /* Tell the device to stop sending interrupts */
                iwl_disable_interrupts(priv);
@@ -935,7 +939,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & (IWL_DL_ISR)) {
+       if (iwl_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
                if (inta & CSR_INT_BIT_SCD) {
                        IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -960,7 +964,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
                        hw_rf_kill = 1;
 
-               IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+               IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
                                hw_rf_kill ? "disable radio" : "enable radio");
 
                priv->isr_stats.rfkill++;
@@ -1049,7 +1053,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
                iwl_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & (IWL_DL_ISR)) {
+       if (iwl_debug_level & (IWL_DL_ISR)) {
                inta = iwl_read32(priv, CSR_INT);
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1080,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
        inta = priv->inta;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & IWL_DL_ISR) {
+       if (iwl_debug_level & IWL_DL_ISR) {
                /* just for debug */
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
@@ -1092,7 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
-               IWL_ERR(priv, "Microcode HW error detected.  Restarting.\n");
+               IWL_ERR(priv, "Hardware error detected.  Restarting.\n");
 
                /* Tell the device to stop sending interrupts */
                iwl_disable_interrupts(priv);
@@ -1108,7 +1112,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & (IWL_DL_ISR)) {
+       if (iwl_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
                if (inta & CSR_INT_BIT_SCD) {
                        IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1133,7 +1137,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
                        hw_rf_kill = 1;
 
-               IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+               IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
                                hw_rf_kill ? "disable radio" : "enable radio");
 
                priv->isr_stats.rfkill++;
@@ -1284,7 +1288,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
  */
 static int iwl_read_ucode(struct iwl_priv *priv)
 {
-       struct iwl_ucode *ucode;
+       struct iwl_ucode_header *ucode;
        int ret = -EINVAL, index;
        const struct firmware *ucode_raw;
        const char *name_pre = priv->cfg->fw_name_pre;
@@ -1293,7 +1297,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
        char buf[25];
        u8 *src;
        size_t len;
-       u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
+       u32 api_ver, build;
+       u32 inst_size, data_size, init_size, init_data_size, boot_size;
 
        /* Ask kernel firmware_class module to get the boot firmware off disk.
         * request_firmware() is synchronous, file is in memory on return. */
@@ -1323,23 +1328,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
        if (ret < 0)
                goto error;
 
-       /* Make sure that we got at least our header! */
-       if (ucode_raw->size < sizeof(*ucode)) {
+       /* Make sure that we got at least the v1 header! */
+       if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
                IWL_ERR(priv, "File size way too small!\n");
                ret = -EINVAL;
                goto err_release;
        }
 
        /* Data from ucode file:  header followed by uCode images */
-       ucode = (void *)ucode_raw->data;
+       ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
        priv->ucode_ver = le32_to_cpu(ucode->ver);
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       inst_size = le32_to_cpu(ucode->inst_size);
-       data_size = le32_to_cpu(ucode->data_size);
-       init_size = le32_to_cpu(ucode->init_size);
-       init_data_size = le32_to_cpu(ucode->init_data_size);
-       boot_size = le32_to_cpu(ucode->boot_size);
+       build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
+       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+       init_data_size =
+               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
 
        /* api_ver should match the api version forming part of the
         * firmware filename ... but we don't check for that and only rely
@@ -1365,6 +1373,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
               IWL_UCODE_API(priv->ucode_ver),
               IWL_UCODE_SERIAL(priv->ucode_ver));
 
+       if (build)
+               IWL_DEBUG_INFO(priv, "Build %u\n", build);
+
        IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
                       priv->ucode_ver);
        IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@@ -1379,12 +1390,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
                       boot_size);
 
        /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size < sizeof(*ucode) +
+       if (ucode_raw->size !=
+               priv->cfg->ops->ucode->get_header_size(api_ver) +
                inst_size + data_size + init_size +
                init_data_size + boot_size) {
 
-               IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
-                              (int)ucode_raw->size);
+               IWL_DEBUG_INFO(priv,
+                       "uCode file size %d does not match expected size\n",
+                       (int)ucode_raw->size);
                ret = -EINVAL;
                goto err_release;
        }
@@ -1464,42 +1477,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
-       src = &ucode->data[0];
-       len = priv->ucode_code.len;
+       len = inst_size;
        IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
        memcpy(priv->ucode_code.v_addr, src, len);
+       src += len;
+
        IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
        /* Runtime data (2nd block)
         * NOTE:  Copy into backup buffer will be done in iwl_up()  */
-       src = &ucode->data[inst_size];
-       len = priv->ucode_data.len;
+       len = data_size;
        IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
        memcpy(priv->ucode_data.v_addr, src, len);
        memcpy(priv->ucode_data_backup.v_addr, src, len);
+       src += len;
 
        /* Initialization instructions (3rd block) */
        if (init_size) {
-               src = &ucode->data[inst_size + data_size];
-               len = priv->ucode_init.len;
+               len = init_size;
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
                                len);
                memcpy(priv->ucode_init.v_addr, src, len);
+               src += len;
        }
 
        /* Initialization data (4th block) */
        if (init_data_size) {
-               src = &ucode->data[inst_size + data_size + init_size];
-               len = priv->ucode_init_data.len;
+               len = init_data_size;
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
                               len);
                memcpy(priv->ucode_init_data.v_addr, src, len);
+               src += len;
        }
 
        /* Bootstrap instructions (5th block) */
-       src = &ucode->data[inst_size + data_size + init_size + init_data_size];
-       len = priv->ucode_boot.len;
+       len = boot_size;
        IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
        memcpy(priv->ucode_boot.v_addr, src, len);
 
@@ -1773,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv)
 {
        int i;
        int ret;
+       unsigned long status;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@@ -1850,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv)
                /* start card; "initialize" will load runtime ucode */
                iwl_nic_start(priv);
 
+               /* Just finish download Init or Runtime uCode image to device
+                * now we wait here for uCode send REPLY_ALIVE notification
+                * to indicate uCode is ready.
+                * 1) For Init uCode image, all iwlagn devices should wait here
+                * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
+                * receive the REPLY_ALIVE notification, go back and try to
+                * download the Init uCode image again.
+                * 2) For Runtime uCode image, all iwlagn devices except 4965
+                * wait here on STATUS_RT_UCODE_ALIVE status bit; if
+                * timeout before receive the REPLY_ALIVE notification, go back
+                * and download the Runtime uCode image again.
+                * 3) For 4965 Runtime uCode, it will not go through this path,
+                * need to wait for STATUS_RT_UCODE_ALIVE status bit in
+                * iwl4965_init_alive_start() function; if timeout, need to
+                * restart and download Init uCode image.
+                */
+               if (priv->ucode_type == UCODE_INIT)
+                       status = STATUS_INIT_UCODE_ALIVE;
+               else
+                       status = STATUS_RT_UCODE_ALIVE;
+               if (test_bit(status, &priv->status)) {
+                       IWL_WARN(priv,
+                               "%s uCode already alive? "
+                               "Waiting for alive anyway\n",
+                               (status == STATUS_INIT_UCODE_ALIVE)
+                               ? "INIT" : "Runtime");
+                       clear_bit(status, &priv->status);
+               }
+               ret = wait_event_interruptible_timeout(
+                               priv->wait_command_queue,
+                               test_bit(status, &priv->status),
+                               UCODE_ALIVE_TIMEOUT);
+               if (!ret) {
+                       if (!test_bit(status, &priv->status)) {
+                               priv->ucode_type =
+                                       (status == STATUS_INIT_UCODE_ALIVE)
+                                       ? UCODE_NONE : UCODE_INIT;
+                               IWL_ERR(priv,
+                                       "%s timeout after %dms\n",
+                                       (status == STATUS_INIT_UCODE_ALIVE)
+                                       ? "INIT" : "Runtime",
+                                       jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+                               continue;
+                       }
+               }
                IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
 
                return 0;
@@ -2397,14 +2456,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
  * used for controlling the debug level.
  *
  * See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
  */
 
 static ssize_t show_debug_level(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       return sprintf(buf, "0x%08X\n", priv->debug_level);
+       return sprintf(buf, "0x%08X\n", iwl_debug_level);
 }
 static ssize_t store_debug_level(struct device *d,
                                struct device_attribute *attr,
@@ -2418,7 +2479,7 @@ static ssize_t store_debug_level(struct device *d,
        if (ret)
                IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
        else
-               priv->debug_level = val;
+               iwl_debug_level = val;
 
        return strnlen(buf, count);
 }
@@ -2627,26 +2688,6 @@ static ssize_t show_power_level(struct device *d,
 static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
                   store_power_level);
 
-static ssize_t show_qos(struct device *d,
-                               struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       char *p = buf;
-       int   q;
-
-       for (q = 0; q < AC_NUM; q++) {
-               p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
-               p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
-                            priv->qos_data.def_qos_parm.ac[q].cw_min,
-                            priv->qos_data.def_qos_parm.ac[q].cw_max,
-                            priv->qos_data.def_qos_parm.ac[q].aifsn,
-                            priv->qos_data.def_qos_parm.ac[q].edca_txop);
-       }
-
-       return p - buf + 1;
-}
-
-static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
 
 static ssize_t show_statistics(struct device *d,
                               struct device_attribute *attr, char *buf)
@@ -2747,7 +2788,6 @@ static struct attribute *iwl_sysfs_entries[] = {
        &dev_attr_debug_level.attr,
 #endif
        &dev_attr_version.attr,
-       &dev_attr_qos.attr,
        NULL
 };
 
@@ -2791,7 +2831,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan. */
        if (cfg->mod_params->disable_hw_scan) {
-               if (cfg->mod_params->debug & IWL_DL_INFO)
+               if (iwl_debug_level & IWL_DL_INFO)
                        dev_printk(KERN_DEBUG, &(pdev->dev),
                                   "Disabling hw_scan\n");
                iwl_hw_ops.hw_scan = NULL;
@@ -2813,7 +2853,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        priv->inta_mask = CSR_INI_SET_MASK;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       priv->debug_level = priv->cfg->mod_params->debug;
        atomic_set(&priv->restrict_refcnt, 0);
 #endif
 
@@ -3173,3 +3212,11 @@ static void __exit iwl_exit(void)
 
 module_exit(iwl_exit);
 module_init(iwl_init);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug50, iwl_debug_level, uint, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
+module_param_named(debug, iwl_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug, "debug output mask");
+#endif
+
index d5cd9a2..6aea026 100644 (file)
@@ -59,6 +59,9 @@ MODULE_LICENSE("GPL");
                                    IWL_RATE_##pp##M_INDEX,    \
                                    IWL_RATE_##np##M_INDEX }
 
+u32 iwl_debug_level;
+EXPORT_SYMBOL(iwl_debug_level);
+
 static irqreturn_t iwl_isr(int irq, void *data);
 
 /*
@@ -1275,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
        struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 
        IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+       iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
        IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
        IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
        IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
@@ -1290,6 +1293,209 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
 }
 #endif
 
+static const char *desc_lookup_text[] = {
+       "OK",
+       "FAIL",
+       "BAD_PARAM",
+       "BAD_CHECKSUM",
+       "NMI_INTERRUPT_WDG",
+       "SYSASSERT",
+       "FATAL_ERROR",
+       "BAD_COMMAND",
+       "HW_ERROR_TUNE_LOCK",
+       "HW_ERROR_TEMPERATURE",
+       "ILLEGAL_CHAN_FREQ",
+       "VCC_NOT_STABLE",
+       "FH_ERROR",
+       "NMI_INTERRUPT_HOST",
+       "NMI_INTERRUPT_ACTION_PT",
+       "NMI_INTERRUPT_UNKNOWN",
+       "UCODE_VERSION_MISMATCH",
+       "HW_ERROR_ABS_LOCK",
+       "HW_ERROR_CAL_LOCK_FAIL",
+       "NMI_INTERRUPT_INST_ACTION_PT",
+       "NMI_INTERRUPT_DATA_ACTION_PT",
+       "NMI_TRM_HW_ER",
+       "NMI_INTERRUPT_TRM",
+       "NMI_INTERRUPT_BREAK_POINT"
+       "DEBUG_0",
+       "DEBUG_1",
+       "DEBUG_2",
+       "DEBUG_3",
+       "UNKNOWN"
+};
+
+static const char *desc_lookup(int i)
+{
+       int max = ARRAY_SIZE(desc_lookup_text) - 1;
+
+       if (i < 0 || i > max)
+               i = max;
+
+       return desc_lookup_text[i];
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+       u32 data2, line;
+       u32 desc, time, count, base, data1;
+       u32 blink1, blink2, ilink1, ilink2;
+
+       switch (priv->ucode_type) {
+       case UCODE_RT:
+               base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+               break;
+       case UCODE_INIT:
+               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+               break;
+       default:
+               IWL_ERR(priv, "uCode image not available\n");
+               return;
+       }
+
+       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
+               return;
+       }
+
+       count = iwl_read_targ_mem(priv, base);
+
+       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+               IWL_ERR(priv, "Start IWL Error Log Dump:\n");
+               IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
+                       priv->status, count);
+       }
+
+       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+       IWL_ERR(priv, "Desc                               Time       "
+               "data1      data2      line\n");
+       IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+               desc_lookup(desc), desc, time, data1, data2, line);
+       IWL_ERR(priv, "blink1  blink2  ilink1  ilink2\n");
+       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+               ilink1, ilink2);
+
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                               u32 num_events, u32 mode)
+{
+       u32 i;
+       u32 base;       /* SRAM byte address of event log header */
+       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+
+       if (num_events == 0)
+               return;
+       switch (priv->ucode_type) {
+       case UCODE_RT:
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+               break;
+       case UCODE_INIT:
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+               break;
+       default:
+               IWL_ERR(priv, "uCode image not available\n");
+               return;
+       }
+
+       if (mode == 0)
+               event_size = 2 * sizeof(u32);
+       else
+               event_size = 3 * sizeof(u32);
+
+       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+       /* "time" is actually "data" for mode 0 (no timestamp).
+       * place event id # at far right for easier visual parsing. */
+       for (i = 0; i < num_events; i++) {
+               ev = iwl_read_targ_mem(priv, ptr);
+               ptr += sizeof(u32);
+               time = iwl_read_targ_mem(priv, ptr);
+               ptr += sizeof(u32);
+               if (mode == 0) {
+                       /* data, ev */
+                       IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+               } else {
+                       data = iwl_read_targ_mem(priv, ptr);
+                       ptr += sizeof(u32);
+                       IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                       time, data, ev);
+               }
+       }
+}
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+       u32 base;       /* SRAM byte address of event log header */
+       u32 capacity;   /* event log capacity in # entries */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+       u32 size;       /* # entries that we'll print */
+
+       switch (priv->ucode_type) {
+       case UCODE_RT:
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+               break;
+       case UCODE_INIT:
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+               break;
+       default:
+               IWL_ERR(priv, "uCode image not available\n");
+               return;
+       }
+
+       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
+               return;
+       }
+
+       /* event log header */
+       capacity = iwl_read_targ_mem(priv, base);
+       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+       size = num_wraps ? capacity : next_entry;
+
+       /* bail out if nothing in log */
+       if (size == 0) {
+               IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
+               return;
+       }
+
+       IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
+                       size, num_wraps);
+
+       /* if uCode has wrapped back to top of log, start at the oldest entry,
+        * i.e the next one that uCode would fill. */
+       if (num_wraps)
+               iwl_print_event_log(priv, next_entry,
+                                       capacity - next_entry, mode);
+       /* (then/else) start at top of log */
+       iwl_print_event_log(priv, 0, next_entry, mode);
+
+}
 /**
  * iwl_irq_handle_error - called for HW or SW error interrupt from card
  */
@@ -1302,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & IWL_DL_FW_ERRORS) {
+       if (iwl_debug_level & IWL_DL_FW_ERRORS) {
                iwl_dump_nic_error_log(priv);
                iwl_dump_nic_event_log(priv);
                iwl_print_rx_config_cmd(priv);
@@ -1543,31 +1749,6 @@ void iwl_uninit_drv(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_uninit_drv);
 
-
-void iwl_disable_interrupts(struct iwl_priv *priv)
-{
-       clear_bit(STATUS_INT_ENABLED, &priv->status);
-
-       /* disable interrupts from uCode/NIC to host */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-       /* acknowledge/clear/reset any interrupts still pending
-        * from uCode or flow handler (Rx/Tx DMA) */
-       iwl_write32(priv, CSR_INT, 0xffffffff);
-       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
-       IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-EXPORT_SYMBOL(iwl_disable_interrupts);
-
-void iwl_enable_interrupts(struct iwl_priv *priv)
-{
-       IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &priv->status);
-       iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
-}
-EXPORT_SYMBOL(iwl_enable_interrupts);
-
-
 #define ICT_COUNT (PAGE_SIZE/sizeof(u32))
 
 /* Free dram table */
@@ -1801,7 +1982,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & (IWL_DL_ISR)) {
+       if (iwl_debug_level & (IWL_DL_ISR)) {
                inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
                IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
                              "fh 0x%08x\n", inta, inta_mask, inta_fh);
@@ -2040,191 +2221,6 @@ int iwl_verify_ucode(struct iwl_priv *priv)
 EXPORT_SYMBOL(iwl_verify_ucode);
 
 
-static const char *desc_lookup_text[] = {
-       "OK",
-       "FAIL",
-       "BAD_PARAM",
-       "BAD_CHECKSUM",
-       "NMI_INTERRUPT_WDG",
-       "SYSASSERT",
-       "FATAL_ERROR",
-       "BAD_COMMAND",
-       "HW_ERROR_TUNE_LOCK",
-       "HW_ERROR_TEMPERATURE",
-       "ILLEGAL_CHAN_FREQ",
-       "VCC_NOT_STABLE",
-       "FH_ERROR",
-       "NMI_INTERRUPT_HOST",
-       "NMI_INTERRUPT_ACTION_PT",
-       "NMI_INTERRUPT_UNKNOWN",
-       "UCODE_VERSION_MISMATCH",
-       "HW_ERROR_ABS_LOCK",
-       "HW_ERROR_CAL_LOCK_FAIL",
-       "NMI_INTERRUPT_INST_ACTION_PT",
-       "NMI_INTERRUPT_DATA_ACTION_PT",
-       "NMI_TRM_HW_ER",
-       "NMI_INTERRUPT_TRM",
-       "NMI_INTERRUPT_BREAK_POINT"
-       "DEBUG_0",
-       "DEBUG_1",
-       "DEBUG_2",
-       "DEBUG_3",
-       "UNKNOWN"
-};
-
-static const char *desc_lookup(int i)
-{
-       int max = ARRAY_SIZE(desc_lookup_text) - 1;
-
-       if (i < 0 || i > max)
-               i = max;
-
-       return desc_lookup_text[i];
-}
-
-#define ERROR_START_OFFSET  (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
-       u32 data2, line;
-       u32 desc, time, count, base, data1;
-       u32 blink1, blink2, ilink1, ilink2;
-
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
-       else
-               base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
-       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
-               IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
-               return;
-       }
-
-       count = iwl_read_targ_mem(priv, base);
-
-       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
-               IWL_ERR(priv, "Start IWL Error Log Dump:\n");
-               IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
-                       priv->status, count);
-       }
-
-       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
-       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
-       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
-       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
-       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
-       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
-       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
-       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
-       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
-       IWL_ERR(priv, "Desc                               Time       "
-               "data1      data2      line\n");
-       IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
-               desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERR(priv, "blink1  blink2  ilink1  ilink2\n");
-       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
-               ilink1, ilink2);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_error_log);
-
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
-{
-       u32 i;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
-       u32 ptr;        /* SRAM byte address of log data */
-       u32 ev, time, data; /* event log data */
-
-       if (num_events == 0)
-               return;
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-       else
-               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
-       if (mode == 0)
-               event_size = 2 * sizeof(u32);
-       else
-               event_size = 3 * sizeof(u32);
-
-       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
-       /* "time" is actually "data" for mode 0 (no timestamp).
-       * place event id # at far right for easier visual parsing. */
-       for (i = 0; i < num_events; i++) {
-               ev = iwl_read_targ_mem(priv, ptr);
-               ptr += sizeof(u32);
-               time = iwl_read_targ_mem(priv, ptr);
-               ptr += sizeof(u32);
-               if (mode == 0) {
-                       /* data, ev */
-                       IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
-               } else {
-                       data = iwl_read_targ_mem(priv, ptr);
-                       ptr += sizeof(u32);
-                       IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
-                                       time, data, ev);
-               }
-       }
-}
-
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
-       u32 base;       /* SRAM byte address of event log header */
-       u32 capacity;   /* event log capacity in # entries */
-       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-       u32 num_wraps;  /* # times uCode wrapped to top of log */
-       u32 next_entry; /* index of next entry to be written by uCode */
-       u32 size;       /* # entries that we'll print */
-
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-       else
-               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
-       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
-               IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
-               return;
-       }
-
-       /* event log header */
-       capacity = iwl_read_targ_mem(priv, base);
-       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
-       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
-       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
-       size = num_wraps ? capacity : next_entry;
-
-       /* bail out if nothing in log */
-       if (size == 0) {
-               IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               return;
-       }
-
-       IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
-                       size, num_wraps);
-
-       /* if uCode has wrapped back to top of log, start at the oldest entry,
-        * i.e the next one that uCode would fill. */
-       if (num_wraps)
-               iwl_print_event_log(priv, next_entry,
-                                       capacity - next_entry, mode);
-       /* (then/else) start at top of log */
-       iwl_print_event_log(priv, 0, next_entry, mode);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_event_log);
-
 void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 {
        struct iwl_ct_kill_config cmd;
@@ -2293,7 +2289,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
        IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
                        "notification for %s:\n",
                        le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+       iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
 }
 EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
 
index a658410..614ec7c 100644 (file)
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
        void (*set_ct_kill)(struct iwl_priv *priv);
 };
 
+struct iwl_ucode_ops {
+       u32 (*get_header_size)(u32);
+       u32 (*get_build)(const struct iwl_ucode_header *, u32);
+       u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
+       u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
+       u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
+       u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
+       u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
+       u8 * (*get_data)(const struct iwl_ucode_header *, u32);
+};
+
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,6 +182,7 @@ struct iwl_lib_ops {
 };
 
 struct iwl_ops {
+       const struct iwl_ucode_ops *ucode;
        const struct iwl_lib_ops *lib;
        const struct iwl_hcmd_ops *hcmd;
        const struct iwl_hcmd_utils_ops *utils;
@@ -178,7 +190,6 @@ struct iwl_ops {
 
 struct iwl_mod_params {
        int sw_crypto;          /* def: 0 = using hardware encryption */
-       u32 debug;              /* def: 0 = minimal debug log messages */
        int disable_hw_scan;    /* def: 0 = use h/w scan */
        int num_of_queues;      /* def: HW dependent */
        int num_of_ampdu_queues;/* def: HW dependent */
@@ -447,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
 /*****************************************************
  * PCI                                              *
  *****************************************************/
-void iwl_disable_interrupts(struct iwl_priv *priv);
-void iwl_enable_interrupts(struct iwl_priv *priv);
 irqreturn_t iwl_isr_legacy(int irq, void *data);
 int iwl_reset_ict(struct iwl_priv *priv);
 void iwl_disable_ict(struct iwl_priv *priv);
@@ -472,7 +481,6 @@ int iwl_pci_resume(struct pci_dev *pdev);
 /*****************************************************
 *  Error Handling Debugging
 ******************************************************/
-void iwl_dump_nic_error_log(struct iwl_priv *priv);
 void iwl_dump_nic_event_log(struct iwl_priv *priv);
 void iwl_clear_isr_stats(struct iwl_priv *priv);
 
@@ -501,6 +509,8 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
 #define STATUS_MODE_PENDING    18
+#define STATUS_INIT_UCODE_ALIVE        19
+#define STATUS_RT_UCODE_ALIVE  20
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
index 65bbce0..9faf0c2 100644 (file)
@@ -30,6 +30,7 @@
 #define __iwl_debug_h__
 
 struct iwl_priv;
+extern u32 iwl_debug_level;
 
 #define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
 #define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
@@ -45,7 +46,7 @@ do {                                                                  \
 #ifdef CONFIG_IWLWIFI_DEBUG
 #define IWL_DEBUG(__priv, level, fmt, args...)                         \
 do {                                                                   \
-       if (__priv->debug_level & (level))                              \
+       if (iwl_debug_level & (level))                                  \
                dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev),         \
                         "%c %s " fmt, in_interrupt() ? 'I' : 'U',      \
                        __func__ , ## args);                            \
@@ -53,15 +54,15 @@ do {                                                                        \
 
 #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)                   \
 do {                                                                   \
-       if ((__priv->debug_level & (level)) && net_ratelimit())         \
+       if ((iwl_debug_level & (level)) && net_ratelimit())             \
                dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev),         \
                        "%c %s " fmt, in_interrupt() ? 'I' : 'U',       \
                         __func__ , ## args);                           \
 } while (0)
 
-#define iwl_print_hex_dump(priv, level, p, len)                        \
+#define iwl_print_hex_dump(level, p, len)                              \
 do {                                                                   \
-       if (priv->debug_level & level)                                  \
+       if (iwl_debug_level & level)                                    \
                print_hex_dump(KERN_DEBUG, "iwl data: ",                \
                               DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);   \
 } while (0)
@@ -82,6 +83,10 @@ struct iwl_debugfs {
                struct dentry *file_channels;
                struct dentry *file_status;
                struct dentry *file_interrupt;
+               struct dentry *file_qos;
+#ifdef CONFIG_IWLWIFI_LEDS
+               struct dentry *file_led;
+#endif
        } dbgfs_data_files;
        struct dir_rf_files {
                struct dentry *file_disable_sensitivity;
@@ -99,8 +104,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
 #else
 #define IWL_DEBUG(__priv, level, fmt, args...)
 #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
-                                     void *p, u32 len)
+static inline void iwl_print_hex_dump(int level, void *p, u32 len)
 {}
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
index f32ac74..0ab3463 100644 (file)
@@ -49,7 +49,8 @@
 
 #define DEBUGFS_ADD_FILE(name, parent) do {                             \
        dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv,     \
+       debugfs_create_file(#name, S_IWUSR | S_IRUSR,                   \
+                               dbgfs->dir_##parent, priv,              \
                                &iwl_dbgfs_##name##_ops);               \
        if (!(dbgfs->dbgfs_##parent##_files.file_##name))               \
                goto err;                                               \
@@ -57,7 +58,8 @@
 
 #define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
        dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr);     \
+       debugfs_create_bool(#name, S_IWUSR | S_IRUSR,                   \
+                           dbgfs->dir_##parent, ptr);                  \
        if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)           \
                        || !dbgfs->dbgfs_##parent##_files.file_##name)  \
                goto err;                                               \
@@ -65,7 +67,7 @@
 
 #define DEBUGFS_ADD_X32(name, parent, ptr) do {                        \
        dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr);     \
+       debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr);   \
        if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)           \
                        || !dbgfs->dbgfs_##parent##_files.file_##name)  \
                goto err;                                               \
@@ -566,6 +568,55 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
        return count;
 }
 
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0, i;
+       char buf[256];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       for (i = 0; i < AC_NUM; i++) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "\tcw_min\tcw_max\taifsn\ttxop\n");
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "AC[%d]\t%u\t%u\t%u\t%u\n", i,
+                               priv->qos_data.def_qos_parm.ac[i].cw_min,
+                               priv->qos_data.def_qos_parm.ac[i].cw_max,
+                               priv->qos_data.def_qos_parm.ac[i].aifsn,
+                               priv->qos_data.def_qos_parm.ac[i].edca_txop);
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_LEDS
+static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char buf[256];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "allow blinking: %s\n",
+                        (priv->allow_blinking) ? "True" : "False");
+       if (priv->allow_blinking) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                "Led blinking rate: %u\n",
+                                priv->last_blink_rate);
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                "Last blink time: %lu\n",
+                                priv->last_blink_time);
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+#endif
 
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
 DEBUGFS_WRITE_FILE_OPS(log_event);
@@ -576,6 +627,10 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_FILE_OPS(channels);
 DEBUGFS_READ_FILE_OPS(status);
 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+DEBUGFS_READ_FILE_OPS(led);
+#endif
 
 /*
  * Create the debugfs files and directories
@@ -612,6 +667,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(channels, data);
        DEBUGFS_ADD_FILE(status, data);
        DEBUGFS_ADD_FILE(interrupt, data);
+       DEBUGFS_ADD_FILE(qos, data);
+#ifdef CONFIG_IWLWIFI_LEDS
+       DEBUGFS_ADD_FILE(led, data);
+#endif
        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
                         &priv->disable_chain_noise_cal);
@@ -646,6 +705,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
+#endif
        DEBUGFS_REMOVE(priv->dbgfs->dir_data);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
index 1a2fe37..0751891 100644 (file)
@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
 /* shared structures from iwl-5000.c */
 extern struct iwl_mod_params iwl50_mod_params;
 extern struct iwl_ops iwl5000_ops;
+extern struct iwl_ucode_ops iwl5000_ucode;
 extern struct iwl_lib_ops iwl5000_lib;
 extern struct iwl_hcmd_ops iwl5000_hcmd;
 extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@@ -258,8 +259,10 @@ struct iwl_channel_info {
 #define IWL_TX_FIFO_HCCA_2     6
 #define IWL_TX_FIFO_NONE       7
 
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES     4
+/* Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate the 4 standard TX queues, 1 command
+ * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
+#define IWL_MIN_NUM_QUEUES     10
 
 /* Power management (not Tx power) structures */
 
@@ -523,15 +526,29 @@ struct fw_desc {
 };
 
 /* uCode file layout */
-struct iwl_ucode {
-       __le32 ver;             /* major/minor/API/serial */
-       __le32 inst_size;       /* bytes of runtime instructions */
-       __le32 data_size;       /* bytes of runtime data */
-       __le32 init_size;       /* bytes of initialization instructions */
-       __le32 init_data_size;  /* bytes of initialization data */
-       __le32 boot_size;       /* bytes of bootstrap instructions */
-       u8 data[0];             /* data in same order as "size" elements */
+struct iwl_ucode_header {
+       __le32 ver;     /* major/minor/API/serial */
+       union {
+               struct {
+                       __le32 inst_size;       /* bytes of runtime code */
+                       __le32 data_size;       /* bytes of runtime data */
+                       __le32 init_size;       /* bytes of init code */
+                       __le32 init_data_size;  /* bytes of init data */
+                       __le32 boot_size;       /* bytes of bootstrap code */
+                       u8 data[0];             /* in same order as sizes */
+               } v1;
+               struct {
+                       __le32 build;           /* build number */
+                       __le32 inst_size;       /* bytes of runtime code */
+                       __le32 data_size;       /* bytes of runtime data */
+                       __le32 init_size;       /* bytes of init code */
+                       __le32 init_data_size;  /* bytes of init data */
+                       __le32 boot_size;       /* bytes of bootstrap code */
+                       u8 data[0];             /* in same order as sizes */
+               } v2;
+       } u;
 };
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
 
 struct iwl4965_ibss_seq {
        u8 mac[ETH_ALEN];
@@ -755,6 +772,8 @@ struct iwl_calib_result {
        size_t buf_len;
 };
 
+#define UCODE_ALIVE_TIMEOUT    (5 * HZ)
+
 enum ucode_type {
        UCODE_NONE = 0,
        UCODE_INIT,
@@ -1092,7 +1111,6 @@ struct iwl_priv {
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        /* debugging info */
-       u32 debug_level;
        u32 framecnt_to_us;
        atomic_t restrict_refcnt;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
index 7d7554a..51eed72 100644 (file)
@@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
 
        /* OTP only valid for CP/PP and after */
        switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+       case CSR_HW_REV_TYPE_NONE:
+               IWL_ERR(priv, "Unknown hardware type\n");
+               return -ENOENT;
        case CSR_HW_REV_TYPE_3945:
        case CSR_HW_REV_TYPE_4965:
        case CSR_HW_REV_TYPE_5300:
@@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
        u32 otpgp;
 
        priv->nvm_device_type = iwlcore_get_nvm_type(priv);
-
+       if (priv->nvm_device_type == -ENOENT)
+               return -ENOENT;
        /* allocate eeprom */
        if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                priv->cfg->eeprom_size =
index a1328c3..bd0b12e 100644 (file)
@@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
 #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
 #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
 
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+       clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+       /* disable interrupts from uCode/NIC to host */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+       /* acknowledge/clear/reset any interrupts still pending
+        * from uCode or flow handler (Rx/Tx DMA) */
+       iwl_write32(priv, CSR_INT, 0xffffffff);
+       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+       IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+       IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
+       set_bit(STATUS_INT_ENABLED, &priv->status);
+       iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
+}
+
 #endif                         /* __iwl_helpers_h__ */
index 5e64252..8c81152 100644 (file)
@@ -54,7 +54,7 @@ static const char *led_type_str[] = {
 
 
 static const struct {
-       u16 tpt;
+       u16 tpt;        /* Mb/s */
        u8 on_time;
        u8 off_time;
 } blink_tbl[] =
@@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
 }
 
 /* Set led pattern command */
-static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
+static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
                               unsigned int idx)
 {
        struct iwl_led_cmd led_cmd = {
@@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
 }
 
 /* Set led register off */
-static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
 {
        IWL_DEBUG_LED(priv, "led on %d\n", led_id);
        iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
@@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
 
 #if 0
 /* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+static int iwl_led_on(struct iwl_priv *priv, int led_id)
 {
        struct iwl_led_cmd led_cmd = {
                .id = led_id,
@@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
 }
 
 /* Set led off command */
-int iwl4965_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_off(struct iwl_priv *priv, int led_id)
 {
        struct iwl_led_cmd led_cmd = {
                .id = led_id,
@@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
 
 
 /* Set led register off */
-static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
 {
        IWL_DEBUG_LED(priv, "LED Reg off\n");
        iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
@@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
 {
        IWL_DEBUG_LED(priv, "Associated\n");
        priv->allow_blinking = 1;
-       return iwl4965_led_on_reg(priv, led_id);
+       return iwl_led_on_reg(priv, led_id);
 }
 static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
 {
@@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
 
 
 /*
- * calculate blink rate according to last 2 sec Tx/Rx activities
+ * calculate blink rate according to last second Tx/Rx activities
  */
 static int iwl_get_blink_rate(struct iwl_priv *priv)
 {
        int i;
-       u64 current_tpt = priv->tx_stats[2].bytes;
-       /* FIXME: + priv->rx_stats[2].bytes; */
+       /* count both tx and rx traffic to be able to
+        * handle traffic in either direction
+        */
+       u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
        s64 tpt = current_tpt - priv->led_tpt;
 
        if (tpt < 0) /* wraparound */
@@ -314,7 +316,7 @@ void iwl_leds_background(struct iwl_priv *priv)
                priv->last_blink_time = 0;
                if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
                        priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
-                       iwl4965_led_pattern(priv, IWL_LED_LINK,
+                       iwl_led_pattern(priv, IWL_LED_LINK,
                                            IWL_SOLID_BLINK_IDX);
                }
                return;
@@ -328,7 +330,7 @@ void iwl_leds_background(struct iwl_priv *priv)
 
        /* call only if blink rate change */
        if (blink_idx != priv->last_blink_rate)
-               iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
+               iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
 
        priv->last_blink_time = jiffies;
        priv->last_blink_rate = blink_idx;
@@ -351,8 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv)
                 sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
                 wiphy_name(priv->hw->wiphy));
 
-       priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
-       priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
+       priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
+       priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
        priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
 
        ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
@@ -386,7 +388,7 @@ int iwl_leds_register(struct iwl_priv *priv)
 
        priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
        priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
-       priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
+       priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
 
        if (ret)
                goto exit_fail;
@@ -401,7 +403,7 @@ int iwl_leds_register(struct iwl_priv *priv)
 
        priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
        priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
-       priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
+       priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
 
        if (ret)
                goto exit_fail;
index 3b9cac3..d393e8f 100644 (file)
@@ -80,6 +80,8 @@
 #define APMG_RFKILL_REG                        (APMG_BASE + 0x0014)
 #define APMG_RTC_INT_STT_REG           (APMG_BASE + 0x001c)
 #define APMG_RTC_INT_MSK_REG           (APMG_BASE + 0x0020)
+#define APMG_DIGITAL_SVR_REG           (APMG_BASE + 0x0058)
+#define APMG_ANALOG_SVR_REG            (APMG_BASE + 0x006C)
 
 #define APMG_CLK_VAL_DMA_CLK_RQT       (0x00000200)
 #define APMG_CLK_VAL_BSM_CLK_RQT       (0x00000800)
@@ -91,7 +93,8 @@
 #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN         (0x00000000)
 #define APMG_PS_CTRL_VAL_PWR_SRC_MAX           (0x01000000) /* 3945 only */
 #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX          (0x02000000)
-
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK        (0x000001E0) /* bit 8:5 */
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32          (0x00000060)
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS         (0x00000800)
 
index 66fe365..5d5f215 100644 (file)
@@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
        u32 tsf_low;
        int rssi;
 
-       if (likely(!(priv->debug_level & IWL_DL_RX)))
+       if (likely(!(iwl_debug_level & IWL_DL_RX)))
                return;
 
        /* MAC header */
@@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
                }
        }
        if (print_dump)
-               iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
+               iwl_print_hex_dump(IWL_DL_RX, header, length);
 }
 #endif
 
@@ -1061,11 +1061,11 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 
        /* Set "1" to report good data frames in groups of 100 */
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (unlikely(priv->debug_level & IWL_DL_RX))
+       if (unlikely(iwl_debug_level & IWL_DL_RX))
                iwl_dbg_report_frame(priv, rx_start, len, header, 1);
 #endif
        IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
-               rx_status.signal, rx_status.noise, rx_status.signal,
+               rx_status.signal, rx_status.noise, rx_status.qual,
                (unsigned long long)rx_status.mactime);
 
        /*
index 2addf73..cbe4e26 100644 (file)
@@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
        unsigned long flags;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
+       IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+                     keyconf->keyidx);
 
        if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
                IWL_ERR(priv, "index %d not used in uCode key table.\n",
@@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
 
        priv->default_wep_key--;
        memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+               return 0;
+       }
        ret = iwl_send_static_wepkey_cmd(priv, 1);
        IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
                      keyconf->keyidx, ret);
@@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(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;
 
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+               return 0;
+       }
        ret =  iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
        return ret;
@@ -1044,11 +1056,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station);
 int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 {
        int sta_id;
-       u16 fc = le16_to_cpu(hdr->frame_control);
+       __le16 fc = hdr->frame_control;
 
        /* If this frame is broadcast or management, use broadcast station id */
-       if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
-           is_multicast_ether_addr(hdr->addr1))
+       if (!ieee80211_is_data(fc) ||  is_multicast_ether_addr(hdr->addr1))
                return priv->hw_params.bcast_sta_id;
 
        switch (priv->iw_mode) {
@@ -1082,7 +1093,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
                IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
                               "Defaulting to broadcast...\n",
                               hdr->addr1);
-               iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+               iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
                return priv->hw_params.bcast_sta_id;
 
        default:
index 7073069..0912987 100644 (file)
@@ -869,8 +869,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
                     le16_to_cpu(out_cmd->hdr.sequence));
        IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+       iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+       iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
 
        /* Set up entry for this TFD in Tx byte-count array */
        if (info->flags & IEEE80211_TX_CTL_AMPDU)
@@ -940,7 +940,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
               !(cmd->meta.flags & CMD_SIZE_HUGE));
 
        if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_INFO(priv, "Not sending command - RF KILL");
+               IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
                return -EIO;
        }
 
index 7ff95f8..2cc7e30 100644 (file)
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
 
  /* module parameters */
 struct iwl_mod_params iwl3945_mod_params = {
-       .num_of_queues = IWL39_MAX_NUM_QUEUES,
+       .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
        .sw_crypto = 1,
        .restart_fw = 1,
        /* the rest are 0 by default */
@@ -612,8 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
                     le16_to_cpu(out_cmd->hdr.sequence));
        IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags));
-       iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
+       iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx));
+       iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr,
                           ieee80211_hdrlen(fc));
 
        /*
@@ -926,7 +926,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
        unsigned long status = priv->status;
 
-       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+       IWL_WARN(priv, "Card state received: HW:%s SW:%s\n",
                          (flags & HW_CARD_DISABLED) ? "Kill" : "On",
                          (flags & SW_CARD_DISABLED) ? "Kill" : "On");
 
@@ -1644,7 +1644,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
        iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & IWL_DL_ISR) {
+       if (iwl_debug_level & IWL_DL_ISR) {
                /* just for debug */
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -1663,7 +1663,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
-               IWL_ERR(priv, "Microcode HW error detected.  Restarting.\n");
+               IWL_ERR(priv, "Hardware error detected.  Restarting.\n");
 
                /* Tell the device to stop sending interrupts */
                iwl_disable_interrupts(priv);
@@ -1679,7 +1679,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & (IWL_DL_ISR)) {
+       if (iwl_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
                if (inta & CSR_INT_BIT_SCD) {
                        IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1758,7 +1758,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
                iwl_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & (IWL_DL_ISR)) {
+       if (iwl_debug_level & (IWL_DL_ISR)) {
                inta = iwl_read32(priv, CSR_INT);
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -2041,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
  */
 static int iwl3945_read_ucode(struct iwl_priv *priv)
 {
-       struct iwl_ucode *ucode;
+       const struct iwl_ucode_header *ucode;
        int ret = -EINVAL, index;
        const struct firmware *ucode_raw;
        /* firmware file name contains uCode/driver compatibility version */
@@ -2082,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
                goto error;
 
        /* Make sure that we got at least our header! */
-       if (ucode_raw->size < sizeof(*ucode)) {
+       if (ucode_raw->size <  priv->cfg->ops->ucode->get_header_size(1)) {
                IWL_ERR(priv, "File size way too small!\n");
                ret = -EINVAL;
                goto err_release;
        }
 
        /* Data from ucode file:  header followed by uCode images */
-       ucode = (void *)ucode_raw->data;
+       ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
        priv->ucode_ver = le32_to_cpu(ucode->ver);
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       inst_size = le32_to_cpu(ucode->inst_size);
-       data_size = le32_to_cpu(ucode->data_size);
-       init_size = le32_to_cpu(ucode->init_size);
-       init_data_size = le32_to_cpu(ucode->init_data_size);
-       boot_size = le32_to_cpu(ucode->boot_size);
+       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+       init_data_size =
+               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
 
        /* api_ver should match the api version forming part of the
         * firmware filename ... but we don't check for that and only rely
@@ -2138,12 +2140,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
 
 
        /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size < sizeof(*ucode) +
+       if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
                inst_size + data_size + init_size +
                init_data_size + boot_size) {
 
-               IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
-                              ucode_raw->size);
+               IWL_DEBUG_INFO(priv,
+                       "uCode file size %zd does not match expected size\n",
+                       ucode_raw->size);
                ret = -EINVAL;
                goto err_release;
        }
@@ -2226,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
-       src = &ucode->data[0];
-       len = priv->ucode_code.len;
+       len = inst_size;
        IWL_DEBUG_INFO(priv,
                "Copying (but not loading) uCode instr len %zd\n", len);
        memcpy(priv->ucode_code.v_addr, src, len);
+       src += len;
+
        IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
        /* Runtime data (2nd block)
         * NOTE:  Copy into backup buffer will be done in iwl3945_up()  */
-       src = &ucode->data[inst_size];
-       len = priv->ucode_data.len;
+       len = data_size;
        IWL_DEBUG_INFO(priv,
                "Copying (but not loading) uCode data len %zd\n", len);
        memcpy(priv->ucode_data.v_addr, src, len);
        memcpy(priv->ucode_data_backup.v_addr, src, len);
+       src += len;
 
        /* Initialization instructions (3rd block) */
        if (init_size) {
-               src = &ucode->data[inst_size + data_size];
-               len = priv->ucode_init.len;
+               len = init_size;
                IWL_DEBUG_INFO(priv,
                        "Copying (but not loading) init instr len %zd\n", len);
                memcpy(priv->ucode_init.v_addr, src, len);
+               src += len;
        }
 
        /* Initialization data (4th block) */
        if (init_data_size) {
-               src = &ucode->data[inst_size + data_size + init_size];
-               len = priv->ucode_init_data.len;
+               len = init_data_size;
                IWL_DEBUG_INFO(priv,
                        "Copying (but not loading) init data len %zd\n", len);
                memcpy(priv->ucode_init_data.v_addr, src, len);
+               src += len;
        }
 
        /* Bootstrap instructions (5th block) */
-       src = &ucode->data[inst_size + data_size + init_size + init_data_size];
-       len = priv->ucode_boot.len;
+       len = boot_size;
        IWL_DEBUG_INFO(priv,
                "Copying (but not loading) boot instr len %zd\n", len);
        memcpy(priv->ucode_boot.v_addr, src, len);
@@ -3305,13 +3308,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  * used for controlling the debug level.
  *
  * See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
  */
 static ssize_t show_debug_level(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       return sprintf(buf, "0x%08X\n", priv->debug_level);
+       return sprintf(buf, "0x%08X\n", iwl_debug_level);
 }
 static ssize_t store_debug_level(struct device *d,
                                struct device_attribute *attr,
@@ -3325,7 +3330,7 @@ static ssize_t store_debug_level(struct device *d,
        if (ret)
                IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
        else
-               priv->debug_level = val;
+               iwl_debug_level = val;
 
        return strnlen(buf, count);
 }
@@ -3947,15 +3952,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv = hw->priv;
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
-       if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
-            (iwl3945_mod_params.num_of_queues < IWL_MIN_NUM_QUEUES)) {
-               IWL_ERR(priv,
-                       "invalid queues_num, should be between %d and %d\n",
-                       IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
-               err = -EINVAL;
-               goto out_ieee80211_free_hw;
-       }
-
        /*
         * Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan.
@@ -3972,7 +3968,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv->inta_mask = CSR_INI_SET_MASK;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       priv->debug_level = iwl3945_mod_params.debug;
        atomic_set(&priv->restrict_refcnt, 0);
 #endif
 
@@ -4268,14 +4263,12 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
 module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
 MODULE_PARM_DESC(swcrypto,
                 "using software crypto (default 1 [software])\n");
-module_param_named(debug, iwl3945_mod_params.debug, uint, 0444);
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug, iwl_debug_level, uint, 0644);
 MODULE_PARM_DESC(debug, "debug output mask");
+#endif
 module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-
 module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
 MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
 
index 54bebba..3f5a08f 100644 (file)
@@ -158,34 +158,6 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
        return 0;
 }
 
-static int iwm_reset_profile(struct iwm_priv *iwm)
-{
-       int ret;
-
-       if (!iwm->umac_profile_active)
-               return 0;
-
-       /*
-        * If there is a current active profile, but no
-        * default key, it's not worth trying to associate again.
-        */
-       if (iwm->default_key < 0)
-               return 0;
-
-       /*
-        * Here we have an active profile, but a key setting changed.
-        * We thus have to invalidate the current profile, and push the
-        * new one. Keys will be pushed when association takes place.
-        */
-       ret = iwm_invalidate_mlme_profile(iwm);
-       if (ret < 0) {
-               IWM_ERR(iwm, "Couldn't invalidate profile\n");
-               return ret;
-       }
-
-       return iwm_send_mlme_profile(iwm);
-}
-
 static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                u8 key_index, const u8 *mac_addr,
                                struct key_params *params)
@@ -203,32 +175,6 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                return ret;
        }
 
-       /*
-        * The WEP keys can be set before or after setting the essid.
-        * We need to handle both cases by simply pushing the keys after
-        * we send the profile.
-        * If the profile is not set yet (i.e. we're pushing keys before
-        * the essid), we set the cipher appropriately.
-        * If the profile is set, we havent associated yet because our
-        * cipher was incorrectly set. So we invalidate and send the
-        * profile again.
-        */
-       if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-           key->cipher == WLAN_CIPHER_SUITE_WEP104) {
-               u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
-               u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
-
-               IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
-
-               if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
-                       *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
-               if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
-                       *ucast_cipher = *mcast_cipher =
-                               UMAC_CIPHER_TYPE_WEP_104;
-
-               return iwm_reset_profile(iwm);
-       }
-
        return iwm_set_key(iwm, 0, key);
 }
 
@@ -271,10 +217,6 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
        if (key_index == iwm->default_key)
                iwm->default_key = -1;
 
-       /* If the interface is down, we just cache this */
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return 0;
-
        return iwm_set_key(iwm, 1, key);
 }
 
@@ -283,7 +225,6 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
                                        u8 key_index)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       int ret;
 
        IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
 
@@ -294,15 +235,26 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 
        iwm->default_key = key_index;
 
-       /* If the interface is down, we just cache this */
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return 0;
+       return iwm_set_tx_key(iwm, key_index);
+}
 
-       ret = iwm_set_tx_key(iwm, key_index);
-       if (ret < 0)
-               return ret;
+int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+                            u8 *mac, struct station_info *sinfo)
+{
+       struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+       if (memcmp(mac, iwm->bssid, ETH_ALEN))
+               return -ENOENT;
 
-       return iwm_reset_profile(iwm);
+       sinfo->filled |= STATION_INFO_TX_BITRATE;
+       sinfo->txrate.legacy = iwm->rate * 10;
+
+       if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->signal = iwm->wstats.qual.level;
+       }
+
+       return 0;
 }
 
 
@@ -500,6 +452,179 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return 0;
 }
 
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+                            enum nl80211_auth_type sme_auth_type)
+{
+       u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+       switch (sme_auth_type) {
+       case NL80211_AUTHTYPE_AUTOMATIC:
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+               IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+               *auth_type = UMAC_AUTH_TYPE_OPEN;
+               break;
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               if (iwm->umac_profile->sec.flags &
+                   (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+                       IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+                       *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+               } else {
+                       IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+                       *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+               }
+
+               break;
+       default:
+               IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+       if (!wpa_version) {
+               iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+               return 0;
+       }
+
+       if (wpa_version & NL80211_WPA_VERSION_2)
+               iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+       if (wpa_version & NL80211_WPA_VERSION_1)
+               iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+       return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+       u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+               &iwm->umac_profile->sec.mcast_cipher;
+
+       if (!cipher) {
+               *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+               return 0;
+       }
+
+       switch (cipher) {
+       case IW_AUTH_CIPHER_NONE:
+               *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+               break;
+       case WLAN_CIPHER_SUITE_WEP40:
+               *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+               break;
+       default:
+               IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+       u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+       IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+       if (key_mgt == WLAN_AKM_SUITE_8021X)
+               *auth_type = UMAC_AUTH_TYPE_8021X;
+       else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+               if (iwm->umac_profile->sec.flags &
+                   (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+                       *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+               else
+                       *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+       } else {
+               IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+                                struct cfg80211_connect_params *sme)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+       struct ieee80211_channel *chan = sme->channel;
+       int ret;
+
+       if (!test_bit(IWM_STATUS_READY, &iwm->status))
+               return -EIO;
+
+       if (!sme->ssid)
+               return -EINVAL;
+
+       if (chan)
+               iwm->channel =
+                       ieee80211_frequency_to_channel(chan->center_freq);
+
+       iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+       memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+       if (sme->bssid) {
+               IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+               memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+               iwm->umac_profile->bss_num = 1;
+       } else {
+               memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+               iwm->umac_profile->bss_num = 0;
+       }
+
+       ret = iwm_set_auth_type(iwm, sme->auth_type);
+       if (ret < 0)
+               return ret;
+
+       ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+       if (ret < 0)
+               return ret;
+
+       if (sme->crypto.n_ciphers_pairwise) {
+               ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+                                    true);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+       if (ret < 0)
+               return ret;
+
+       if (sme->crypto.n_akm_suites) {
+               ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+                                  u16 reason_code)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+       IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+       if (iwm->umac_profile_active)
+               return iwm_invalidate_mlme_profile(iwm);
+
+       return 0;
+}
+
 static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
                                    enum tx_power_setting type, int dbm)
 {
@@ -549,8 +674,11 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
        .get_key = iwm_cfg80211_get_key,
        .del_key = iwm_cfg80211_del_key,
        .set_default_key = iwm_cfg80211_set_default_key,
+       .get_station = iwm_cfg80211_get_station,
        .scan = iwm_cfg80211_scan,
        .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+       .connect = iwm_cfg80211_connect,
+       .disconnect = iwm_cfg80211_disconnect,
        .join_ibss = iwm_cfg80211_join_ibss,
        .leave_ibss = iwm_cfg80211_leave_ibss,
        .set_tx_power = iwm_cfg80211_set_txpower,
@@ -558,6 +686,13 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
        .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
 };
 
+static const u32 cipher_suites[] = {
+       WLAN_CIPHER_SUITE_WEP40,
+       WLAN_CIPHER_SUITE_WEP104,
+       WLAN_CIPHER_SUITE_TKIP,
+       WLAN_CIPHER_SUITE_CCMP,
+};
+
 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
 {
        int ret = 0;
@@ -600,6 +735,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
        wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
        wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
+       wdev->wiphy->cipher_suites = cipher_suites;
+       wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
        ret = wiphy_register(wdev->wiphy);
        if (ret < 0) {
                dev_err(dev, "Couldn't register wiphy device\n");
index 0d35afe..0d66370 100644 (file)
@@ -87,8 +87,7 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
                                   test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
                                   3 * HZ);
 
-               if (!ret)
-                       ret = -EBUSY;
+               return ret ? 0 : -EBUSY;
        }
 
        return ret;
@@ -480,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
        target_cmd.eop = 1;
 
        ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
-       if (ret < 0)
+       if (ret < 0) {
                IWM_ERR(iwm, "Couldn't send READ command\n");
+               return ret;
+       }
 
        /* When succeding, the send_target routine returns the seq number */
        seq_num = ret;
@@ -501,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
 
        kfree(cmd);
 
-       return ret;
+       return 0;
 }
 
 int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -511,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
 
        ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
                              mac_align, sizeof(mac_align));
-       if (ret < 0)
+       if (ret)
                return ret;
 
        if (is_valid_ether_addr(mac_align))
@@ -583,12 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
        struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
        struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
 
-       /*
-        * We check if our current profile is valid.
-        * If not, we dont push the key, we just cache them,
-        * so that with the next siwsessid call, the keys
-        * will be actually pushed.
-        */
        if (!remove) {
                ret = iwm_check_profile(iwm);
                if (ret < 0)
@@ -714,7 +709,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
                ret =  iwm_send_wifi_if_cmd(iwm, &key_remove,
                                            sizeof(struct iwm_umac_key_remove),
                                            1);
-               if (ret < 0)
+               if (ret)
                        return ret;
 
                iwm->keys[key_idx].key_len = 0;
@@ -726,7 +721,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
 
 int iwm_send_mlme_profile(struct iwm_priv *iwm)
 {
-       int ret, i;
+       int ret;
        struct iwm_umac_profile profile;
 
        memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -736,32 +731,11 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
                                           sizeof(struct iwm_umac_wifi_if));
 
        ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
-       if (ret < 0) {
+       if (ret) {
                IWM_ERR(iwm, "Send profile command failed\n");
                return ret;
        }
 
-       for (i = 0; i < IWM_NUM_KEYS; i++)
-               if (iwm->keys[i].key_len) {
-                       struct iwm_key *key = &iwm->keys[i];
-
-                       /* Wait for the profile before sending the keys */
-                       wait_event_interruptible_timeout(iwm->mlme_queue,
-                            (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
-                             test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
-                                                        3 * HZ);
-
-                       ret = iwm_set_key(iwm, 0, key);
-                       if (ret < 0)
-                               return ret;
-
-                       if (iwm->default_key == i) {
-                               ret = iwm_set_tx_key(iwm, i);
-                               if (ret < 0)
-                                       return ret;
-                       }
-               }
-
        return 0;
 }
 
@@ -778,15 +752,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
        invalid.reason = WLAN_REASON_UNSPECIFIED;
 
        ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
-       if (ret < 0)
+       if (ret)
                return ret;
 
        ret = wait_event_interruptible_timeout(iwm->mlme_queue,
                                (iwm->umac_profile_active == 0), 2 * HZ);
-       if (!ret)
-               return -EBUSY;
 
-       return 0;
+       return ret ? 0 : -EBUSY;
 }
 
 int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@@ -869,7 +841,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
        }
 
        ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
-       if (ret < 0) {
+       if (ret) {
                IWM_ERR(iwm, "Couldn't send scan request\n");
                return ret;
        }
index ee127fe..c430418 100644 (file)
 #include "umac.h"
 #include "debug.h"
 
-static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
-                                struct iwm_nonwifi_cmd *cmd,
-                                struct iwm_udma_nonwifi_cmd *udma_cmd)
+static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
+                               struct iwm_nonwifi_cmd *cmd,
+                               struct iwm_udma_nonwifi_cmd *udma_cmd)
 {
        INIT_LIST_HEAD(&cmd->pending);
 
@@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
        cmd->seq_num = iwm->nonwifi_seq_num;
        udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
 
-       cmd->seq_num = iwm->nonwifi_seq_num++;
+       iwm->nonwifi_seq_num++;
        iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
 
        if (udma_cmd->resp)
@@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
        cmd->buf.len = 0;
 
        memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+
+       return cmd->seq_num;
 }
 
 u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
                            const void *payload)
 {
        struct iwm_nonwifi_cmd *cmd;
-       int ret;
+       int ret, seq_num;
 
        cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
        if (!cmd) {
@@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
                return -ENOMEM;
        }
 
-       iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
+       seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
 
        if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
            cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
        if (ret < 0)
                return ret;
 
-       return cmd->seq_num;
+       return seq_num;
 }
 
 static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
index 79d9d89..2175a48 100644 (file)
@@ -281,6 +281,11 @@ struct iwm_priv {
        struct work_struct reset_worker;
        struct mutex mutex;
 
+       u8 *req_ie;
+       int req_ie_len;
+       u8 *resp_ie;
+       int resp_ie_len;
+
        char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
 
index 484f110..cf25744 100644 (file)
@@ -497,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm)
        memset(wstats, 0, sizeof(struct iw_statistics));
        wstats->qual.updated = IW_QUAL_ALL_INVALID;
 
+       kfree(iwm->req_ie);
+       iwm->req_ie = NULL;
+       iwm->req_ie_len = 0;
+       kfree(iwm->resp_ie);
+       iwm->resp_ie = NULL;
+       iwm->resp_ie_len = 0;
+
        del_timer_sync(&iwm->watchdog);
 }
 
index 3909477..86079a1 100644 (file)
@@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
        error = (struct iwm_umac_notif_error *)buf;
        fw_err = &error->err;
 
-
        IWM_ERR(iwm, "%cMAC FW ERROR:\n",
         (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
        IWM_ERR(iwm, "\tCategory:    %d\n", le32_to_cpu(fw_err->category));
@@ -219,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
                (buf + sizeof(struct iwm_umac_wifi_in_hdr));
        hdr = (struct iwm_umac_wifi_in_hdr *)buf;
 
-       IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+       IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
 
-       IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
-                   le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
-       IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
-       IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
-                   le16_to_cpu(tx_resp->retry_cnt));
-       IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
-       IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
-                   le16_to_cpu(tx_resp->byte_cnt));
-       IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+       IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
+                  le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+       IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+       IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
+                  le16_to_cpu(tx_resp->retry_cnt));
+       IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+       IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
+                  le16_to_cpu(tx_resp->byte_cnt));
+       IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
 
        return 0;
 }
@@ -419,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
                        if (IS_ERR(ticket_node))
                                return PTR_ERR(ticket_node);
 
-                       IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
-                                   ticket->id);
+                       IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+                                  ticket->id);
                        list_add_tail(&ticket_node->node, &iwm->rx_tickets);
 
                        /*
@@ -455,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
        u16 id, buf_offset;
        u32 packet_size;
 
-       IWM_DBG_NTF(iwm, DBG, "\n");
+       IWM_DBG_RX(iwm, DBG, "\n");
 
        wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
        id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
        buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
        packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
 
-       IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
-                   wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+       IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+                  wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
        IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
        IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
 
@@ -504,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 {
        struct iwm_umac_notif_assoc_complete *complete =
                (struct iwm_umac_notif_assoc_complete *)buf;
-       union iwreq_data wrqu;
 
        IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
                     complete->bssid, complete->status);
 
-       memset(&wrqu, 0, sizeof(wrqu));
-
        clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
 
        switch (le32_to_cpu(complete->status)) {
@@ -521,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 
                iwm_link_on(iwm);
 
-               memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+               if (iwm->conf.mode == UMAC_MODE_IBSS)
+                       goto ibss;
+
+               cfg80211_connect_result(iwm_to_ndev(iwm),
+                                       complete->bssid,
+                                       iwm->req_ie, iwm->req_ie_len,
+                                       iwm->resp_ie, iwm->resp_ie_len,
+                                       WLAN_STATUS_SUCCESS, GFP_KERNEL);
                break;
        case UMAC_ASSOC_COMPLETE_FAILURE:
                clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -529,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                iwm->channel = 0;
 
                iwm_link_off(iwm);
+
+               if (iwm->conf.mode == UMAC_MODE_IBSS)
+                       goto ibss;
+
+               cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
+                                       NULL, 0, NULL, 0,
+                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                       GFP_KERNEL);
        default:
                break;
        }
 
-       if (iwm->conf.mode == UMAC_MODE_IBSS) {
-               cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
-               return 0;
-       }
-
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
+       return 0;
 
+ ibss:
+       cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
        return 0;
 }
 
@@ -770,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
                              unsigned long buf_size, struct iwm_wifi_cmd *cmd)
 {
        struct iwm_umac_notif_mgt_frame *mgt_frame =
-       (struct iwm_umac_notif_mgt_frame *)buf;
+                       (struct iwm_umac_notif_mgt_frame *)buf;
        struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
        u8 *ie;
-       unsigned int event;
-       union iwreq_data wrqu;
 
        IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
                    le16_to_cpu(mgt_frame->len));
 
        if (ieee80211_is_assoc_req(mgt->frame_control)) {
                ie = mgt->u.assoc_req.variable;;
-               event = IWEVASSOCREQIE;
+               iwm->req_ie_len =
+                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               kfree(iwm->req_ie);
+               iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
+                                     iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
                ie = mgt->u.reassoc_req.variable;;
-               event = IWEVASSOCREQIE;
+               iwm->req_ie_len =
+                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               kfree(iwm->req_ie);
+               iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
+                                     iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
                ie = mgt->u.assoc_resp.variable;;
-               event = IWEVASSOCRESPIE;
+               iwm->resp_ie_len =
+                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               kfree(iwm->resp_ie);
+               iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
+                                      iwm->resp_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
                ie = mgt->u.reassoc_resp.variable;;
-               event = IWEVASSOCRESPIE;
+               iwm->resp_ie_len =
+                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               kfree(iwm->resp_ie);
+               iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
+                                      iwm->resp_ie_len, GFP_KERNEL);
        } else {
                IWM_ERR(iwm, "Unsupported management frame");
                return 0;
        }
 
-       wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
-
-       IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
-       wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
-
        return 0;
 }
 
@@ -1360,7 +1376,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
 
                skb->dev = iwm_to_ndev(iwm);
                skb->protocol = eth_type_trans(skb, ndev);
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               skb->ip_summed = CHECKSUM_NONE;
                memset(skb->cb, 0, sizeof(skb->cb));
 
                ndev->stats.rx_packets++;
index 0af2a3c..c5a14ae 100644 (file)
@@ -615,6 +615,7 @@ struct iwm_umac_notif_alive {
 } __attribute__ ((packed));
 
 struct iwm_umac_notif_init_complete {
+       struct iwm_umac_wifi_in_hdr hdr;
        __le16 status;
        __le16 reserved;
 } __attribute__ ((packed));
@@ -643,6 +644,11 @@ struct iwm_fw_error_hdr {
        __le32 umac_status;
        __le32 lmac_status;
        __le32 sdio_status;
+       __le32 dbm_sample_ctrl;
+       __le32 dbm_buf_base;
+       __le32 dbm_buf_end;
+       __le32 dbm_buf_write_ptr;
+       __le32 dbm_buf_cycle_cnt;
 } __attribute__ ((packed));
 
 struct iwm_umac_notif_error {
index 2e7eaf9..c3c90d5 100644 (file)
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
 #include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
 #include <net/cfg80211.h>
-#include <net/iw_handler.h>
 
 #include "iwm.h"
-#include "umac.h"
 #include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-       struct iw_statistics *wstats = &iwm->wstats;
-
-       if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
-               memset(wstats, 0, sizeof(struct iw_statistics));
-               wstats->qual.updated = IW_QUAL_ALL_INVALID;
-       }
-
-       return wstats;
-}
 
 static int iwm_wext_siwfreq(struct net_device *dev,
                            struct iw_request_info *info,
@@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev,
 {
        struct iwm_priv *iwm = ndev_to_iwm(dev);
 
-       if (freq->flags == IW_FREQ_AUTO)
-               return 0;
-
-       /* frequency/channel can only be set in IBSS mode */
-       if (iwm->conf.mode != UMAC_MODE_IBSS)
+       switch (iwm->conf.mode) {
+       case UMAC_MODE_IBSS:
+               return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+       default:
                return -EOPNOTSUPP;
-
-       return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+       }
 }
 
 static int iwm_wext_giwfreq(struct net_device *dev,
@@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_device *dev,
 {
        struct iwm_priv *iwm = ndev_to_iwm(dev);
 
-       if (iwm->conf.mode == UMAC_MODE_IBSS)
+       switch (iwm->conf.mode) {
+       case UMAC_MODE_IBSS:
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
-       freq->e = 0;
-       freq->m = iwm->channel;
-
-       return 0;
+       case UMAC_MODE_BSS:
+               return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
                          struct sockaddr *ap_addr, char *extra)
 {
        struct iwm_priv *iwm = ndev_to_iwm(dev);
-       int ret;
-
-       IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
 
-       if (iwm->conf.mode == UMAC_MODE_IBSS)
+       switch (iwm->conf.mode) {
+       case UMAC_MODE_IBSS:
                return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return -EIO;
-
-       if (is_zero_ether_addr(ap_addr->sa_data) ||
-           is_broadcast_ether_addr(ap_addr->sa_data)) {
-               IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
-                            iwm->umac_profile->bssid[0]);
-               memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
-               iwm->umac_profile->bss_num = 0;
-       } else {
-               IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
-                            ap_addr->sa_data);
-               memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
-                      ETH_ALEN);
-               iwm->umac_profile->bss_num = 1;
-       }
-
-       if (iwm->umac_profile_active) {
-               int i;
-
-               if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
-                       return 0;
-
-               /*
-                * If we're clearing the BSSID, and we're associated,
-                * we have to clear the keys as they're no longer valid.
-                */
-               if (is_zero_ether_addr(ap_addr->sa_data)) {
-                       for (i = 0; i < IWM_NUM_KEYS; i++)
-                               iwm->keys[i].key_len = 0;
-               }
-
-               ret = iwm_invalidate_mlme_profile(iwm);
-               if (ret < 0) {
-                       IWM_ERR(iwm, "Couldn't invalidate profile\n");
-                       return ret;
-               }
+       case UMAC_MODE_BSS:
+               return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+       default:
+               return -EOPNOTSUPP;
        }
-
-       if (iwm->umac_profile->ssid.ssid_len)
-               return iwm_send_mlme_profile(iwm);
-
-       return 0;
 }
 
 static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
@@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
        case UMAC_MODE_IBSS:
                return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
        case UMAC_MODE_BSS:
-               if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
-                       ap_addr->sa_family = ARPHRD_ETHER;
-                       memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
-               } else
-                       memset(&ap_addr->sa_data, 0, ETH_ALEN);
-               break;
+               return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
        default:
                return -EOPNOTSUPP;
        }
-
-       return 0;
 }
 
 static int iwm_wext_siwessid(struct net_device *dev,
@@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev,
                             struct iw_point *data, char *ssid)
 {
        struct iwm_priv *iwm = ndev_to_iwm(dev);
-       size_t len = data->length;
-       int ret;
-
-       IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
 
-       if (iwm->conf.mode == UMAC_MODE_IBSS)
+       switch (iwm->conf.mode) {
+       case UMAC_MODE_IBSS:
                return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return -EIO;
-
-       if (len > 0 && ssid[len - 1] == '\0')
-               len--;
-
-       if (iwm->umac_profile_active) {
-               if (iwm->umac_profile->ssid.ssid_len == len &&
-                   !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
-                       return 0;
-
-               ret = iwm_invalidate_mlme_profile(iwm);
-               if (ret < 0) {
-                       IWM_ERR(iwm, "Couldn't invalidate profile\n");
-                       return ret;
-               }
+       case UMAC_MODE_BSS:
+               return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+       default:
+               return -EOPNOTSUPP;
        }
-
-       iwm->umac_profile->ssid.ssid_len = len;
-       memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
-       return iwm_send_mlme_profile(iwm);
 }
 
 static int iwm_wext_giwessid(struct net_device *dev,
@@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev,
 {
        struct iwm_priv *iwm = ndev_to_iwm(dev);
 
-       if (iwm->conf.mode == UMAC_MODE_IBSS)
+       switch (iwm->conf.mode) {
+       case UMAC_MODE_IBSS:
                return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return -EIO;
-
-       data->length = iwm->umac_profile->ssid.ssid_len;
-       if (data->length) {
-               memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
-               data->flags = 1;
-       } else
-               data->flags = 0;
-
-       return 0;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
-                           struct iw_request_info *info,
-                           struct iw_param *rate, char *extra)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-
-       rate->value = iwm->rate * 1000000;
-
-       return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
-       if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
-               iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
-       else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
-               iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
-       else
-               iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
-       return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
-       u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
-       IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
-
-       if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
-               *auth_type = UMAC_AUTH_TYPE_8021X;
-       else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
-               if (iwm->umac_profile->sec.flags &
-                   (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
-                       *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
-               else
-                       *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
-       } else {
-               IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
-       u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
-               &iwm->umac_profile->sec.mcast_cipher;
-
-       switch (cipher) {
-       case IW_AUTH_CIPHER_NONE:
-               *profile_cipher = UMAC_CIPHER_TYPE_NONE;
-               break;
-       case IW_AUTH_CIPHER_WEP40:
-               *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
-               break;
-       case IW_AUTH_CIPHER_TKIP:
-               *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
-               break;
-       case IW_AUTH_CIPHER_CCMP:
-               *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
-               break;
-       case IW_AUTH_CIPHER_WEP104:
-               *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
-               break;
-       default:
-               IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
-               return -ENOTSUPP;
-       }
-
-       return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
-       u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
-       IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
-
-       switch (auth_alg) {
-       case IW_AUTH_ALG_OPEN_SYSTEM:
-               *auth_type = UMAC_AUTH_TYPE_OPEN;
-               break;
-       case IW_AUTH_ALG_SHARED_KEY:
-               if (iwm->umac_profile->sec.flags &
-                   (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
-                       if (*auth_type == UMAC_AUTH_TYPE_8021X)
-                               return -EINVAL;
-                       *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
-               } else {
-                       IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
-                       *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
-               }
-               break;
-       case IW_AUTH_ALG_LEAP:
-       default:
-               IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
-               return -ENOTSUPP;
-       }
-
-       return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
-                           struct iw_request_info *info,
-                           struct iw_param *data, char *extra)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-       int ret;
-
-       if ((data->flags) &
-           (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
-            IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
-               /* We need to invalidate the current profile */
-               if (iwm->umac_profile_active) {
-                       ret = iwm_invalidate_mlme_profile(iwm);
-                       if (ret < 0) {
-                               IWM_ERR(iwm, "Couldn't invalidate profile\n");
-                               return ret;
-                       }
-               }
-       }
-
-       switch (data->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-               return iwm_set_wpa_version(iwm, data->value);
-               break;
-       case IW_AUTH_CIPHER_PAIRWISE:
-               return iwm_set_cipher(iwm, data->value, 1);
-               break;
-       case IW_AUTH_CIPHER_GROUP:
-               return iwm_set_cipher(iwm, data->value, 0);
-               break;
-       case IW_AUTH_KEY_MGMT:
-               return iwm_set_key_mgt(iwm, data->value);
-               break;
-       case IW_AUTH_80211_AUTH_ALG:
-               return iwm_set_auth_alg(iwm, data->value);
-               break;
+       case UMAC_MODE_BSS:
+               return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
        default:
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
-
-       return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
-                           struct iw_request_info *info,
-                           struct iw_param *data, char *extra)
-{
-       return 0;
 }
 
 static const iw_handler iwm_handlers[] =
@@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] =
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* SIOCSIWRATE */
-       (iw_handler) iwm_wext_giwrate,                  /* SIOCGIWRATE */
+       (iw_handler) cfg80211_wext_giwrate,             /* SIOCGIWRATE */
        (iw_handler) cfg80211_wext_siwrts,              /* SIOCSIWRTS */
        (iw_handler) cfg80211_wext_giwrts,              /* SIOCGIWRTS */
        (iw_handler) cfg80211_wext_siwfrag,             /* SIOCSIWFRAG */
@@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] =
        (iw_handler) cfg80211_wext_giwpower,            /* SIOCGIWPOWER */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* -- hole -- */
-       (iw_handler) NULL,                              /* SIOCSIWGENIE */
+       (iw_handler) cfg80211_wext_siwgenie,            /* SIOCSIWGENIE */
        (iw_handler) NULL,                              /* SIOCGIWGENIE */
-       (iw_handler) iwm_wext_siwauth,                  /* SIOCSIWAUTH */
-       (iw_handler) iwm_wext_giwauth,                  /* SIOCGIWAUTH */
+       (iw_handler) cfg80211_wext_siwauth,             /* SIOCSIWAUTH */
+       (iw_handler) cfg80211_wext_giwauth,             /* SIOCGIWAUTH */
        (iw_handler) cfg80211_wext_siwencodeext,        /* SIOCSIWENCODEEXT */
        (iw_handler) NULL,                              /* SIOCGIWENCODEEXT */
        (iw_handler) NULL,                              /* SIOCSIWPMKSA */
@@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] =
 const struct iw_handler_def iwm_iw_handler_def = {
        .num_standard   = ARRAY_SIZE(iwm_handlers),
        .standard       = (iw_handler *) iwm_handlers,
-       .get_wireless_stats = iwm_get_wireless_stats,
+       .get_wireless_stats = cfg80211_wireless_stats,
 };
 
index fbf2649..385b50f 100644 (file)
@@ -129,7 +129,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
 {
        struct cmd_ds_802_11_authenticate cmd;
        int ret = -1;
-       DECLARE_MAC_BUF(mac);
 
        lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -138,8 +137,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
 
        cmd.authtype = iw_auth_to_ieee_auth(auth);
 
-       lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
-               print_mac(mac, bssid), cmd.authtype);
+       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);
 
@@ -342,8 +340,6 @@ static int lbs_associate(struct lbs_private *priv,
 
        /* Firmware v9+ indicate authentication suites as a TLV */
        if (priv->fwrelease >= 0x09000000) {
-               DECLARE_MAC_BUF(mac);
-
                auth = (struct mrvl_ie_auth_type *) pos;
                auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
                auth->header.len = cpu_to_le16(2);
@@ -351,8 +347,8 @@ static int lbs_associate(struct lbs_private *priv,
                auth->auth = cpu_to_le16(tmpauth);
                pos += sizeof(auth->header) + 2;
 
-               lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
-                       print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
+               lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+                       bss->bssid, priv->secinfo.auth_mode);
        }
 
        /* WPA/WPA2 IEs */
index e9b5442..930f5c7 100644 (file)
@@ -406,7 +406,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
        rx_status.freq = data->channel->center_freq;
        rx_status.band = data->channel->band;
        rx_status.rate_idx = info->control.rates[0].idx;
-       /* TODO: simulate signal strength (and optional packet drop) */
+       /* TODO: simulate real signal strength (and optional packet loss) */
+       rx_status.signal = -50;
 
        if (data->ps != PS_DISABLED)
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@@ -836,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
 {
        struct mac80211_hwsim_data *data = dat;
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-       DECLARE_MAC_BUF(buf);
        struct sk_buff *skb;
        struct ieee80211_pspoll *pspoll;
 
@@ -866,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
                                struct ieee80211_vif *vif, int ps)
 {
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-       DECLARE_MAC_BUF(buf);
        struct sk_buff *skb;
        struct ieee80211_hdr *hdr;
 
@@ -1024,7 +1023,8 @@ static int __init init_mac80211_hwsim(void)
                        BIT(NL80211_IFTYPE_AP) |
                        BIT(NL80211_IFTYPE_MESH_POINT);
 
-               hw->flags = IEEE80211_HW_MFP_CAPABLE;
+               hw->flags = IEEE80211_HW_MFP_CAPABLE |
+                           IEEE80211_HW_SIGNAL_DBM;
 
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
index b9eded8..4f72547 100644 (file)
@@ -2271,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
        struct mwl8k_cmd_update_sta_db *cmd;
        struct peer_capability_info *peer_info;
        struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
-       DECLARE_MAC_BUF(mac);
        int rc;
        __u8 count, *rates;
 
@@ -3480,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 {
        struct ieee80211_hw *hw;
        struct mwl8k_priv *priv;
-       DECLARE_MAC_BUF(mac);
        int rc;
        int i;
        u8 *fw;
@@ -3669,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
                MWL8K_DESC);
        printk(KERN_INFO "%s: Driver Ver:%s  Firmware Ver:%u.%u.%u.%u\n",
                priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
-       printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
-              print_mac(mac, hw->wiphy->perm_addr));
+       printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
+               hw->wiphy->perm_addr);
 
        return 0;
 
index a2a044e..0efe67d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
+#include <linux/sort.h>
 
 #include <net/mac80211.h>
 
@@ -41,30 +42,6 @@ static struct ieee80211_rate p54_bgrates[] = {
        { .bitrate = 540, .hw_value = 11, },
 };
 
-static struct ieee80211_channel p54_bgchannels[] = {
-       { .center_freq = 2412, .hw_value = 1, },
-       { .center_freq = 2417, .hw_value = 2, },
-       { .center_freq = 2422, .hw_value = 3, },
-       { .center_freq = 2427, .hw_value = 4, },
-       { .center_freq = 2432, .hw_value = 5, },
-       { .center_freq = 2437, .hw_value = 6, },
-       { .center_freq = 2442, .hw_value = 7, },
-       { .center_freq = 2447, .hw_value = 8, },
-       { .center_freq = 2452, .hw_value = 9, },
-       { .center_freq = 2457, .hw_value = 10, },
-       { .center_freq = 2462, .hw_value = 11, },
-       { .center_freq = 2467, .hw_value = 12, },
-       { .center_freq = 2472, .hw_value = 13, },
-       { .center_freq = 2484, .hw_value = 14, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
-       .channels = p54_bgchannels,
-       .n_channels = ARRAY_SIZE(p54_bgchannels),
-       .bitrates = p54_bgrates,
-       .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
 static struct ieee80211_rate p54_arates[] = {
        { .bitrate = 60, .hw_value = 4, },
        { .bitrate = 90, .hw_value = 5, },
@@ -76,51 +53,257 @@ static struct ieee80211_rate p54_arates[] = {
        { .bitrate = 540, .hw_value = 11, },
 };
 
-static struct ieee80211_channel p54_achannels[] = {
-       { .center_freq = 4920 },
-       { .center_freq = 4940 },
-       { .center_freq = 4960 },
-       { .center_freq = 4980 },
-       { .center_freq = 5040 },
-       { .center_freq = 5060 },
-       { .center_freq = 5080 },
-       { .center_freq = 5170 },
-       { .center_freq = 5180 },
-       { .center_freq = 5190 },
-       { .center_freq = 5200 },
-       { .center_freq = 5210 },
-       { .center_freq = 5220 },
-       { .center_freq = 5230 },
-       { .center_freq = 5240 },
-       { .center_freq = 5260 },
-       { .center_freq = 5280 },
-       { .center_freq = 5300 },
-       { .center_freq = 5320 },
-       { .center_freq = 5500 },
-       { .center_freq = 5520 },
-       { .center_freq = 5540 },
-       { .center_freq = 5560 },
-       { .center_freq = 5580 },
-       { .center_freq = 5600 },
-       { .center_freq = 5620 },
-       { .center_freq = 5640 },
-       { .center_freq = 5660 },
-       { .center_freq = 5680 },
-       { .center_freq = 5700 },
-       { .center_freq = 5745 },
-       { .center_freq = 5765 },
-       { .center_freq = 5785 },
-       { .center_freq = 5805 },
-       { .center_freq = 5825 },
+#define CHAN_HAS_CAL           BIT(0)
+#define CHAN_HAS_LIMIT         BIT(1)
+#define CHAN_HAS_CURVE         BIT(2)
+#define CHAN_HAS_ALL           (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+       u16 freq;
+       u16 data;
+       int index;
+       enum ieee80211_band band;
 };
 
-static struct ieee80211_supported_band band_5GHz = {
-       .channels = p54_achannels,
-       .n_channels = ARRAY_SIZE(p54_achannels),
-       .bitrates = p54_arates,
-       .n_bitrates = ARRAY_SIZE(p54_arates),
+struct p54_channel_list {
+       struct p54_channel_entry *channels;
+       size_t entries;
+       size_t max_entries;
+       size_t band_channel_num[IEEE80211_NUM_BANDS];
 };
 
+static int p54_get_band_from_freq(u16 freq)
+{
+       /* FIXME: sync these values with the 802.11 spec */
+
+       if ((freq >= 2412) && (freq <= 2484))
+               return IEEE80211_BAND_2GHZ;
+
+       if ((freq >= 4920) && (freq <= 5825))
+               return IEEE80211_BAND_5GHZ;
+
+       return -1;
+}
+
+static int p54_compare_channels(const void *_a,
+                               const void *_b)
+{
+       const struct p54_channel_entry *a = _a;
+       const struct p54_channel_entry *b = _b;
+
+       return a->index - b->index;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+                                 struct ieee80211_supported_band *band_entry,
+                                 enum ieee80211_band band)
+{
+       /* TODO: generate rate array dynamically */
+
+       switch (band) {
+       case IEEE80211_BAND_2GHZ:
+               band_entry->bitrates = p54_bgrates;
+               band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+               break;
+       case IEEE80211_BAND_5GHZ:
+               band_entry->bitrates = p54_arates;
+               band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+                            struct p54_channel_list *list,
+                            enum ieee80211_band band)
+{
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_supported_band *tmp, *old;
+       unsigned int i, j;
+       int ret = -ENOMEM;
+
+       if ((!list->entries) || (!list->band_channel_num[band]))
+               return 0;
+
+       tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               goto err_out;
+
+       tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+                               list->band_channel_num[band], GFP_KERNEL);
+       if (!tmp->channels)
+               goto err_out;
+
+       ret = p54_fill_band_bitrates(dev, tmp, band);
+       if (ret)
+               goto err_out;
+
+       for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+                          (i < list->entries); i++) {
+
+               if (list->channels[i].band != band)
+                       continue;
+
+               if (list->channels[i].data != CHAN_HAS_ALL) {
+                       printk(KERN_ERR "%s:%s%s%s is/are missing for "
+                                       "channel:%d [%d MHz].\n",
+                              wiphy_name(dev->wiphy),
+                              (list->channels[i].data & CHAN_HAS_CAL ? "" :
+                               " [iqauto calibration data]"),
+                              (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+                               " [output power limits]"),
+                              (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+                               " [curve data]"),
+                              list->channels[i].index, list->channels[i].freq);
+               }
+
+               tmp->channels[j].band = list->channels[i].band;
+               tmp->channels[j].center_freq = list->channels[i].freq;
+               j++;
+       }
+
+       tmp->n_channels = list->band_channel_num[band];
+       old = priv->band_table[band];
+       priv->band_table[band] = tmp;
+       if (old) {
+               kfree(old->channels);
+               kfree(old);
+       }
+
+       return 0;
+
+err_out:
+       if (tmp) {
+               kfree(tmp->channels);
+               kfree(tmp);
+       }
+
+       return ret;
+}
+
+static void p54_update_channel_param(struct p54_channel_list *list,
+                                    u16 freq, u16 data)
+{
+       int band, i;
+
+       /*
+        * usually all lists in the eeprom are mostly sorted.
+        * so it's very likely that the entry we are looking for
+        * is right at the end of the list
+        */
+       for (i = list->entries; i >= 0; i--) {
+               if (freq == list->channels[i].freq) {
+                       list->channels[i].data |= data;
+                       break;
+               }
+       }
+
+       if ((i < 0) && (list->entries < list->max_entries)) {
+               /* entry does not exist yet. Initialize a new one. */
+               band = p54_get_band_from_freq(freq);
+
+               /*
+                * filter out frequencies which don't belong into
+                * any supported band.
+                */
+               if (band < 0)
+                       return ;
+
+               i = list->entries++;
+               list->band_channel_num[band]++;
+
+               list->channels[i].freq = freq;
+               list->channels[i].data = data;
+               list->channels[i].band = band;
+               list->channels[i].index = ieee80211_frequency_to_channel(freq);
+               /* TODO: parse output_limit and fill max_power */
+       }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_channel_list *list;
+       unsigned int i, j, max_channel_num;
+       int ret = -ENOMEM;
+       u16 freq;
+
+       if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+           (priv->iq_autocal_len != priv->output_limit->entries))
+               printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
+                               "to use all channels with this device.\n",
+                               wiphy_name(dev->wiphy));
+
+       max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+                               priv->iq_autocal_len);
+       max_channel_num = max_t(unsigned int, max_channel_num,
+                               priv->curve_data->entries);
+
+       list = kzalloc(sizeof(*list), GFP_KERNEL);
+       if (!list)
+               goto free;
+
+       list->max_entries = max_channel_num;
+       list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+                                max_channel_num, GFP_KERNEL);
+       if (!list->channels)
+               goto free;
+
+       for (i = 0; i < max_channel_num; i++) {
+               if (i < priv->iq_autocal_len) {
+                       freq = le16_to_cpu(priv->iq_autocal[i].freq);
+                       p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+               }
+
+               if (i < priv->output_limit->entries) {
+                       freq = le16_to_cpup((__le16 *) (i *
+                                           priv->output_limit->entry_size +
+                                           priv->output_limit->offset +
+                                           priv->output_limit->data));
+
+                       p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+               }
+
+               if (i < priv->curve_data->entries) {
+                       freq = le16_to_cpup((__le16 *) (i *
+                                           priv->curve_data->entry_size +
+                                           priv->curve_data->offset +
+                                           priv->curve_data->data));
+
+                       p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+               }
+       }
+
+       /* sort the list by the channel index */
+       sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+            p54_compare_channels, NULL);
+
+       for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+               if (list->band_channel_num[i]) {
+                       ret = p54_generate_band(dev, list, i);
+                       if (ret)
+                               goto free;
+
+                       j++;
+               }
+       }
+       if (j == 0) {
+               /* no useable band available. */
+               ret = -EINVAL;
+       }
+
+free:
+       if (list) {
+               kfree(list->channels);
+               kfree(list);
+       }
+
+       return ret;
+}
+
 static int p54_convert_rev0(struct ieee80211_hw *dev,
                            struct pda_pa_curve_data *curve_data)
 {
@@ -346,7 +529,7 @@ static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
 int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 {
        struct p54_common *priv = dev->priv;
-       struct eeprom_pda_wrap *wrap = NULL;
+       struct eeprom_pda_wrap *wrap;
        struct pda_entry *entry;
        unsigned int data_len, entry_len;
        void *tmp;
@@ -487,13 +670,19 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
                goto err;
        }
 
+       err = p54_generate_channel_lists(dev);
+       if (err)
+               goto err;
+
        priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
        if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
                p54_init_xbow_synth(priv);
        if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
-               dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
+               dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       priv->band_table[IEEE80211_BAND_2GHZ];
        if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
-               dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
+               dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       priv->band_table[IEEE80211_BAND_5GHZ];
        if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
                priv->rx_diversity_mask = 3;
        if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
@@ -533,7 +722,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
        struct p54_common *priv = dev->priv;
        size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
        int ret = -ENOMEM;
-       void *eeprom = NULL;
+       void *eeprom;
 
        maxblocksize = EEPROM_READBACK_LEN;
        if (priv->fw_var >= 0x509)
index dc4f3f5..21f1901 100644 (file)
@@ -585,7 +585,8 @@ int p54_set_ps(struct p54_common *priv)
        unsigned int i;
        u16 mode;
 
-       if (priv->hw->conf.flags & IEEE80211_CONF_PS)
+       if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+           !priv->powersave_override)
                mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
                       P54_PSM_CHECKSUM | P54_PSM_MCBC;
        else
@@ -607,8 +608,8 @@ int p54_set_ps(struct p54_common *priv)
 
        psm->beacon_rssi_skip_max = 200;
        psm->rssi_delta_threshold = 0;
-       psm->nr = 10;
-       psm->exclude[0] = 0;
+       psm->nr = 1;
+       psm->exclude[0] = WLAN_EID_TIM;
 
        p54_tx(priv, skb);
        return 0;
@@ -685,6 +686,8 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
 
 int p54_fetch_statistics(struct p54_common *priv)
 {
+       struct ieee80211_tx_info *txinfo;
+       struct p54_tx_info *p54info;
        struct sk_buff *skb;
 
        skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
@@ -693,6 +696,20 @@ int p54_fetch_statistics(struct p54_common *priv)
        if (!skb)
                return -ENOMEM;
 
+       /*
+        * The statistic feedback causes some extra headaches here, if it
+        * is not to crash/corrupt the firmware data structures.
+        *
+        * Unlike all other Control Get OIDs we can not use helpers like
+        * skb_put to reserve the space for the data we're requesting.
+        * Instead the extra frame length -which will hold the results later-
+        * will only be told to the p54_assign_address, so that following
+        * frames won't be placed into the  allegedly empty area.
+        */
+       txinfo = IEEE80211_SKB_CB(skb);
+       p54info = (void *) txinfo->rate_driver_data;
+       p54info->extra_len = sizeof(struct p54_statistics);
+
        p54_tx(priv, skb);
        return 0;
 }
index 0496cff..04b63ec 100644 (file)
@@ -98,6 +98,10 @@ struct p54_hdr {
        (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->       \
        flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
 
+#define GET_HW_QUEUE(skb)                                              \
+       (((struct p54_tx_data *)((struct p54_hdr *)                     \
+       skb->data)->data)->hw_queue)
+
 /*
  * shared interface ID definitions
  * The interface ID is a unique identification of a specific interface.
@@ -548,4 +552,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
 int p54_download_eeprom(struct p54_common *priv, void *buf,
                        u16 offset, u16 len);
 
+/* utility */
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
+
 #endif /* LMAC_H */
index f9b4f6a..955f6d7 100644 (file)
@@ -65,51 +65,64 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
        return p54_update_beacon_tim(priv, sta->aid, set);
 }
 
-static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
 {
-       /*
-        * the good excuse for this mess is ... the firmware.
-        * The dummy TIM MUST be at the end of the beacon frame,
-        * because it'll be overwritten!
-        */
-
        struct ieee80211_mgmt *mgmt = (void *)skb->data;
        u8 *pos, *end;
 
        if (skb->len <= sizeof(mgmt))
-               return -EINVAL;
+               return NULL;
 
        pos = (u8 *)mgmt->u.beacon.variable;
        end = skb->data + skb->len;
        while (pos < end) {
                if (pos + 2 + pos[1] > end)
-                       return -EINVAL;
+                       return NULL;
+
+               if (pos[0] == ie)
+                       return pos;
+
+               pos += 2 + pos[1];
+       }
+       return NULL;
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+       /*
+        * the good excuse for this mess is ... the firmware.
+        * The dummy TIM MUST be at the end of the beacon frame,
+        * because it'll be overwritten!
+        */
+       u8 *tim;
+       u8 dtim_len;
+       u8 dtim_period;
+       u8 *next;
 
-               if (pos[0] == WLAN_EID_TIM) {
-                       u8 dtim_len = pos[1];
-                       u8 dtim_period = pos[3];
-                       u8 *next = pos + 2 + dtim_len;
+       tim = p54_find_ie(skb, WLAN_EID_TIM);
+       if (!tim)
+               return 0;
 
-                       if (dtim_len < 3)
-                               return -EINVAL;
+       dtim_len = tim[1];
+       dtim_period = tim[3];
+       next = tim + 2 + dtim_len;
 
-                       memmove(pos, next, end - next);
+       if (dtim_len < 3)
+               return -EINVAL;
 
-                       if (dtim_len > 3)
-                               skb_trim(skb, skb->len - (dtim_len - 3));
+       memmove(tim, next, skb_tail_pointer(skb) - next);
+       tim = skb_tail_pointer(skb) - (dtim_len + 2);
 
-                       pos = end - (dtim_len + 2);
+       /* add the dummy at the end */
+       tim[0] = WLAN_EID_TIM;
+       tim[1] = 3;
+       tim[2] = 0;
+       tim[3] = dtim_period;
+       tim[4] = 0;
+
+       if (dtim_len > 3)
+               skb_trim(skb, skb->len - (dtim_len - 3));
 
-                       /* add the dummy at the end */
-                       pos[0] = WLAN_EID_TIM;
-                       pos[1] = 3;
-                       pos[2] = 0;
-                       pos[3] = dtim_period;
-                       pos[4] = 0;
-                       return 0;
-               }
-               pos += 2 + pos[1];
-       }
        return 0;
 }
 
@@ -117,7 +130,6 @@ static int p54_beacon_update(struct p54_common *priv,
                        struct ieee80211_vif *vif)
 {
        struct sk_buff *beacon;
-       __le32 old_beacon_req_id;
        int ret;
 
        beacon = ieee80211_beacon_get(priv->hw, vif);
@@ -127,15 +139,16 @@ static int p54_beacon_update(struct p54_common *priv,
        if (ret)
                return ret;
 
-       old_beacon_req_id = priv->beacon_req_id;
-       priv->beacon_req_id = GET_REQ_ID(beacon);
-
-       ret = p54_tx_80211(priv->hw, beacon);
-       if (ret) {
-               priv->beacon_req_id = old_beacon_req_id;
-               return -ENOSPC;
-       }
-
+       /*
+        * During operation, the firmware takes care of beaconing.
+        * The driver only needs to upload a new beacon template, once
+        * the template was changed by the stack or userspace.
+        *
+        * LMAC API 3.2.2 also specifies that the driver does not need
+        * to cancel the old beacon template by hand, instead the firmware
+        * will release the previous one through the feedback mechanism.
+        */
+       WARN_ON(p54_tx_80211(priv->hw, beacon));
        priv->tsf_high32 = 0;
        priv->tsf_low32 = 0;
 
@@ -240,9 +253,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
 
        mutex_lock(&priv->conf_mutex);
        priv->vif = NULL;
-       if (priv->beacon_req_id) {
+
+       /*
+        * LMAC API 3.2.2 states that any active beacon template must be
+        * canceled by the driver before attempting a mode transition.
+        */
+       if (le32_to_cpu(priv->beacon_req_id) != 0) {
                p54_tx_cancel(priv, priv->beacon_req_id);
-               priv->beacon_req_id = cpu_to_le32(0);
+               wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
        }
        priv->mode = NL80211_IFTYPE_MONITOR;
        memset(priv->mac_addr, 0, ETH_ALEN);
@@ -384,6 +402,9 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
                        priv->wakeup_timer = info->beacon_int *
                                             info->dtim_period * 5;
                        p54_setup_mac(priv);
+               } else {
+                       priv->wakeup_timer = 500;
+                       priv->aid = 0;
                }
        }
 
@@ -517,6 +538,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
        skb_queue_head_init(&priv->tx_pending);
        dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_SIGNAL_DBM |
+                    IEEE80211_HW_SUPPORTS_PS |
+                    IEEE80211_HW_PS_NULLFUNC_STACK |
+                    IEEE80211_HW_BEACON_FILTER |
                     IEEE80211_HW_NOISE_DBM;
 
        dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
@@ -525,6 +549,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
                                      BIT(NL80211_IFTYPE_MESH_POINT);
 
        dev->channel_change_time = 1000;        /* TODO: find actual value */
+       priv->beacon_req_id = cpu_to_le32(0);
        priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
        priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
        priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
@@ -548,6 +573,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
        mutex_init(&priv->conf_mutex);
        mutex_init(&priv->eeprom_mutex);
        init_completion(&priv->eeprom_comp);
+       init_completion(&priv->beacon_comp);
        INIT_DELAYED_WORK(&priv->work, p54_work);
 
        return dev;
@@ -579,6 +605,10 @@ EXPORT_SYMBOL_GPL(p54_register_common);
 void p54_free_common(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
+       unsigned int i;
+
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               kfree(priv->band_table[i]);
 
        kfree(priv->iq_autocal);
        kfree(priv->output_limit);
index 19d085c..1afc394 100644 (file)
@@ -198,6 +198,7 @@ struct p54_common {
        struct p54_cal_database *curve_data;
        struct p54_cal_database *output_limit;
        struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+       struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
 
        /* BBP/MAC state */
        u8 mac_addr[ETH_ALEN];
@@ -208,7 +209,9 @@ struct p54_common {
        u32 tsf_low32, tsf_high32;
        u32 basic_rate_mask;
        u16 aid;
+       bool powersave_override;
        __le32 beacon_req_id;
+       struct completion beacon_comp;
 
        /* cryptographic engine information */
        u8 privacy_caps;
index 6426d2c..0d589d6 100644 (file)
@@ -87,9 +87,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
        u32 target_addr = priv->rx_start;
        u16 len = priv->headroom + skb->len + priv->tailroom + 3;
 
-       if (unlikely(WARN_ON(!skb || !priv)))
-               return -EINVAL;
-
        info = IEEE80211_SKB_CB(skb);
        range = (void *) info->rate_driver_data;
        len = (range->extra_len + len) & ~0x3;
@@ -111,11 +108,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
                range = (void *) info->rate_driver_data;
                hole_size = range->start_addr - last_addr;
 
-               if (!entry->next) {
-                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-                       return -ENOSPC;
-               }
-
                if (!target_skb && hole_size >= len) {
                        target_skb = entry->prev;
                        hole_size -= len;
@@ -142,9 +134,13 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
        range = (void *) info->rate_driver_data;
        range->start_addr = target_addr;
        range->end_addr = target_addr + len;
+       data->req_id = cpu_to_le32(target_addr + priv->headroom);
+       if (IS_DATA_FRAME(skb) &&
+           unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+               priv->beacon_req_id = data->req_id;
+
        __skb_queue_after(&priv->tx_queue, target_skb, skb);
        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-       data->req_id = cpu_to_le32(target_addr + priv->headroom);
        return 0;
 }
 
@@ -153,9 +149,6 @@ static void p54_tx_pending(struct p54_common *priv)
        struct sk_buff *skb;
        int ret;
 
-       if (unlikely(WARN_ON(!priv)))
-               return ;
-
        skb = skb_dequeue(&priv->tx_pending);
        if (unlikely(!skb))
                return ;
@@ -219,14 +212,20 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
 static void p54_tx_qos_accounting_free(struct p54_common *priv,
                                       struct sk_buff *skb)
 {
-       if (skb && IS_DATA_FRAME(skb)) {
-               struct p54_hdr *hdr = (void *) skb->data;
-               struct p54_tx_data *data = (void *) hdr->data;
+       if (IS_DATA_FRAME(skb)) {
                unsigned long flags;
 
                spin_lock_irqsave(&priv->tx_stats_lock, flags);
-               priv->tx_stats[data->hw_queue].len--;
+               priv->tx_stats[GET_HW_QUEUE(skb)].len--;
                spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+               if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+                       if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+                               /* this is the  active beacon set anymore */
+                               priv->beacon_req_id = 0;
+                       }
+                       complete(&priv->beacon_comp);
+               }
        }
        p54_wake_queues(priv);
 }
@@ -266,9 +265,6 @@ static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
 
 void p54_tx(struct p54_common *priv, struct sk_buff *skb)
 {
-       if (unlikely(WARN_ON(!priv)))
-               return ;
-
        skb_queue_tail(&priv->tx_pending, skb);
        p54_tx_pending(priv);
 }
@@ -288,6 +284,45 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
                         priv->rssical_db[band].add) / 4;
 }
 
+/*
+ * Even if the firmware is capable of dealing with incoming traffic,
+ * while dozing, we have to prepared in case mac80211 uses PS-POLL
+ * to retrieve outstanding frames from our AP.
+ * (see comment in net/mac80211/mlme.c @ line 1993)
+ */
+static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (void *) skb->data;
+       struct ieee80211_tim_ie *tim_ie;
+       u8 *tim;
+       u8 tim_len;
+       bool new_psm;
+
+       /* only beacons have a TIM IE */
+       if (!ieee80211_is_beacon(hdr->frame_control))
+               return;
+
+       if (!priv->aid)
+               return;
+
+       /* only consider beacons from the associated BSSID */
+       if (compare_ether_addr(hdr->addr3, priv->bssid))
+               return;
+
+       tim = p54_find_ie(skb, WLAN_EID_TIM);
+       if (!tim)
+               return;
+
+       tim_len = tim[1];
+       tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+       new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
+       if (new_psm != priv->powersave_override) {
+               priv->powersave_override = new_psm;
+               p54_set_ps(priv);
+       }
+}
+
 static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
 {
        struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
@@ -340,6 +375,9 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
 
        skb_pull(skb, header_len);
        skb_trim(skb, le16_to_cpu(hdr->len));
+       if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+               p54_pspoll_workaround(priv, skb);
+
        ieee80211_rx_irqsafe(priv->hw, skb);
 
        queue_delayed_work(priv->hw->workqueue, &priv->work,
@@ -375,10 +413,6 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
         * and we don't want to confuse the mac80211 stack.
         */
        if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
-               if (entry_data->hw_queue == P54_QUEUE_BEACON &&
-                   hdr->req_id == priv->beacon_req_id)
-                       priv->beacon_req_id = cpu_to_le32(0);
-
                dev_kfree_skb_any(entry);
                return ;
        }
index d8035e3..30185ad 100644 (file)
@@ -1561,6 +1561,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .configure_filter       = rt2x00mac_configure_filter,
+       .set_tim                = rt2x00mac_set_tim,
        .get_stats              = rt2x00mac_get_stats,
        .bss_info_changed       = rt2x00mac_bss_info_changed,
        .conf_tx                = rt2400pci_conf_tx,
index ec3b004..ccd6441 100644 (file)
 #define RXD_W7_RESERVED                        FIELD32(0xffffffff)
 
 /*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
  * and from mac80211 value to register value.
  * NOTE: Logics in rt2400pci for txpower are reversed
  * compared to the other rt2x00 drivers. A higher txpower
index c123e28..3b31715 100644 (file)
@@ -1860,6 +1860,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .configure_filter       = rt2x00mac_configure_filter,
+       .set_tim                = rt2x00mac_set_tim,
        .get_stats              = rt2x00mac_get_stats,
        .bss_info_changed       = rt2x00mac_bss_info_changed,
        .conf_tx                = rt2x00mac_conf_tx,
index ce2f065..54d3795 100644 (file)
 #define RXD_W10_DROP                   FIELD32(0x00000001)
 
 /*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
  * and from mac80211 value to register value.
  */
 #define MIN_TXPOWER    0
index 00611b3..de48c5c 100644 (file)
@@ -1896,6 +1896,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .configure_filter       = rt2x00mac_configure_filter,
+       .set_tim                = rt2x00mac_set_tim,
        .set_key                = rt2x00mac_set_key,
        .get_stats              = rt2x00mac_get_stats,
        .bss_info_changed       = rt2x00mac_bss_info_changed,
index 5bc46fe..b01edca 100644 (file)
 #define RXD_W3_EIV                     FIELD32(0xffffffff)
 
 /*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
  * and from mac80211 value to register value.
  */
 #define MIN_TXPOWER    0
index a204e66..9efb417 100644 (file)
@@ -1910,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
                /*
                 * Before the radio can be enabled, the device first has
                 * to be woken up. After that it needs a bit of time
-                * to be fully awake and the radio can be enabled.
+                * to be fully awake and then the radio can be enabled.
                 */
                rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
                msleep(1);
@@ -1918,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
                break;
        case STATE_RADIO_OFF:
                /*
-                * After the radio has been disablee, the device should
+                * After the radio has been disabled, the device should
                 * be put to sleep for powersaving.
                 */
                rt2800usb_disable_radio(rt2x00dev);
@@ -2220,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
         */
        mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
        if (!is_valid_ether_addr(mac)) {
-               DECLARE_MAC_BUF(macbuf);
-
                random_ether_addr(mac);
-               EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+               EEPROM(rt2x00dev, "MAC: %pM\n", mac);
        }
 
        rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2786,6 +2784,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .configure_filter       = rt2x00mac_configure_filter,
+       .set_tim                = rt2x00mac_set_tim,
        .set_key                = rt2x00mac_set_key,
        .get_stats              = rt2x00mac_get_stats,
        .get_tkip_seq           = rt2800usb_get_tkip_seq,
index 61a8be6..2d9dc37 100644 (file)
@@ -1921,7 +1921,7 @@ struct mac_iveiv_entry {
 #define RXWI_W3_SNR1                   FIELD32(0x0000ff00)
 
 /*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
  * and from mac80211 value to register value.
  */
 #define MIN_G_TXPOWER  0
index 71f37cb..cbec91e 100644 (file)
@@ -245,7 +245,7 @@ struct link_ant {
        struct antenna_setup active;
 
        /*
-        * RSSI information for the different antenna's.
+        * RSSI information for the different antennas.
         * These statistics are used to determine when
         * to switch antenna when using software diversity.
         *
@@ -594,7 +594,6 @@ enum rt2x00_flags {
        DEVICE_STATE_INITIALIZED,
        DEVICE_STATE_STARTED,
        DEVICE_STATE_ENABLED_RADIO,
-       DEVICE_STATE_DISABLED_RADIO_HW,
 
        /*
         * Driver requirements
@@ -634,7 +633,7 @@ struct rt2x00_dev {
         * The structure stored in here depends on the
         * system bus (PCI or USB).
         * When accessing this variable, the rt2x00dev_{pci,usb}
-        * macro's should be used for correct typecasting.
+        * macros should be used for correct typecasting.
         */
        struct device *dev;
 
@@ -963,6 +962,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
                                unsigned int changed_flags,
                                unsigned int *total_flags,
                                int mc_count, struct dev_addr_list *mc_list);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+                     bool set);
 #ifdef CONFIG_RT2X00_LIB_CRYPTO
 int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
index 3e019a1..c6e0bcf 100644 (file)
@@ -132,7 +132,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
        /*
         * Failsafe: Make sure we are not sending the
         * ANTENNA_SW_DIVERSITY state to the driver.
-        * If that happes fallback to hardware default,
+        * If that happens, fallback to hardware defaults,
         * or our own default.
         * The calls to rt2x00lib_config_antenna_check()
         * might have caused that we restore back to the already
index c54eda3..30fbd3b 100644 (file)
@@ -129,7 +129,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
        /* Pull buffer to correct size */
        skb_pull(skb, txdesc->iv_len);
 
-       /* IV/EIV data has officially be stripped */
+       /* IV/EIV data has officially been stripped */
        skbdesc->flags |= SKBDESC_IV_STRIPPED;
 }
 
index 4fff3a8..658a63b 100644 (file)
@@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
         * Don't enable the radio twice.
         * And check if the hardware button has been disabled.
         */
-       if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+       if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
                return 0;
 
        /*
index eb9b981..3257075 100644 (file)
@@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
 
        /*
         * During the last period we have sampled the RSSI
-        * from both antenna's. It now is time to determine
+        * from both antennas. It now is time to determine
         * which antenna demonstrated the best performance.
         * When we are already on the antenna with the best
         * performance, then there really is nothing for us
index b7e0ddd..9d31c23 100644 (file)
@@ -341,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
        int status;
 
        /*
-        * Mac80211 might be calling this function while we are trying
+        * mac80211 might be calling this function while we are trying
         * to remove the device or perhaps suspending it.
         */
        if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -454,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
                       sizeof(crypto->rx_mic));
 }
 
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+                     bool set)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+
+       rt2x00lib_beacondone(rt2x00dev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
+
 int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
                      struct ieee80211_key_conf *key)
@@ -577,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
        int update_bssid = 0;
 
        /*
-        * Mac80211 might be calling this function while we are trying
+        * mac80211 might be calling this function while we are trying
         * to remove the device or perhaps suspending it.
         */
        if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
index b5e0634..47d175a 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/prefetch.h>
 
 /**
- * DOC: Entrie frame size
+ * DOC: Entry frame size
  *
  * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
  * for USB devices this restriction does not apply, but the value of
 /**
  * DOC: Number of entries per queue
  *
- * Under normal load without fragmentation 12 entries are sufficient
+ * Under normal load without fragmentation, 12 entries are sufficient
  * without the queue being filled up to the maximum. When using fragmentation
- * and the queue threshold code we need to add some additional margins to
+ * and the queue threshold code, we need to add some additional margins to
  * make sure the queue will never (or only under extreme load) fill up
  * completely.
- * Since we don't use preallocated DMA having a large number of queue entries
- * will have only minimal impact on the memory requirements for the queue.
+ * Since we don't use preallocated DMA, having a large number of queue entries
+ * will have minimal impact on the memory requirements for the queue.
  */
 #define RX_ENTRIES     24
 #define TX_ENTRIES     24
index 861322d..983e52e 100644 (file)
@@ -176,8 +176,8 @@ struct rt2x00_field32 {
 #define is_valid_mask(x)       is_power_of_two(1LU + (x) + low_bit_mask(x))
 
 /*
- * Macro's to find first set bit in a variable.
- * These macro's behaves the same as the __ffs() function with
+ * Macros to find first set bit in a variable.
+ * These macros behave the same as the __ffs() functions but
  * the most important difference that this is done during
  * compile-time rather then run-time.
  */
index 8a49d99..fb95b8c 100644 (file)
@@ -2312,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        }
 
        /*
-        * Determine number of antenna's.
+        * Determine number of antennas.
         */
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
                __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
@@ -2716,6 +2716,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .configure_filter       = rt2x00mac_configure_filter,
+       .set_tim                = rt2x00mac_set_tim,
        .set_key                = rt2x00mac_set_key,
        .get_stats              = rt2x00mac_get_stats,
        .bss_info_changed       = rt2x00mac_bss_info_changed,
index 6c71f77..93eb699 100644 (file)
@@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry {
 #define RXD_W15_RESERVED               FIELD32(0xffffffff)
 
 /*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
  * and from mac80211 value to register value.
  */
 #define MIN_TXPOWER    0
index ad2898c..4f9b177 100644 (file)
@@ -2241,6 +2241,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .configure_filter       = rt2x00mac_configure_filter,
+       .set_tim                = rt2x00mac_set_tim,
        .set_key                = rt2x00mac_set_key,
        .get_stats              = rt2x00mac_get_stats,
        .bss_info_changed       = rt2x00mac_bss_info_changed,
index c8016f6..81fe0be 100644 (file)
@@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry {
 
 /*
  * EEPROM antenna.
- * ANTENNA_NUM: Number of antenna's.
+ * ANTENNA_NUM: Number of antennas.
  * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
  * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
  * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
@@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry {
 #define RXD_W5_RESERVED                        FIELD32(0xffffffff)
 
 /*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
  * and from mac80211 value to register value.
  */
 #define MIN_TXPOWER    0
index 5a8d21c..a46c92a 100644 (file)
@@ -84,7 +84,7 @@ int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
        ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
                                   default_key, sizeof(*default_key));
        if (ret < 0) {
-               wl1251_error("Couldnt set default key");
+               wl1251_error("Couldn't set default key");
                goto out;
        }
 
@@ -231,7 +231,7 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl)
        ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
                                   feature, sizeof(*feature));
        if (ret < 0) {
-               wl1251_error("Couldnt set HW encryption");
+               wl1251_error("Couldn't set HW encryption");
                goto out;
        }
 
index cf5e054..da4c688 100644 (file)
@@ -246,60 +246,6 @@ out:
        mutex_unlock(&wl->mutex);
 }
 
-int wl1251_plt_start(struct wl1251 *wl)
-{
-       int ret;
-
-       mutex_lock(&wl->mutex);
-
-       wl1251_notice("power up");
-
-       if (wl->state != WL1251_STATE_OFF) {
-               wl1251_error("cannot go into PLT state because not "
-                            "in off state: %d", wl->state);
-               return -EBUSY;
-       }
-
-       wl->state = WL1251_STATE_PLT;
-
-       ret = wl1251_chip_wakeup(wl);
-       if (ret < 0)
-               return ret;
-
-       ret = wl->chip.op_boot(wl);
-       if (ret < 0)
-               return ret;
-
-       wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
-
-       ret = wl->chip.op_plt_init(wl);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-int wl1251_plt_stop(struct wl1251 *wl)
-{
-       mutex_lock(&wl->mutex);
-
-       wl1251_notice("power down");
-
-       if (wl->state != WL1251_STATE_PLT) {
-               wl1251_error("cannot power down because not in PLT "
-                            "state: %d", wl->state);
-               return -EBUSY;
-       }
-
-       wl1251_disable_interrupts(wl);
-       wl1251_power_off(wl);
-
-       wl->state = WL1251_STATE_OFF;
-
-       return 0;
-}
-
-
 static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1251 *wl = hw->priv;
@@ -349,7 +295,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw)
 
        ret = wl1251_chip_wakeup(wl);
        if (ret < 0)
-               return ret;
+               goto out;
 
        ret = wl->chip.op_boot(wl);
        if (ret < 0)
@@ -435,11 +381,10 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_if_init_conf *conf)
 {
        struct wl1251 *wl = hw->priv;
-       DECLARE_MAC_BUF(mac);
        int ret = 0;
 
-       wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
-                    conf->type, print_mac(mac, conf->mac_addr));
+       wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+                    conf->type, conf->mac_addr);
 
        mutex_lock(&wl->mutex);
 
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c
deleted file mode 100644 (file)
index 67d3d5a..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * This file is part of wl1251
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#include "wl1251_netlink.h"
-
-#include <linux/mutex.h>
-#include <linux/socket.h>
-#include <net/net_namespace.h>
-#include <net/sock.h>
-#include <net/genetlink.h>
-#include <net/wireless.h>
-#include <net/mac80211.h>
-
-#include "wl1251.h"
-#include "wl1251_spi.h"
-#include "wl1251_acx.h"
-
-/* FIXME: this should be changed as soon as user space catches up */
-#define WL1251_NL_NAME "wl1251"
-#define WL1251_NL_VERSION 1
-
-#define WL1251_MAX_TEST_LENGTH 1024
-#define WL1251_MAX_NVS_LENGTH 1024
-
-enum wl1251_nl_commands {
-       WL1251_NL_CMD_UNSPEC,
-       WL1251_NL_CMD_TEST,
-       WL1251_NL_CMD_INTERROGATE,
-       WL1251_NL_CMD_CONFIGURE,
-       WL1251_NL_CMD_PHY_REG_READ,
-       WL1251_NL_CMD_NVS_PUSH,
-       WL1251_NL_CMD_REG_WRITE,
-       WL1251_NL_CMD_REG_READ,
-       WL1251_NL_CMD_SET_PLT_MODE,
-
-       __WL1251_NL_CMD_AFTER_LAST
-};
-#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1)
-
-enum wl1251_nl_attrs {
-       WL1251_NL_ATTR_UNSPEC,
-       WL1251_NL_ATTR_IFNAME,
-       WL1251_NL_ATTR_CMD_TEST_PARAM,
-       WL1251_NL_ATTR_CMD_TEST_ANSWER,
-       WL1251_NL_ATTR_CMD_IE,
-       WL1251_NL_ATTR_CMD_IE_LEN,
-       WL1251_NL_ATTR_CMD_IE_BUFFER,
-       WL1251_NL_ATTR_CMD_IE_ANSWER,
-       WL1251_NL_ATTR_REG_ADDR,
-       WL1251_NL_ATTR_REG_VAL,
-       WL1251_NL_ATTR_NVS_BUFFER,
-       WL1251_NL_ATTR_NVS_LEN,
-       WL1251_NL_ATTR_PLT_MODE,
-
-       __WL1251_NL_ATTR_AFTER_LAST
-};
-#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1)
-
-static struct genl_family wl1251_nl_family = {
-       .id = GENL_ID_GENERATE,
-       .name = WL1251_NL_NAME,
-       .hdrsize = 0,
-       .version = WL1251_NL_VERSION,
-       .maxattr = WL1251_NL_ATTR_MAX,
-};
-
-static struct net_device *ifname_to_netdev(struct net *net,
-                                          struct genl_info *info)
-{
-       char *ifname;
-
-       if (!info->attrs[WL1251_NL_ATTR_IFNAME])
-               return NULL;
-
-       ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]);
-
-       wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname);
-
-       return dev_get_by_name(net, ifname);
-}
-
-static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info)
-{
-       struct net_device *netdev;
-       struct wireless_dev *wdev;
-       struct wiphy *wiphy;
-       struct ieee80211_hw *hw;
-
-       netdev = ifname_to_netdev(net, info);
-       if (netdev == NULL) {
-               wl1251_error("Wrong interface");
-               return NULL;
-       }
-
-       wdev = netdev->ieee80211_ptr;
-       if (wdev == NULL) {
-               wl1251_error("ieee80211_ptr is NULL");
-               return NULL;
-       }
-
-       wiphy = wdev->wiphy;
-       if (wiphy == NULL) {
-               wl1251_error("wiphy is NULL");
-               return NULL;
-       }
-
-       hw = wiphy_priv(wiphy);
-       if (hw == NULL) {
-               wl1251_error("hw is NULL");
-               return NULL;
-       }
-
-       dev_put(netdev);
-
-       return hw->priv;
-}
-
-static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       struct wl1251_command *cmd;
-       char *buf;
-       int buf_len, ret, cmd_len;
-       u8 answer;
-
-       if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM])
-               return -EINVAL;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               return -EINVAL;
-       }
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (!cmd)
-               return -ENOMEM;
-
-       buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
-       buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
-       answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]);
-
-       cmd->header.id = CMD_TEST;
-       memcpy(cmd->parameters, buf, buf_len);
-       cmd_len = sizeof(struct wl1251_cmd_header) + buf_len;
-
-       mutex_lock(&wl->mutex);
-       ret = wl1251_cmd_test(wl, cmd, cmd_len, answer);
-       mutex_unlock(&wl->mutex);
-
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto out;
-       }
-
-       if (answer) {
-               struct sk_buff *msg;
-               void *hdr;
-
-               msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-               if (!msg) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
-                                 &wl1251_nl_family, 0, WL1251_NL_CMD_TEST);
-               if (IS_ERR(hdr)) {
-                       ret = PTR_ERR(hdr);
-                       goto nla_put_failure;
-               }
-
-               NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
-                              nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
-               NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER,
-                       sizeof(*cmd), cmd);
-
-               ret = genlmsg_end(msg, hdr);
-               if (ret < 0) {
-                       wl1251_error("%s() failed", __func__);
-                       goto nla_put_failure;
-               }
-
-               wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
-               ret = genlmsg_reply(msg, info);
-               goto out;
-
- nla_put_failure:
-               nlmsg_free(msg);
-       } else
-               wl1251_debug(DEBUG_NETLINK, "TEST cmd sent");
-
-out:
-       kfree(cmd);
-       return ret;
-}
-
-static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       struct sk_buff *msg;
-       int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
-       struct wl1251_command *cmd;
-       void *hdr;
-
-       if (!info->attrs[WL1251_NL_ATTR_CMD_IE])
-               return -EINVAL;
-
-       if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
-               return -EINVAL;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (!cmd)
-               return -ENOMEM;
-
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               ret = -EINVAL;
-               goto nla_put_failure;
-       }
-
-       /* acx id */
-       cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]);
-
-       /* maximum length of acx, including all headers */
-       cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
-
-       wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
-                    cmd_ie, cmd_ie_len);
-
-       mutex_lock(&wl->mutex);
-       ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
-       mutex_unlock(&wl->mutex);
-
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto nla_put_failure;
-       }
-
-       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
-                         &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE);
-       if (IS_ERR(hdr)) {
-               ret = PTR_ERR(hdr);
-               goto nla_put_failure;
-       }
-
-       NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
-                      nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
-       NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd);
-
-       ret = genlmsg_end(msg, hdr);
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto nla_put_failure;
-       }
-
-       kfree(cmd);
-       return genlmsg_reply(msg, info);
-
- nla_put_failure:
-       kfree(cmd);
-       nlmsg_free(msg);
-
-       return ret;
-}
-
-static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info)
-{
-       int ret = 0, cmd_ie_len, acx_len;
-       struct acx_header *acx = NULL;
-       struct sk_buff *msg;
-       struct wl1251 *wl;
-       void *cmd_ie;
-       u16 *id;
-
-       if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER])
-               return -EINVAL;
-
-       if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
-               return -EINVAL;
-
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               ret = -EINVAL;
-               goto nla_put_failure;
-       }
-
-       /* contains the acx header but not the cmd header */
-       cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]);
-
-       cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
-
-       /* acx id is in the first two bytes */
-       id = cmd_ie;
-
-       /* need to add acx_header before cmd_ie, so create a new command */
-       acx_len = sizeof(struct acx_header) + cmd_ie_len;
-       acx = kzalloc(acx_len, GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto nla_put_failure;
-       }
-
-       /* copy the acx header and the payload */
-       memcpy(&acx->id, cmd_ie, cmd_ie_len);
-
-       mutex_lock(&wl->mutex);
-       ret = wl1251_cmd_configure(wl, *id, acx, acx_len);
-       mutex_unlock(&wl->mutex);
-
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto nla_put_failure;
-       }
-
-       wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
-
- nla_put_failure:
-       kfree(acx);
-       nlmsg_free(msg);
-
-       return ret;
-}
-
-static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       struct sk_buff *msg;
-       u32 reg_addr, *reg_value = NULL;
-       int ret = 0;
-       void *hdr;
-
-       if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
-               return -EINVAL;
-
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               ret = -EINVAL;
-               goto nla_put_failure;
-       }
-
-       reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL);
-       if (!reg_value) {
-               ret = -ENOMEM;
-               goto nla_put_failure;
-       }
-
-       reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
-
-       wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
-
-       mutex_lock(&wl->mutex);
-       ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value,
-                                    sizeof(*reg_value));
-       mutex_unlock(&wl->mutex);
-
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto nla_put_failure;
-       }
-
-
-       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
-                         &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
-       if (IS_ERR(hdr)) {
-               ret = PTR_ERR(hdr);
-               goto nla_put_failure;
-       }
-
-       NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
-                      nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
-
-       NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value);
-
-       ret = genlmsg_end(msg, hdr);
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto nla_put_failure;
-       }
-
-       kfree(reg_value);
-
-       return genlmsg_reply(msg, info);
-
- nla_put_failure:
-       nlmsg_free(msg);
-       kfree(reg_value);
-
-       return ret;
-}
-
-static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       int ret = 0;
-
-       if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER])
-               return -EINVAL;
-
-       if (!info->attrs[WL1251_NL_ATTR_NVS_LEN])
-               return -EINVAL;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               return -EINVAL;
-       }
-
-       mutex_lock(&wl->mutex);
-       wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]);
-       if (wl->nvs_len % 4) {
-               wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len);
-               ret = -EILSEQ;
-               goto out;
-       }
-
-       /* If we already have an NVS, we should free it */
-       kfree(wl->nvs);
-
-       wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL);
-       if (wl->nvs == NULL) {
-               wl1251_error("Can't allocate NVS");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memcpy(wl->nvs,
-              nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]),
-              wl->nvs_len);
-
-       wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
-                    wl->nvs_len);
-
-out:
-       mutex_unlock(&wl->mutex);
-
-       return ret;
-}
-
-static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       u32 addr, val;
-       int ret = 0;
-       struct sk_buff *msg;
-       void *hdr;
-
-       if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
-               return -EINVAL;
-
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               return -EINVAL;
-       }
-
-       addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
-
-       mutex_lock(&wl->mutex);
-       val = wl1251_reg_read32(wl, addr);
-       mutex_unlock(&wl->mutex);
-
-       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
-                         &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
-       if (IS_ERR(hdr)) {
-               ret = PTR_ERR(hdr);
-               goto nla_put_failure;
-       }
-
-       NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
-                      nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
-
-       NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val);
-
-       ret = genlmsg_end(msg, hdr);
-       if (ret < 0) {
-               wl1251_error("%s() failed", __func__);
-               goto nla_put_failure;
-       }
-
-       return genlmsg_reply(msg, info);
-
- nla_put_failure:
-       nlmsg_free(msg);
-
-       return ret;
-}
-
-static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       u32 addr, val;
-
-       if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
-               return -EINVAL;
-
-       if (!info->attrs[WL1251_NL_ATTR_REG_VAL])
-               return -EINVAL;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               return -EINVAL;
-       }
-
-       addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
-       val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]);
-
-       mutex_lock(&wl->mutex);
-       wl1251_reg_write32(wl, addr, val);
-       mutex_unlock(&wl->mutex);
-
-       return 0;
-}
-
-static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
-{
-       struct wl1251 *wl;
-       u32 val;
-       int ret;
-
-       if (!info->attrs[WL1251_NL_ATTR_PLT_MODE])
-               return -EINVAL;
-
-       wl = ifname_to_wl1251(&init_net, info);
-       if (wl == NULL) {
-               wl1251_error("wl1251 not found");
-               return -EINVAL;
-       }
-
-       val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]);
-
-       switch (val) {
-       case 0:
-               ret = wl1251_plt_stop(wl);
-               break;
-       case 1:
-               ret = wl1251_plt_start(wl);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = {
-       [WL1251_NL_ATTR_IFNAME] =            { .type = NLA_NUL_STRING,
-                                              .len = IFNAMSIZ-1 },
-       [WL1251_NL_ATTR_CMD_TEST_PARAM] =    { .type = NLA_BINARY,
-                                              .len = WL1251_MAX_TEST_LENGTH },
-       [WL1251_NL_ATTR_CMD_TEST_ANSWER] =   { .type = NLA_U8 },
-       [WL1251_NL_ATTR_CMD_IE] =            { .type = NLA_U32 },
-       [WL1251_NL_ATTR_CMD_IE_LEN] =        { .type = NLA_U32 },
-       [WL1251_NL_ATTR_CMD_IE_BUFFER] =     { .type = NLA_BINARY,
-                                              .len = WL1251_MAX_TEST_LENGTH },
-       [WL1251_NL_ATTR_CMD_IE_ANSWER] =     { .type = NLA_BINARY,
-                                              .len = WL1251_MAX_TEST_LENGTH },
-       [WL1251_NL_ATTR_REG_ADDR] =          { .type = NLA_U32 },
-       [WL1251_NL_ATTR_REG_VAL] =           { .type = NLA_U32 },
-       [WL1251_NL_ATTR_NVS_BUFFER] =        { .type = NLA_BINARY,
-                                              .len = WL1251_MAX_NVS_LENGTH },
-       [WL1251_NL_ATTR_NVS_LEN] =           { .type = NLA_U32 },
-       [WL1251_NL_ATTR_PLT_MODE] =          { .type = NLA_U32 },
-};
-
-static struct genl_ops wl1251_nl_ops[] = {
-       {
-               .cmd = WL1251_NL_CMD_TEST,
-               .doit = wl1251_nl_test_cmd,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_INTERROGATE,
-               .doit = wl1251_nl_interrogate,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_CONFIGURE,
-               .doit = wl1251_nl_configure,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_PHY_REG_READ,
-               .doit = wl1251_nl_phy_reg_read,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_NVS_PUSH,
-               .doit = wl1251_nl_nvs_push,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_REG_WRITE,
-               .doit = wl1251_nl_reg_write,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_REG_READ,
-               .doit = wl1251_nl_reg_read,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-       {
-               .cmd = WL1251_NL_CMD_SET_PLT_MODE,
-               .doit = wl1251_nl_set_plt_mode,
-               .policy = wl1251_nl_policy,
-               .flags = GENL_ADMIN_PERM,
-       },
-};
-
-int wl1251_nl_register(void)
-{
-       int err, i;
-
-       err = genl_register_family(&wl1251_nl_family);
-       if (err)
-               return err;
-
-       for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) {
-               err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]);
-               if (err)
-                       goto err_out;
-       }
-       return 0;
- err_out:
-       genl_unregister_family(&wl1251_nl_family);
-       return err;
-}
-
-void wl1251_nl_unregister(void)
-{
-       genl_unregister_family(&wl1251_nl_family);
-}
index 96a45f5..e7b9aab 100644 (file)
@@ -423,7 +423,7 @@ static void wl1251_irq_work(struct work_struct *work)
                wl->rx_counter =
                        wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
 
-               /* We handle a frmware bug here */
+               /* We handle a firmware bug here */
                switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
                case 0:
                        wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
@@ -575,7 +575,7 @@ static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
        wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
                                GFP_KERNEL);
        if (!wl->data_path) {
-               wl1251_error("Couldnt allocate data path parameters");
+               wl1251_error("Couldn't allocate data path parameters");
                return -ENOMEM;
        }
 
index 81156b9..563a3fd 100644 (file)
@@ -88,7 +88,7 @@ struct wl1251_rx_descriptor {
        u8 type;
 
        /*
-        * Recevied Rate:
+        * Received Rate:
         * 0x0A - 1MBPS
         * 0x14 - 2MBPS
         * 0x37 - 5_5MBPS
index 07d7ab6..3868884 100644 (file)
@@ -76,6 +76,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
index e496a2d..962e223 100644 (file)
@@ -567,6 +567,12 @@ enum nl80211_commands {
  * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
  *     commands to specify using a reassociate frame
  *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ *     %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ *     and join_ibss(), key information is in a nested attribute each
+ *     with %NL80211_KEY_* sub-attributes
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -692,6 +698,9 @@ enum nl80211_attrs {
 
        NL80211_ATTR_PREV_BSSID,
 
+       NL80211_ATTR_KEY,
+       NL80211_ATTR_KEYS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -720,6 +729,8 @@ enum nl80211_attrs {
 #define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
 #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -1249,6 +1260,7 @@ enum nl80211_channel_type {
  *     in mBm (100 * dBm) (s32)
  * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
  *     in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -1262,12 +1274,22 @@ enum nl80211_bss {
        NL80211_BSS_INFORMATION_ELEMENTS,
        NL80211_BSS_SIGNAL_MBM,
        NL80211_BSS_SIGNAL_UNSPEC,
+       NL80211_BSS_STATUS,
 
        /* keep last */
        __NL80211_BSS_AFTER_LAST,
        NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_bss_status - BSS "status"
+ */
+enum nl80211_bss_status {
+       NL80211_BSS_STATUS_AUTHENTICATED,
+       NL80211_BSS_STATUS_ASSOCIATED,
+       NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
 /**
  * enum nl80211_auth_type - AuthenticationType
  *
@@ -1320,4 +1342,34 @@ enum nl80211_wpa_versions {
        NL80211_WPA_VERSION_2 = 1 << 1,
 };
 
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *     16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *     keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *     section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *     CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+       __NL80211_KEY_INVALID,
+       NL80211_KEY_DATA,
+       NL80211_KEY_IDX,
+       NL80211_KEY_CIPHER,
+       NL80211_KEY_SEQ,
+       NL80211_KEY_DEFAULT,
+       NL80211_KEY_DEFAULT_MGMT,
+
+       /* keep last */
+       __NL80211_KEY_AFTER_LAST,
+       NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
index f2c69a2..df7b23a 100644 (file)
@@ -304,7 +304,6 @@ typedef unsigned char *sk_buff_data_t;
  *     @tc_index: Traffic control index
  *     @tc_verd: traffic control verdict
  *     @ndisc_nodetype: router type (from link layer)
- *     @do_not_encrypt: set to prevent encryption of this frame
  *     @dma_cookie: a cookie to one of several possible DMA operations
  *             done by skb DMA functions
  *     @secmark: security marking
@@ -379,13 +378,10 @@ struct sk_buff {
        kmemcheck_bitfield_begin(flags2);
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2;
-#endif
-#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
-       __u8                    do_not_encrypt:1;
 #endif
        kmemcheck_bitfield_end(flags2);
 
-       /* 0/13/14 bit hole */
+       /* 0/14 bit hole */
 
 #ifdef CONFIG_NET_DMA
        dma_cookie_t            dma_cookie;
index 83c2c72..a981ca8 100644 (file)
@@ -538,7 +538,7 @@ struct cfg80211_ssid {
  * @ssids: SSIDs to scan for (active scan only)
  * @n_ssids: number of SSIDs
  * @channels: channels to scan on.
- * @n_channels: number of channels for each band
+ * @n_channels: total number of channels to scan
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
  * @wiphy: the wiphy this was for
@@ -647,12 +647,17 @@ struct cfg80211_crypto_settings {
  * @auth_type: Authentication type (algorithm)
  * @ie: Extra IEs to add to Authentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_auth_request {
        struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
        enum nl80211_auth_type auth_type;
+       const u8 *key;
+       u8 key_len, key_idx;
 };
 
 /**
@@ -727,6 +732,8 @@ struct cfg80211_disassoc_request {
  * @ie: information element(s) to include in the beacon
  * @ie_len: length of that
  * @beacon_interval: beacon interval to use
+ * @privacy: this is a protected network, keys will be configured
+ *     after joining
  */
 struct cfg80211_ibss_params {
        u8 *ssid;
@@ -736,6 +743,7 @@ struct cfg80211_ibss_params {
        u8 ssid_len, ie_len;
        u16 beacon_interval;
        bool channel_fixed;
+       bool privacy;
 };
 
 /**
@@ -755,6 +763,9 @@ struct cfg80211_ibss_params {
  * @assoc_ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
  * @crypto: crypto settings
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_connect_params {
        struct ieee80211_channel *channel;
@@ -766,6 +777,8 @@ struct cfg80211_connect_params {
        size_t ie_len;
        bool privacy;
        struct cfg80211_crypto_settings crypto;
+       const u8 *key;
+       u8 key_len, key_idx;
 };
 
 /**
@@ -1223,9 +1236,10 @@ extern void wiphy_unregister(struct wiphy *wiphy);
  */
 extern void wiphy_free(struct wiphy *wiphy);
 
-/* internal struct */
+/* internal structs */
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
+struct cfg80211_cached_keys;
 
 #define MAX_AUTH_BSSES         4
 
@@ -1267,6 +1281,7 @@ struct wireless_dev {
                CFG80211_SME_CONNECTED,
        } sme_state;
        struct cfg80211_conn *conn;
+       struct cfg80211_cached_keys *connect_keys;
 
        struct list_head event_list;
        spinlock_t event_lock;
@@ -1280,6 +1295,7 @@ struct wireless_dev {
        struct {
                struct cfg80211_ibss_params ibss;
                struct cfg80211_connect_params connect;
+               struct cfg80211_cached_keys *keys;
                u8 *ie;
                size_t ie_len;
                u8 bssid[ETH_ALEN];
index ce7cb1b..7dd67a1 100644 (file)
@@ -241,6 +241,8 @@ struct ieee80211_bss_conf {
  *     it can be sent out.
  * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
  *     used to indicate that a frame was already retried due to PS
+ * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
+ *     used to indicate frame should not be encrypted
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
@@ -259,6 +261,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_INTFL_RCALGO               = BIT(13),
        IEEE80211_TX_INTFL_NEED_TXPROCESSING    = BIT(14),
        IEEE80211_TX_INTFL_RETRIED              = BIT(15),
+       IEEE80211_TX_INTFL_DONT_ENCRYPT         = BIT(16),
 };
 
 /**
@@ -2094,6 +2097,29 @@ static inline int rate_supported(struct ieee80211_sta *sta,
        return (sta == NULL || sta->supp_rates[band] & BIT(index));
 }
 
+/**
+ * rate_control_send_low - helper for drivers for management/no-ack frames
+ *
+ * Rate control algorithms that agree to use the lowest rate to
+ * send management frames and NO_ACK data with the respective hw
+ * retries should use this in the beginning of their mac80211 get_rate
+ * callback. If true is returned the rate control can simply return.
+ * If false is returned we guarantee that sta and sta and priv_sta is
+ * not null.
+ *
+ * Rate control algorithms wishing to do more intelligent selection of
+ * rate for multicast/broadcast frames may choose to not use this.
+ *
+ * @sta: &struct ieee80211_sta pointer to the target destination. Note
+ *     that this may be null.
+ * @priv_sta: private rate control structure. This may be null.
+ * @txrc: rate control information we sholud populate for mac80211.
+ */
+bool rate_control_send_low(struct ieee80211_sta *sta,
+                          void *priv_sta,
+                          struct ieee80211_tx_rate_control *txrc);
+
+
 static inline s8
 rate_lowest_index(struct ieee80211_supported_band *sband,
                  struct ieee80211_sta *sta)
@@ -2110,6 +2136,17 @@ rate_lowest_index(struct ieee80211_supported_band *sband,
        return 0;
 }
 
+static inline
+bool rate_usable_index_exists(struct ieee80211_supported_band *sband,
+                             struct ieee80211_sta *sta)
+{
+       unsigned int i;
+
+       for (i = 0; i < sband->n_bitrates; i++)
+               if (rate_supported(sta, sband->band, i))
+                       return true;
+       return false;
+}
 
 int ieee80211_rate_control_register(struct rate_control_ops *ops);
 void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
index dca8b50..d6c657e 100644 (file)
@@ -3923,6 +3923,7 @@ int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
        }
        return err;
 }
+EXPORT_SYMBOL_GPL(__dev_addr_sync);
 
 void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
                       struct dev_addr_list **from, int *from_count)
@@ -3942,6 +3943,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
                da = next;
        }
 }
+EXPORT_SYMBOL_GPL(__dev_addr_unsync);
 
 /**
  *     dev_unicast_sync - Synchronize device's unicast list to another device
index 9e0597d..80a9616 100644 (file)
@@ -559,9 +559,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 #endif
 #endif
        new->vlan_tci           = old->vlan_tci;
-#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
-       new->do_not_encrypt     = old->do_not_encrypt;
-#endif
 
        skb_copy_secmark(new, old);
 }
index 182c9c5..19a4c66 100644 (file)
@@ -206,3 +206,15 @@ config MAC80211_DEBUG_COUNTERS
          and show them in debugfs.
 
          If unsure, say N.
+
+config MAC80211_DRIVER_API_TRACER
+       bool "Driver API tracer"
+       depends on MAC80211_DEBUG_MENU
+       depends on EVENT_TRACING
+       help
+         Say Y here to make mac80211 register with the ftrace
+         framework for the driver API -- you can see which
+         driver methods it is calling then by looking at the
+         trace.
+
+         If unsure, say N.
index 0e3ab88..91284a7 100644 (file)
@@ -41,6 +41,9 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
 
 mac80211-$(CONFIG_PM) += pm.o
 
+mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o
+CFLAGS_driver-trace.o := -I$(src)
+
 # objects for PID algorithm
 rc80211_pid-y := rc80211_pid_algo.o
 rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
index 9e5762a..1958c7c 100644 (file)
@@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
 
        if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
                spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               /* mark queue as pending, it is stopped already */
-               __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
-                         &local->queue_stop_reasons[queue]);
                /* copy over remaining packets */
                skb_queue_splice_tail_init(
                        &sta->ampdu_mlme.tid_tx[tid]->pending,
index 36f8f24..52928ad 100644 (file)
@@ -1293,7 +1293,7 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy)
 }
 
 #ifdef CONFIG_NL80211_TESTMODE
-int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
 
index 6c439cd..96991b6 100644 (file)
@@ -175,7 +175,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
        for (q = 0; q < local->hw.queues; q++)
                res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
                                local->queue_stop_reasons[q],
-                               __netif_subqueue_stopped(local->mdev, q));
+                               skb_queue_len(&local->pending[q]));
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, res);
index b13446a..4100c36 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "driver-trace.h"
 
 static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 {
@@ -11,29 +12,37 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 
 static inline int drv_start(struct ieee80211_local *local)
 {
-       return local->ops->start(&local->hw);
+       int ret = local->ops->start(&local->hw);
+       trace_drv_start(local, ret);
+       return ret;
 }
 
 static inline void drv_stop(struct ieee80211_local *local)
 {
        local->ops->stop(&local->hw);
+       trace_drv_stop(local);
 }
 
 static inline int drv_add_interface(struct ieee80211_local *local,
                                    struct ieee80211_if_init_conf *conf)
 {
-       return local->ops->add_interface(&local->hw, conf);
+       int ret = local->ops->add_interface(&local->hw, conf);
+       trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
+       return ret;
 }
 
 static inline void drv_remove_interface(struct ieee80211_local *local,
                                        struct ieee80211_if_init_conf *conf)
 {
        local->ops->remove_interface(&local->hw, conf);
+       trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
 }
 
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
 {
-       return local->ops->config(&local->hw, changed);
+       int ret = local->ops->config(&local->hw, changed);
+       trace_drv_config(local, changed, ret);
+       return ret;
 }
 
 static inline void drv_bss_info_changed(struct ieee80211_local *local,
@@ -43,6 +52,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 {
        if (local->ops->bss_info_changed)
                local->ops->bss_info_changed(&local->hw, vif, info, changed);
+       trace_drv_bss_info_changed(local, vif, info, changed);
 }
 
 static inline void drv_configure_filter(struct ieee80211_local *local,
@@ -53,14 +63,18 @@ static inline void drv_configure_filter(struct ieee80211_local *local,
 {
        local->ops->configure_filter(&local->hw, changed_flags, total_flags,
                                     mc_count, mc_list);
+       trace_drv_configure_filter(local, changed_flags, total_flags,
+                                           mc_count);
 }
 
 static inline int drv_set_tim(struct ieee80211_local *local,
                              struct ieee80211_sta *sta, bool set)
 {
+       int ret = 0;
        if (local->ops->set_tim)
-               return local->ops->set_tim(&local->hw, sta, set);
-       return 0;
+               ret = local->ops->set_tim(&local->hw, sta, set);
+       trace_drv_set_tim(local, sta, set, ret);
+       return ret;
 }
 
 static inline int drv_set_key(struct ieee80211_local *local,
@@ -68,7 +82,9 @@ static inline int drv_set_key(struct ieee80211_local *local,
                              struct ieee80211_sta *sta,
                              struct ieee80211_key_conf *key)
 {
-       return local->ops->set_key(&local->hw, cmd, vif, sta, key);
+       int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
+       trace_drv_set_key(local, cmd, vif, sta, key, ret);
+       return ret;
 }
 
 static inline void drv_update_tkip_key(struct ieee80211_local *local,
@@ -79,32 +95,41 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
        if (local->ops->update_tkip_key)
                local->ops->update_tkip_key(&local->hw, conf, address,
                                            iv32, phase1key);
+       trace_drv_update_tkip_key(local, conf, address, iv32);
 }
 
 static inline int drv_hw_scan(struct ieee80211_local *local,
                              struct cfg80211_scan_request *req)
 {
-       return local->ops->hw_scan(&local->hw, req);
+       int ret = local->ops->hw_scan(&local->hw, req);
+       trace_drv_hw_scan(local, req, ret);
+       return ret;
 }
 
 static inline void drv_sw_scan_start(struct ieee80211_local *local)
 {
        if (local->ops->sw_scan_start)
                local->ops->sw_scan_start(&local->hw);
+       trace_drv_sw_scan_start(local);
 }
 
 static inline void drv_sw_scan_complete(struct ieee80211_local *local)
 {
        if (local->ops->sw_scan_complete)
                local->ops->sw_scan_complete(&local->hw);
+       trace_drv_sw_scan_complete(local);
 }
 
 static inline int drv_get_stats(struct ieee80211_local *local,
                                struct ieee80211_low_level_stats *stats)
 {
-       if (!local->ops->get_stats)
-               return -EOPNOTSUPP;
-       return local->ops->get_stats(&local->hw, stats);
+       int ret = -EOPNOTSUPP;
+
+       if (local->ops->get_stats)
+               ret = local->ops->get_stats(&local->hw, stats);
+       trace_drv_get_stats(local, stats, ret);
+
+       return ret;
 }
 
 static inline void drv_get_tkip_seq(struct ieee80211_local *local,
@@ -112,14 +137,17 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local,
 {
        if (local->ops->get_tkip_seq)
                local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
+       trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
 }
 
 static inline int drv_set_rts_threshold(struct ieee80211_local *local,
                                        u32 value)
 {
+       int ret = 0;
        if (local->ops->set_rts_threshold)
-               return local->ops->set_rts_threshold(&local->hw, value);
-       return 0;
+               ret = local->ops->set_rts_threshold(&local->hw, value);
+       trace_drv_set_rts_threshold(local, value, ret);
+       return ret;
 }
 
 static inline void drv_sta_notify(struct ieee80211_local *local,
@@ -129,46 +157,57 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
 {
        if (local->ops->sta_notify)
                local->ops->sta_notify(&local->hw, vif, cmd, sta);
+       trace_drv_sta_notify(local, vif, cmd, sta);
 }
 
 static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
                              const struct ieee80211_tx_queue_params *params)
 {
+       int ret = -EOPNOTSUPP;
        if (local->ops->conf_tx)
-               return local->ops->conf_tx(&local->hw, queue, params);
-       return -EOPNOTSUPP;
+               ret = local->ops->conf_tx(&local->hw, queue, params);
+       trace_drv_conf_tx(local, queue, params, ret);
+       return ret;
 }
 
 static inline int drv_get_tx_stats(struct ieee80211_local *local,
                                   struct ieee80211_tx_queue_stats *stats)
 {
-       return local->ops->get_tx_stats(&local->hw, stats);
+       int ret = local->ops->get_tx_stats(&local->hw, stats);
+       trace_drv_get_tx_stats(local, stats, ret);
+       return ret;
 }
 
 static inline u64 drv_get_tsf(struct ieee80211_local *local)
 {
+       u64 ret = -1ULL;
        if (local->ops->get_tsf)
-               return local->ops->get_tsf(&local->hw);
-       return -1ULL;
+               ret = local->ops->get_tsf(&local->hw);
+       trace_drv_get_tsf(local, ret);
+       return ret;
 }
 
 static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
 {
        if (local->ops->set_tsf)
                local->ops->set_tsf(&local->hw, tsf);
+       trace_drv_set_tsf(local, tsf);
 }
 
 static inline void drv_reset_tsf(struct ieee80211_local *local)
 {
        if (local->ops->reset_tsf)
                local->ops->reset_tsf(&local->hw);
+       trace_drv_reset_tsf(local);
 }
 
 static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 {
+       int ret = 1;
        if (local->ops->tx_last_beacon)
-               return local->ops->tx_last_beacon(&local->hw);
-       return 1;
+               ret = local->ops->tx_last_beacon(&local->hw);
+       trace_drv_tx_last_beacon(local, ret);
+       return ret;
 }
 
 static inline int drv_ampdu_action(struct ieee80211_local *local,
@@ -176,10 +215,12 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
                                   struct ieee80211_sta *sta, u16 tid,
                                   u16 *ssn)
 {
+       int ret = -EOPNOTSUPP;
        if (local->ops->ampdu_action)
-               return local->ops->ampdu_action(&local->hw, action,
-                                               sta, tid, ssn);
-       return -EOPNOTSUPP;
+               ret = local->ops->ampdu_action(&local->hw, action,
+                                              sta, tid, ssn);
+       trace_drv_ampdu_action(local, action, sta, tid, ssn, ret);
+       return ret;
 }
 
 
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c
new file mode 100644 (file)
index 0000000..6da6f79
--- /dev/null
@@ -0,0 +1,6 @@
+/* bug in tracepoint.h, it should include this */
+#include <linux/module.h>
+
+#include "driver-ops.h"
+#define CREATE_TRACE_POINTS
+#include "driver-trace.h"
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
new file mode 100644 (file)
index 0000000..5a10da2
--- /dev/null
@@ -0,0 +1,648 @@
+#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __MAC80211_DRIVER_TRACE
+
+#include <linux/tracepoint.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+#if !defined(CONFIG_MAC80211_DRIVER_API_TRACER) || defined(__CHECKER__)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211
+
+#define MAXNAME                32
+#define LOCAL_ENTRY    __array(char, wiphy_name, 32)
+#define LOCAL_ASSIGN   strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
+#define LOCAL_PR_FMT   "%s"
+#define LOCAL_PR_ARG   __entry->wiphy_name
+
+#define STA_ENTRY      __array(char, sta_addr, ETH_ALEN)
+#define STA_ASSIGN     (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
+#define STA_PR_FMT     " sta:%pM"
+#define STA_PR_ARG     __entry->sta_addr
+
+#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, vif)
+#define VIF_ASSIGN     __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif
+#define VIF_PR_FMT     " vif:%p(%d)"
+#define VIF_PR_ARG     __entry->vif, __entry->vif_type
+
+TRACE_EVENT(drv_start,
+       TP_PROTO(struct ieee80211_local *local, int ret),
+
+       TP_ARGS(local, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_stop,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_add_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                const u8 *addr,
+                struct ieee80211_vif *vif,
+                int ret),
+
+       TP_ARGS(local, addr, vif, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __array(char, addr, 6)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               memcpy(__entry->addr, addr, 6);
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM ret:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_remove_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                const u8 *addr, struct ieee80211_vif *vif),
+
+       TP_ARGS(local, addr, vif),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __array(char, addr, 6)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               memcpy(__entry->addr, addr, 6);
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
+       )
+);
+
+TRACE_EVENT(drv_config,
+       TP_PROTO(struct ieee80211_local *local,
+                u32 changed,
+                int ret),
+
+       TP_ARGS(local, changed, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, changed)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->changed = changed;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ch:%#x ret:%d",
+               LOCAL_PR_ARG, __entry->changed, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_bss_info_changed,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_vif *vif,
+                struct ieee80211_bss_conf *info,
+                u32 changed),
+
+       TP_ARGS(local, vif, info, changed),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(bool, assoc)
+               __field(u16, aid)
+               __field(bool, cts)
+               __field(bool, shortpre)
+               __field(bool, shortslot)
+               __field(u8, dtimper)
+               __field(u16, bcnint)
+               __field(u16, assoc_cap)
+               __field(u64, timestamp)
+               __field(u32, basic_rates)
+               __field(u32, changed)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->changed = changed;
+               __entry->aid = info->aid;
+               __entry->assoc = info->assoc;
+               __entry->shortpre = info->use_short_preamble;
+               __entry->cts = info->use_cts_prot;
+               __entry->shortslot = info->use_short_slot;
+               __entry->dtimper = info->dtim_period;
+               __entry->bcnint = info->beacon_int;
+               __entry->assoc_cap = info->assoc_capability;
+               __entry->timestamp = info->timestamp;
+               __entry->basic_rates = info->basic_rates;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " changed:%#x",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
+       )
+);
+
+TRACE_EVENT(drv_configure_filter,
+       TP_PROTO(struct ieee80211_local *local,
+                unsigned int changed_flags,
+                unsigned int *total_flags,
+                int mc_count),
+
+       TP_ARGS(local, changed_flags, total_flags, mc_count),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(unsigned int, changed)
+               __field(unsigned int, total)
+               __field(int, mc)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->changed = changed_flags;
+               __entry->total = *total_flags;
+               __entry->mc = mc_count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " changed:%#x total:%#x mc:%d",
+               LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc
+       )
+);
+
+TRACE_EVENT(drv_set_tim,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta, bool set, int ret),
+
+       TP_ARGS(local, sta, set, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(bool, set)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->set = set;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d",
+               LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_set_key,
+       TP_PROTO(struct ieee80211_local *local,
+                enum set_key_cmd cmd, struct ieee80211_vif *vif,
+                struct ieee80211_sta *sta,
+                struct ieee80211_key_conf *key, int ret),
+
+       TP_ARGS(local, cmd, vif, sta, key, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(enum ieee80211_key_alg, alg)
+               __field(u8, hw_key_idx)
+               __field(u8, flags)
+               __field(s8, keyidx)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->alg = key->alg;
+               __entry->flags = key->flags;
+               __entry->keyidx = key->keyidx;
+               __entry->hw_key_idx = key->hw_key_idx;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " ret:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_update_tkip_key,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_key_conf *conf,
+                const u8 *address, u32 iv32),
+
+       TP_ARGS(local, conf, address, iv32),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __array(u8, addr, 6)
+               __field(u32, iv32)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               memcpy(__entry->addr, address, 6);
+               __entry->iv32 = iv32;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " addr:%pM iv32:%#x",
+               LOCAL_PR_ARG, __entry->addr, __entry->iv32
+       )
+);
+
+TRACE_EVENT(drv_hw_scan,
+       TP_PROTO(struct ieee80211_local *local,
+                struct cfg80211_scan_request *req, int ret),
+
+       TP_ARGS(local, req, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ret:%d",
+               LOCAL_PR_ARG, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_sw_scan_start,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_sw_scan_complete,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_get_stats,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_low_level_stats *stats,
+                int ret),
+
+       TP_ARGS(local, stats, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+               __field(unsigned int, ackfail)
+               __field(unsigned int, rtsfail)
+               __field(unsigned int, fcserr)
+               __field(unsigned int, rtssucc)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+               __entry->ackfail = stats->dot11ACKFailureCount;
+               __entry->rtsfail = stats->dot11RTSFailureCount;
+               __entry->fcserr = stats->dot11FCSErrorCount;
+               __entry->rtssucc = stats->dot11RTSSuccessCount;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ret:%d",
+               LOCAL_PR_ARG, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_get_tkip_seq,
+       TP_PROTO(struct ieee80211_local *local,
+                u8 hw_key_idx, u32 *iv32, u16 *iv16),
+
+       TP_ARGS(local, hw_key_idx, iv32, iv16),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u8, hw_key_idx)
+               __field(u32, iv32)
+               __field(u16, iv16)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->hw_key_idx = hw_key_idx;
+               __entry->iv32 = *iv32;
+               __entry->iv16 = *iv16;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_set_rts_threshold,
+       TP_PROTO(struct ieee80211_local *local, u32 value, int ret),
+
+       TP_ARGS(local, value, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, value)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+               __entry->value = value;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " value:%d ret:%d",
+               LOCAL_PR_ARG, __entry->value, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_sta_notify,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_vif *vif,
+                enum sta_notify_cmd cmd,
+                struct ieee80211_sta *sta),
+
+       TP_ARGS(local, vif, cmd, sta),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(u32, cmd)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->cmd = cmd;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " cmd:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
+       )
+);
+
+TRACE_EVENT(drv_conf_tx,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                const struct ieee80211_tx_queue_params *params,
+                int ret),
+
+       TP_ARGS(local, queue, params, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u16, txop)
+               __field(u16, cw_min)
+               __field(u16, cw_max)
+               __field(u8, aifs)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->ret = ret;
+               __entry->txop = params->txop;
+               __entry->cw_max = params->cw_max;
+               __entry->cw_min = params->cw_min;
+               __entry->aifs = params->aifs;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d ret:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_get_tx_stats,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_tx_queue_stats *stats,
+                int ret),
+
+       TP_ARGS(local, stats, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ret:%d",
+               LOCAL_PR_ARG, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_get_tsf,
+       TP_PROTO(struct ieee80211_local *local, u64 ret),
+
+       TP_ARGS(local, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u64, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ret:%llu",
+               LOCAL_PR_ARG, (unsigned long long)__entry->ret
+       )
+);
+
+TRACE_EVENT(drv_set_tsf,
+       TP_PROTO(struct ieee80211_local *local, u64 tsf),
+
+       TP_ARGS(local, tsf),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u64, tsf)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->tsf = tsf;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " tsf:%llu",
+               LOCAL_PR_ARG, (unsigned long long)__entry->tsf
+       )
+);
+
+TRACE_EVENT(drv_reset_tsf,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_tx_last_beacon,
+       TP_PROTO(struct ieee80211_local *local, int ret),
+
+       TP_ARGS(local, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ret:%d",
+               LOCAL_PR_ARG, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_ampdu_action,
+       TP_PROTO(struct ieee80211_local *local,
+                enum ieee80211_ampdu_mlme_action action,
+                struct ieee80211_sta *sta, u16 tid,
+                u16 *ssn, int ret),
+
+       TP_ARGS(local, action, sta, tid, ssn, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(u32, action)
+               __field(u16, tid)
+               __field(u16, ssn)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->ret = ret;
+               __entry->action = action;
+               __entry->tid = tid;
+               __entry->ssn = *ssn;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  STA_PR_FMT " action:%d tid:%d ret:%d",
+               LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+       )
+);
+#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE driver-trace
+#include <trace/define_trace.h>
index 15d5a53..8e22200 100644 (file)
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
         */
        if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
                ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
-                                   sdata->u.ibss.bssid, 0);
+                                   sdata->u.ibss.bssid, NULL, 0, 0);
 }
 
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
 
        capability = WLAN_CAPABILITY_IBSS;
 
-       if (sdata->default_key)
+       if (ifibss->privacy)
                capability |= WLAN_CAPABILITY_PRIVACY;
        else
                sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                return;
 
        capability = WLAN_CAPABILITY_IBSS;
-       if (sdata->default_key)
+       if (ifibss->privacy)
                capability |= WLAN_CAPABILITY_PRIVACY;
-
        if (ifibss->fixed_bssid)
                bssid = ifibss->bssid;
        if (ifibss->fixed_channel)
@@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        } else
                sdata->u.ibss.fixed_bssid = false;
 
+       sdata->u.ibss.privacy = params->privacy;
+
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
 
        sdata->u.ibss.channel = params->channel;
index 327aabc..6a01771 100644 (file)
@@ -247,18 +247,22 @@ struct ieee80211_mgd_work {
 
        int tries;
 
+       u8 key[WLAN_KEY_LEN_WEP104];
+       u8 key_len, key_idx;
+
        /* must be last */
        u8 ie[0]; /* for auth or assoc frame, not probe */
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
 enum ieee80211_sta_flags {
-       IEEE80211_STA_PROBEREQ_POLL     = BIT(3),
-       IEEE80211_STA_CONTROL_PORT      = BIT(4),
-       IEEE80211_STA_WMM_ENABLED       = BIT(5),
-       IEEE80211_STA_DISABLE_11N       = BIT(6),
-       IEEE80211_STA_CSA_RECEIVED      = BIT(7),
-       IEEE80211_STA_MFP_ENABLED       = BIT(8),
+       IEEE80211_STA_BEACON_POLL       = BIT(0),
+       IEEE80211_STA_CONNECTION_POLL   = BIT(1),
+       IEEE80211_STA_CONTROL_PORT      = BIT(2),
+       IEEE80211_STA_WMM_ENABLED       = BIT(3),
+       IEEE80211_STA_DISABLE_11N       = BIT(4),
+       IEEE80211_STA_CSA_RECEIVED      = BIT(5),
+       IEEE80211_STA_MFP_ENABLED       = BIT(6),
 };
 
 /* flags for MLME request */
@@ -268,11 +272,16 @@ enum ieee80211_sta_request {
 
 struct ieee80211_if_managed {
        struct timer_list timer;
+       struct timer_list conn_mon_timer;
+       struct timer_list bcn_mon_timer;
        struct timer_list chswitch_timer;
        struct work_struct work;
+       struct work_struct monitor_work;
        struct work_struct chswitch_work;
        struct work_struct beacon_loss_work;
 
+       unsigned long probe_timeout;
+
        struct mutex mtx;
        struct ieee80211_bss *associated;
        struct list_head work_list;
@@ -289,8 +298,6 @@ struct ieee80211_if_managed {
 
        unsigned long request;
 
-       unsigned long last_beacon;
-
        unsigned int flags;
 
        u32 beacon_crc;
@@ -321,6 +328,7 @@ struct ieee80211_if_ibss {
 
        bool fixed_bssid;
        bool fixed_channel;
+       bool privacy;
 
        u8 bssid[ETH_ALEN];
        u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -559,14 +567,9 @@ enum queue_stop_reason {
        IEEE80211_QUEUE_STOP_REASON_CSA,
        IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
        IEEE80211_QUEUE_STOP_REASON_SUSPEND,
-       IEEE80211_QUEUE_STOP_REASON_PENDING,
        IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
 };
 
-struct ieee80211_master_priv {
-       struct ieee80211_local *local;
-};
-
 struct ieee80211_local {
        /* embed the driver visible part.
         * don't cast (use the static inlines below), but we keep
@@ -579,13 +582,20 @@ struct ieee80211_local {
        /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
        spinlock_t queue_stop_reason_lock;
 
-       struct net_device *mdev; /* wmaster# - "master" 802.11 device */
        int open_count;
        int monitors, cooked_mntrs;
        /* number of interfaces with corresponding FIF_ flags */
        int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
        unsigned int filter_flags; /* FIF_* */
        struct iw_statistics wstats;
+
+       /* protects the aggregated multicast list and filter calls */
+       spinlock_t filter_lock;
+
+       /* aggregated multicast list */
+       struct dev_addr_list *mc_list;
+       int mc_count;
+
        bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 
        /*
@@ -805,10 +815,6 @@ struct ieee80211_local {
 static inline struct ieee80211_sub_if_data *
 IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       BUG_ON(!local || local->mdev == dev);
-
        return netdev_priv(dev);
 }
 
@@ -988,7 +994,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(unsigned long data);
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
@@ -1093,8 +1098,8 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg,
-                        u8 *extra, size_t extra_len,
-                        const u8 *bssid, int encrypt);
+                        u8 *extra, size_t extra_len, const u8 *bssid,
+                        const u8 *key, u8 key_len, u8 key_idx);
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                             const u8 *ie, size_t ie_len);
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
index 4839a2d..2f797a8 100644 (file)
@@ -190,10 +190,6 @@ static int ieee80211_open(struct net_device *dev)
                               ETH_ALEN);
        }
 
-       if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
-               memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
-                      ETH_ALEN);
-
        /*
         * Validate the MAC address for this device.
         */
@@ -229,9 +225,9 @@ static int ieee80211_open(struct net_device *dev)
                if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
                        local->fif_other_bss++;
 
-               netif_addr_lock_bh(local->mdev);
+               spin_lock_bh(&local->filter_lock);
                ieee80211_configure_filter(local);
-               netif_addr_unlock_bh(local->mdev);
+               spin_unlock_bh(&local->filter_lock);
                break;
        default:
                conf.vif = &sdata->vif;
@@ -243,9 +239,9 @@ static int ieee80211_open(struct net_device *dev)
 
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
                        local->fif_other_bss++;
-                       netif_addr_lock_bh(local->mdev);
+                       spin_lock_bh(&local->filter_lock);
                        ieee80211_configure_filter(local);
-                       netif_addr_unlock_bh(local->mdev);
+                       spin_unlock_bh(&local->filter_lock);
 
                        ieee80211_start_mesh(sdata);
                }
@@ -279,10 +275,6 @@ static int ieee80211_open(struct net_device *dev)
        }
 
        if (local->open_count == 0) {
-               res = dev_open(local->mdev);
-               WARN_ON(res);
-               if (res)
-                       goto err_del_interface;
                tasklet_enable(&local->tx_pending_tasklet);
                tasklet_enable(&local->tasklet);
        }
@@ -393,7 +385,14 @@ static int ieee80211_stop(struct net_device *dev)
        if (sdata->flags & IEEE80211_SDATA_PROMISC)
                atomic_dec(&local->iff_promiscs);
 
-       dev_mc_unsync(local->mdev, dev);
+       netif_addr_lock_bh(dev);
+       spin_lock_bh(&local->filter_lock);
+       __dev_addr_unsync(&local->mc_list, &local->mc_count,
+                         &dev->mc_list, &dev->mc_count);
+       ieee80211_configure_filter(local);
+       spin_unlock_bh(&local->filter_lock);
+       netif_addr_unlock_bh(dev);
+
        del_timer_sync(&local->dynamic_ps_timer);
        cancel_work_sync(&local->dynamic_ps_enable_work);
 
@@ -442,23 +441,25 @@ static int ieee80211_stop(struct net_device *dev)
                if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
                        local->fif_other_bss--;
 
-               netif_addr_lock_bh(local->mdev);
+               spin_lock_bh(&local->filter_lock);
                ieee80211_configure_filter(local);
-               netif_addr_unlock_bh(local->mdev);
+               spin_unlock_bh(&local->filter_lock);
                break;
        case NL80211_IFTYPE_STATION:
                del_timer_sync(&sdata->u.mgd.chswitch_timer);
                del_timer_sync(&sdata->u.mgd.timer);
+               del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+               del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
                /*
-                * If the timer fired while we waited for it, it will have
-                * requeued the work. Now the work will be running again
+                * If any of the timers fired while we waited for it, it will
+                * have queued its work. Now the work will be running again
                 * but will not rearm the timer again because it checks
                 * whether the interface is running, which, at this point,
                 * it no longer is.
                 */
                cancel_work_sync(&sdata->u.mgd.work);
                cancel_work_sync(&sdata->u.mgd.chswitch_work);
-
+               cancel_work_sync(&sdata->u.mgd.monitor_work);
                cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
 
                /*
@@ -485,9 +486,9 @@ static int ieee80211_stop(struct net_device *dev)
                        local->fif_other_bss--;
                        atomic_dec(&local->iff_allmultis);
 
-                       netif_addr_lock_bh(local->mdev);
+                       spin_lock_bh(&local->filter_lock);
                        ieee80211_configure_filter(local);
-                       netif_addr_unlock_bh(local->mdev);
+                       spin_unlock_bh(&local->filter_lock);
 
                        ieee80211_stop_mesh(sdata);
                }
@@ -533,9 +534,6 @@ static int ieee80211_stop(struct net_device *dev)
        ieee80211_recalc_ps(local, -1);
 
        if (local->open_count == 0) {
-               if (netif_running(local->mdev))
-                       dev_close(local->mdev);
-
                drv_stop(local);
 
                ieee80211_led_radio(local, false);
@@ -582,8 +580,11 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
                        atomic_dec(&local->iff_promiscs);
                sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
-
-       dev_mc_sync(local->mdev, dev);
+       spin_lock_bh(&local->filter_lock);
+       __dev_addr_sync(&local->mc_list, &local->mc_count,
+                       &dev->mc_list, &dev->mc_count);
+       ieee80211_configure_filter(local);
+       spin_unlock_bh(&local->filter_lock);
 }
 
 /*
index 5b69f5f..3234f37 100644 (file)
@@ -83,75 +83,14 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        new_flags |= (1<<31);
 
        drv_configure_filter(local, changed_flags, &new_flags,
-                            local->mdev->mc_count,
-                            local->mdev->mc_list);
+                            local->mc_count,
+                            local->mc_list);
 
        WARN_ON(new_flags & (1<<31));
 
        local->filter_flags = new_flags & ~(1<<31);
 }
 
-/* master interface */
-
-static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
-{
-       memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-       return ETH_ALEN;
-}
-
-static const struct header_ops ieee80211_header_ops = {
-       .create         = eth_header,
-       .parse          = header_parse_80211,
-       .rebuild        = eth_rebuild_header,
-       .cache          = eth_header_cache,
-       .cache_update   = eth_header_cache_update,
-};
-
-static int ieee80211_master_open(struct net_device *dev)
-{
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
-       struct ieee80211_sub_if_data *sdata;
-       int res = -EOPNOTSUPP;
-
-       /* we hold the RTNL here so can safely walk the list */
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (netif_running(sdata->dev)) {
-                       res = 0;
-                       break;
-               }
-       }
-
-       if (res)
-               return res;
-
-       netif_tx_start_all_queues(local->mdev);
-
-       return 0;
-}
-
-static int ieee80211_master_stop(struct net_device *dev)
-{
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
-       struct ieee80211_sub_if_data *sdata;
-
-       /* we hold the RTNL here so can safely walk the list */
-       list_for_each_entry(sdata, &local->interfaces, list)
-               if (netif_running(sdata->dev))
-                       dev_close(sdata->dev);
-
-       return 0;
-}
-
-static void ieee80211_master_set_multicast_list(struct net_device *dev)
-{
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
-
-       ieee80211_configure_filter(local);
-}
-
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan, *scan_chan;
@@ -310,7 +249,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int tmp;
 
-       skb->dev = local->mdev;
        skb->pkt_type = IEEE80211_TX_STATUS_MSG;
        skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
                       &local->skb_queue : &local->skb_queue_unreliable, skb);
@@ -716,7 +654,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        mutex_init(&local->scan_mtx);
 
        spin_lock_init(&local->key_lock);
-
+       spin_lock_init(&local->filter_lock);
        spin_lock_init(&local->queue_stop_reason_lock);
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
@@ -752,30 +690,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
 
-static const struct net_device_ops ieee80211_master_ops = {
-       .ndo_start_xmit = ieee80211_master_start_xmit,
-       .ndo_open = ieee80211_master_open,
-       .ndo_stop = ieee80211_master_stop,
-       .ndo_set_multicast_list = ieee80211_master_set_multicast_list,
-       .ndo_select_queue = ieee80211_select_queue,
-};
-
-static void ieee80211_master_setup(struct net_device *mdev)
-{
-       mdev->type = ARPHRD_IEEE80211;
-       mdev->netdev_ops = &ieee80211_master_ops;
-       mdev->header_ops = &ieee80211_header_ops;
-       mdev->tx_queue_len = 1000;
-       mdev->addr_len = ETH_ALEN;
-}
-
 int ieee80211_register_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        int result;
        enum ieee80211_band band;
-       struct net_device *mdev;
-       struct ieee80211_master_priv *mpriv;
        int channels, i, j, max_bitrates;
        bool supp_ht;
        static const u32 cipher_suites[] = {
@@ -874,16 +793,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (hw->queues > IEEE80211_MAX_QUEUES)
                hw->queues = IEEE80211_MAX_QUEUES;
 
-       mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
-                              "wmaster%d", ieee80211_master_setup,
-                              hw->queues);
-       if (!mdev)
-               goto fail_mdev_alloc;
-
-       mpriv = netdev_priv(mdev);
-       mpriv->local = local;
-       local->mdev = mdev;
-
        local->hw.workqueue =
                create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
        if (!local->hw.workqueue) {
@@ -918,17 +827,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        }
 
        rtnl_lock();
-       result = dev_alloc_name(local->mdev, local->mdev->name);
-       if (result < 0)
-               goto fail_dev;
-
-       memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
-       SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
-       local->mdev->features |= NETIF_F_NETNS_LOCAL;
-
-       result = register_netdevice(local->mdev);
-       if (result < 0)
-               goto fail_dev;
 
        result = ieee80211_init_rate_ctrl_alg(local,
                                              hw->rate_control_algorithm);
@@ -981,9 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        ieee80211_led_exit(local);
        ieee80211_remove_interfaces(local);
  fail_rate:
-       unregister_netdevice(local->mdev);
-       local->mdev = NULL;
- fail_dev:
        rtnl_unlock();
        ieee80211_wep_free(local);
  fail_wep:
@@ -992,9 +887,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        debugfs_hw_del(local);
        destroy_workqueue(local->hw.workqueue);
  fail_workqueue:
-       if (local->mdev)
-               free_netdev(local->mdev);
- fail_mdev_alloc:
        wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
        kfree(local->int_scan_req.channels);
@@ -1019,13 +911,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
         * because the driver cannot be handing us frames any
         * more and the tasklet is killed.
         */
-
-       /* First, we remove all virtual interfaces. */
        ieee80211_remove_interfaces(local);
 
-       /* then, finally, remove the master interface */
-       unregister_netdevice(local->mdev);
-
        rtnl_unlock();
 
        ieee80211_clear_tx_pending(local);
@@ -1044,7 +931,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        wiphy_unregister(local->hw.wiphy);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
-       free_netdev(local->mdev);
        kfree(local->int_scan_req.channels);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
index 542ea02..8a97b14 100644 (file)
@@ -685,9 +685,12 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        fc = le16_to_cpu(mgmt->frame_control);
 
        switch (fc & IEEE80211_FCTL_STYPE) {
+       case IEEE80211_STYPE_ACTION:
+               if (skb->len < IEEE80211_MIN_ACTION_SIZE)
+                       return RX_DROP_MONITOR;
+               /* fall through */
        case IEEE80211_STYPE_PROBE_RESP:
        case IEEE80211_STYPE_BEACON:
-       case IEEE80211_STYPE_ACTION:
                skb_queue_tail(&ifmsh->skb_queue, skb);
                queue_work(local->hw.workqueue, &ifmsh->work);
                return RX_QUEUED;
index f49ef28..e93c37e 100644 (file)
@@ -686,11 +686,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
        u8 ttl, dst_flags;
        u32 lifetime;
 
-       spin_lock(&ifmsh->mesh_preq_queue_lock);
+       spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
        if (!ifmsh->preq_queue_len ||
                time_before(jiffies, ifmsh->last_preq +
                                min_preq_int_jiff(sdata))) {
-               spin_unlock(&ifmsh->mesh_preq_queue_lock);
+               spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
                return;
        }
 
@@ -698,7 +698,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                        struct mesh_preq_queue, list);
        list_del(&preq_node->list);
        --ifmsh->preq_queue_len;
-       spin_unlock(&ifmsh->mesh_preq_queue_lock);
+       spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
 
        rcu_read_lock();
        mpath = mesh_path_lookup(preq_node->dst, sdata);
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                mesh_path_add(dst_addr, sdata);
                mpath = mesh_path_lookup(dst_addr, sdata);
                if (!mpath) {
-                       dev_kfree_skb(skb);
                        sdata->u.mesh.mshstats.dropped_frames_no_route++;
                        err = -ENOSPC;
                        goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                memcpy(hdr->addr1, mpath->next_hop->sta.addr,
                                ETH_ALEN);
        } else {
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
                if (!(mpath->flags & MESH_PATH_RESOLVING)) {
                        /* Start discovery only if it is not running yet */
                        mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                        skb_unlink(skb_to_free, &mpath->frame_queue);
                }
 
+               info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                skb_queue_tail(&mpath->frame_queue, skb);
                if (skb_to_free)
                        mesh_path_discard_frame(skb_to_free, sdata);
index 479597e..04b9e4d 100644 (file)
@@ -55,7 +55,25 @@ static DEFINE_RWLOCK(pathtbl_resize_lock);
  */
 void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
 {
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       struct sk_buff_head tmpq;
+       unsigned long flags;
+
        rcu_assign_pointer(mpath->next_hop, sta);
+
+       __skb_queue_head_init(&tmpq);
+
+       spin_lock_irqsave(&mpath->frame_queue.lock, flags);
+
+       while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
+               hdr = (struct ieee80211_hdr *) skb->data;
+               memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+               __skb_queue_tail(&tmpq, skb);
+       }
+
+       skb_queue_splice(&tmpq, &mpath->frame_queue);
+       spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
 }
 
 
@@ -481,11 +499,9 @@ enddel:
  */
 void mesh_path_tx_pending(struct mesh_path *mpath)
 {
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&mpath->frame_queue)) &&
-                       (mpath->flags & MESH_PATH_ACTIVE))
-               dev_queue_xmit(skb);
+       if (mpath->flags & MESH_PATH_ACTIVE)
+               ieee80211_add_pending_skbs(mpath->sdata->local,
+                               &mpath->frame_queue);
 }
 
 /**
index c9db964..523c0d9 100644 (file)
 #define IEEE80211_AUTH_MAX_TRIES 3
 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
 #define IEEE80211_ASSOC_MAX_TRIES 3
-#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_PROBE_WAIT (HZ / 5)
+
+/*
+ * beacon loss detection timeout
+ * XXX: should depend on beacon interval
+ */
+#define IEEE80211_BEACON_LOSS_TIME     (2 * HZ)
+/*
+ * Time the connection can be idle before we probe
+ * it to see if we can still talk to the AP.
+ */
+#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ)
+/*
+ * Time we wait for a probe response after sending
+ * a probe request because of beacon loss or for
+ * checking the connection still works.
+ */
+#define IEEE80211_PROBE_WAIT           (HZ / 5)
 
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
@@ -72,6 +87,35 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
        WARN_ON(!mutex_is_locked(&ifmgd->mtx));
 }
 
+/*
+ * We can have multiple work items (and connection probing)
+ * scheduling this timer, but we need to take care to only
+ * reschedule it when it should fire _earlier_ than it was
+ * asked for before, or if it's not pending right now. This
+ * function ensures that. Note that it then is required to
+ * run this function for all timeouts after the first one
+ * has happened -- the work that runs from this timer will
+ * do that.
+ */
+static void run_again(struct ieee80211_if_managed *ifmgd,
+                            unsigned long timeout)
+{
+       ASSERT_MGD_MTX(ifmgd);
+
+       if (!timer_pending(&ifmgd->timer) ||
+           time_before(timeout, ifmgd->timer.expires))
+               mod_timer(&ifmgd->timer, timeout);
+}
+
+static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
+{
+       if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER)
+               return;
+
+       mod_timer(&sdata->u.mgd.bcn_mon_timer,
+                 round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
+}
+
 static int ecw2cw(int ecw)
 {
        return (1 << ecw) - 1;
@@ -646,7 +690,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 
        if (count == 1 && found->u.mgd.powersave &&
            found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
-           !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
+           !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+                                   IEEE80211_STA_CONNECTION_POLL))) {
                s32 beaconint_us;
 
                if (latency < 0)
@@ -852,6 +897,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        sdata->u.mgd.associated = bss;
        memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
 
+       /* just to be sure */
+       sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+                               IEEE80211_STA_BEACON_POLL);
+
        ieee80211_led_assoc(local, 1);
 
        sdata->vif.bss_conf.assoc = 1;
@@ -916,7 +965,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
        ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
 
        wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-       mod_timer(&ifmgd->timer, wk->timeout);
+       run_again(ifmgd, wk->timeout);
 
        return RX_MGMT_NONE;
 }
@@ -954,25 +1003,30 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
               sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
 
        ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
-                           wk->bss->cbss.bssid, 0);
+                           wk->bss->cbss.bssid, NULL, 0, 0);
        wk->auth_transaction = 2;
 
        wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-       mod_timer(&ifmgd->timer, wk->timeout);
+       run_again(ifmgd, wk->timeout);
 
        return RX_MGMT_NONE;
 }
 
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-                                  const u8 *bssid, bool deauth)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        u32 changed = 0, config_changed = 0;
+       u8 bssid[ETH_ALEN];
 
        ASSERT_MGD_MTX(ifmgd);
 
+       if (WARN_ON(!ifmgd->associated))
+               return;
+
+       memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+
        ifmgd->associated = NULL;
        memset(ifmgd->bssid, 0, ETH_ALEN);
 
@@ -1079,7 +1133,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
        ieee80211_send_assoc(sdata, wk);
 
        wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
-       mod_timer(&ifmgd->timer, wk->timeout);
+       run_again(ifmgd, wk->timeout);
 
        return RX_MGMT_NONE;
 }
@@ -1092,31 +1146,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
         * from AP because we know that the connection is working both ways
         * at that time. But multicast frames (and hence also beacons) must
         * be ignored here, because we need to trigger the timer during
-        * data idle periods for sending the periodical probe request to
-        * the AP.
+        * data idle periods for sending the periodic probe request to the
+        * AP we're connected to.
         */
-       if (!is_multicast_ether_addr(hdr->addr1))
-               mod_timer(&sdata->u.mgd.timer,
-                         jiffies + IEEE80211_MONITORING_INTERVAL);
+       if (is_multicast_ether_addr(hdr->addr1))
+               return;
+
+       mod_timer(&sdata->u.mgd.conn_mon_timer,
+                 round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
 }
 
-void ieee80211_beacon_loss_work(struct work_struct *work)
+static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
+                                  bool beacon)
 {
-       struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data,
-                            u.mgd.beacon_loss_work);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        const u8 *ssid;
+       bool already = false;
 
-       /*
-        * The driver has already reported this event and we have
-        * already sent a probe request. Maybe the AP died and the
-        * driver keeps reporting until we disassociate... We have
-        * to ignore that because otherwise we would continually
-        * reset the timer and never check whether we received a
-        * probe response!
-        */
-       if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+       if (!netif_running(sdata->dev))
                return;
 
        mutex_lock(&ifmgd->mtx);
@@ -1125,12 +1172,35 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
                goto out;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       if (net_ratelimit())
-               printk(KERN_DEBUG "%s: driver reports beacon loss from AP "
+       if (beacon && net_ratelimit())
+               printk(KERN_DEBUG "%s: detected beacon loss from AP "
                       "- sending probe request\n", sdata->dev->name);
 #endif
 
-       ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+       /*
+        * The driver/our work has already reported this event or the
+        * connection monitoring has kicked in and we have already sent
+        * a probe request. Or maybe the AP died and the driver keeps
+        * reporting until we disassociate...
+        *
+        * In either case we have to ignore the current call to this
+        * function (except for setting the correct probe reason bit)
+        * because otherwise we would reset the timer every time and
+        * never check whether we received a probe response!
+        */
+       if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+                           IEEE80211_STA_CONNECTION_POLL))
+               already = true;
+
+       if (beacon)
+               ifmgd->flags |= IEEE80211_STA_BEACON_POLL;
+       else
+               ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
+
+       if (already)
+               goto out;
+
+       ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
 
        mutex_lock(&sdata->local->iflist_mtx);
        ieee80211_recalc_ps(sdata->local, -1);
@@ -1140,11 +1210,21 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
        ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
                                 ssid + 2, ssid[1], NULL, 0);
 
-       mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
+       run_again(ifmgd, ifmgd->probe_timeout);
+
  out:
        mutex_unlock(&ifmgd->mtx);
 }
 
+void ieee80211_beacon_loss_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data,
+                            u.mgd.beacon_loss_work);
+
+       ieee80211_mgd_probe_ap(sdata, true);
+}
+
 void ieee80211_beacon_loss(struct ieee80211_vif *vif)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -1176,7 +1256,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
                return;
        ieee80211_send_auth(sdata, 3, wk->auth_alg,
                            elems.challenge - 2, elems.challenge_len + 2,
-                           wk->bss->cbss.bssid, 1);
+                           wk->bss->cbss.bssid,
+                           wk->key, wk->key_len, wk->key_idx);
        wk->auth_transaction = 4;
 }
 
@@ -1257,7 +1338,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
                        sdata->dev->name, bssid, reason_code);
 
        if (!wk) {
-               ieee80211_set_disassoc(sdata, bssid, true);
+               ieee80211_set_disassoc(sdata);
        } else {
                list_del(&wk->list);
                kfree(wk);
@@ -1290,7 +1371,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
                        sdata->dev->name, reason_code);
 
-       ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false);
+       ieee80211_set_disassoc(sdata);
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
@@ -1349,8 +1430,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                       sdata->dev->name, tu, ms);
                wk->timeout = jiffies + msecs_to_jiffies(ms);
                if (ms > IEEE80211_ASSOC_TIMEOUT)
-                       mod_timer(&ifmgd->timer,
-                                 jiffies + msecs_to_jiffies(ms));
+                       run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
                return RX_MGMT_NONE;
        }
 
@@ -1392,9 +1472,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                        return RX_MGMT_NONE;
                }
 
-               /* update new sta with its last rx activity */
-               sta->last_rx = jiffies;
-
                set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
                                   WLAN_STA_ASSOC_AP);
                if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -1497,10 +1574,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        ieee80211_set_associated(sdata, wk->bss, changed);
 
        /*
-        * initialise the time of last beacon to be the association time,
-        * otherwise beacon loss check will trigger immediately
+        * Start timer to probe the connection to the AP now.
+        * Also start the timer that will detect beacon loss.
         */
-       ifmgd->last_beacon = jiffies;
+       ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
+       mod_beacon_timer(sdata);
 
        list_del(&wk->list);
        kfree(wk);
@@ -1584,11 +1662,22 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        if (ifmgd->associated &&
            memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
-           ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
-               ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+           ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+                           IEEE80211_STA_CONNECTION_POLL)) {
+               ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+                                 IEEE80211_STA_BEACON_POLL);
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_ps(sdata->local, -1);
                mutex_unlock(&sdata->local->iflist_mtx);
+               /*
+                * We've received a probe response, but are not sure whether
+                * we have or will be receiving any beacons or data, so let's
+                * schedule the timers again, just in case.
+                */
+               mod_beacon_timer(sdata);
+               mod_timer(&ifmgd->conn_mon_timer,
+                         round_jiffies_up(jiffies +
+                                          IEEE80211_CONNECTION_IDLE_TIME));
        }
 }
 
@@ -1638,27 +1727,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (rx_status->freq != local->hw.conf.channel->center_freq)
                return;
 
-       if (WARN_ON(!ifmgd->associated))
+       /*
+        * We might have received a number of frames, among them a
+        * disassoc frame and a beacon...
+        */
+       if (!ifmgd->associated)
                return;
 
        bssid = ifmgd->associated->cbss.bssid;
 
-       if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0))
+       /*
+        * And in theory even frames from a different AP we were just
+        * associated to a split-second ago!
+        */
+       if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
-       if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+       if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: cancelling probereq poll due "
                               "to a received beacon\n", sdata->dev->name);
                }
 #endif
-               ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+               ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
                mutex_lock(&local->iflist_mtx);
                ieee80211_recalc_ps(local, -1);
                mutex_unlock(&local->iflist_mtx);
        }
 
+       /*
+        * Push the beacon loss detection into the future since
+        * we are processing a beacon from the AP just now.
+        */
+       mod_beacon_timer(sdata);
+
        ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
        ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
                                          len - baselen, &elems,
@@ -1960,6 +2063,37 @@ static void ieee80211_sta_work(struct work_struct *work)
        /* then process the rest of the work */
        mutex_lock(&ifmgd->mtx);
 
+       if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+                           IEEE80211_STA_CONNECTION_POLL) &&
+           ifmgd->associated) {
+               if (time_is_after_jiffies(ifmgd->probe_timeout))
+                       run_again(ifmgd, ifmgd->probe_timeout);
+               else {
+                       u8 bssid[ETH_ALEN];
+                       /*
+                        * We actually lost the connection ... or did we?
+                        * Let's make sure!
+                        */
+                       ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+                                         IEEE80211_STA_BEACON_POLL);
+                       memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+                       printk(KERN_DEBUG "No probe response from AP %pM"
+                               " after %dms, disconnecting.\n",
+                               bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
+                       ieee80211_set_disassoc(sdata);
+                       mutex_unlock(&ifmgd->mtx);
+                       /*
+                        * must be outside lock due to cfg80211,
+                        * but that's not a problem.
+                        */
+                       ieee80211_send_deauth_disassoc(sdata, bssid,
+                                       IEEE80211_STYPE_DEAUTH,
+                                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+                                       NULL);
+                       mutex_lock(&ifmgd->mtx);
+               }
+       }
+
        list_for_each_entry(wk, &ifmgd->work_list, list) {
                if (wk->state != IEEE80211_MGD_STATE_IDLE) {
                        anybusy = true;
@@ -1980,8 +2114,15 @@ static void ieee80211_sta_work(struct work_struct *work)
        }
 
        list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
-               if (time_before(jiffies, wk->timeout))
+               if (time_is_after_jiffies(wk->timeout)) {
+                       /*
+                        * This work item isn't supposed to be worked on
+                        * right now, but take care to adjust the timer
+                        * properly.
+                        */
+                       run_again(ifmgd, wk->timeout);
                        continue;
+               }
 
                switch (wk->state) {
                default:
@@ -2040,15 +2181,54 @@ static void ieee80211_sta_work(struct work_struct *work)
        ieee80211_recalc_idle(local);
 }
 
+static void ieee80211_sta_bcn_mon_timer(unsigned long data)
+{
+       struct ieee80211_sub_if_data *sdata =
+               (struct ieee80211_sub_if_data *) data;
+       struct ieee80211_local *local = sdata->local;
+
+       if (local->quiescing)
+               return;
+
+       queue_work(sdata->local->hw.workqueue,
+                  &sdata->u.mgd.beacon_loss_work);
+}
+
+static void ieee80211_sta_conn_mon_timer(unsigned long data)
+{
+       struct ieee80211_sub_if_data *sdata =
+               (struct ieee80211_sub_if_data *) data;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_local *local = sdata->local;
+
+       if (local->quiescing)
+               return;
+
+       queue_work(local->hw.workqueue, &ifmgd->monitor_work);
+}
+
+static void ieee80211_sta_monitor_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data,
+                            u.mgd.monitor_work);
+
+       if (sdata->local->sw_scanning || sdata->local->hw_scanning)
+               return;
+
+       ieee80211_mgd_probe_ap(sdata, false);
+}
+
 static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
 {
        if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               /*
-                * Need to update last_beacon to avoid beacon loss
-                * test to trigger.
-                */
-               sdata->u.mgd.last_beacon = jiffies;
+               sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL |
+                                       IEEE80211_STA_CONNECTION_POLL);
 
+               /* let's probe the connection once */
+               queue_work(sdata->local->hw.workqueue,
+                          &sdata->u.mgd.monitor_work);
+               /* and do all the other regular work too */
                queue_work(sdata->local->hw.workqueue,
                           &sdata->u.mgd.work);
        }
@@ -2073,6 +2253,11 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
        cancel_work_sync(&ifmgd->chswitch_work);
        if (del_timer_sync(&ifmgd->chswitch_timer))
                set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
+
+       cancel_work_sync(&ifmgd->monitor_work);
+       /* these will just be re-established on connection */
+       del_timer_sync(&ifmgd->conn_mon_timer);
+       del_timer_sync(&ifmgd->bcn_mon_timer);
 }
 
 void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
@@ -2093,10 +2278,15 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 
        ifmgd = &sdata->u.mgd;
        INIT_WORK(&ifmgd->work, ieee80211_sta_work);
+       INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
        INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
        INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
        setup_timer(&ifmgd->timer, ieee80211_sta_timer,
                    (unsigned long) sdata);
+       setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
+                   (unsigned long) sdata);
+       setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer,
+                   (unsigned long) sdata);
        setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
                    (unsigned long) sdata);
        skb_queue_head_init(&ifmgd->skb_queue);
@@ -2175,6 +2365,12 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                wk->ie_len = req->ie_len;
        }
 
+       if (req->key && req->key_len) {
+               wk->key_len = req->key_len;
+               wk->key_idx = req->key_idx;
+               memcpy(wk->key, req->key, req->key_len);
+       }
+
        ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
        memcpy(wk->ssid, ssid + 2, ssid[1]);
        wk->ssid_len = ssid[1];
@@ -2290,7 +2486,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
        if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
                bssid = req->bss->bssid;
-               ieee80211_set_disassoc(sdata, bssid, true);
+               ieee80211_set_disassoc(sdata);
        } else list_for_each_entry(wk, &ifmgd->work_list, list) {
                if (&wk->bss->cbss == req->bss) {
                        bssid = req->bss->bssid;
@@ -2332,7 +2528,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                return -ENOLINK;
        }
 
-       ieee80211_set_disassoc(sdata, req->bss->bssid, false);
+       ieee80211_set_disassoc(sdata);
 
        mutex_unlock(&ifmgd->mtx);
 
index 4641f00..b33efc4 100644 (file)
@@ -198,6 +198,35 @@ static void rate_control_release(struct kref *kref)
        kfree(ctrl_ref);
 }
 
+static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
+{
+       struct sk_buff *skb = txrc->skb;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       __le16 fc;
+
+       fc = hdr->frame_control;
+
+       return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
+}
+
+bool rate_control_send_low(struct ieee80211_sta *sta,
+                          void *priv_sta,
+                          struct ieee80211_tx_rate_control *txrc)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+
+       if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
+               info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
+               info->control.rates[0].count =
+                       (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+                       1 : txrc->hw->max_rate_tries;
+               return true;
+       }
+       return false;
+}
+EXPORT_SYMBOL(rate_control_send_low);
+
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                           struct sta_info *sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -258,7 +287,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
        struct rate_control_ref *ref, *old;
 
        ASSERT_RTNL();
-       if (local->open_count || netif_running(local->mdev))
+       if (local->open_count)
                return -EBUSY;
 
        ref = rate_control_alloc(name, local);
index 37771ab..7c51429 100644 (file)
@@ -70,20 +70,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
        return i;
 }
 
-static inline bool
-use_low_rate(struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       u16 fc;
-
-       fc = le16_to_cpu(hdr->frame_control);
-
-       return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
-               (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA);
-}
-
-
 static void
 minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
 {
@@ -232,7 +218,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                  void *priv_sta, struct ieee80211_tx_rate_control *txrc)
 {
        struct sk_buff *skb = txrc->skb;
-       struct ieee80211_supported_band *sband = txrc->sband;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct minstrel_sta_info *mi = priv_sta;
        struct minstrel_priv *mp = priv;
@@ -245,14 +230,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        int mrr_ndx[3];
        int sample_rate;
 
-       if (!sta || !mi || use_low_rate(skb)) {
-               ar[0].idx = rate_lowest_index(sband, sta);
-               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
-                       ar[0].count = 1;
-               else
-                       ar[0].count = mp->max_retry;
+       if (rate_control_send_low(sta, priv_sta, txrc))
                return;
-       }
 
        mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
 
index a0bef76..8c053be 100644 (file)
@@ -276,11 +276,9 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
 {
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_supported_band *sband = txrc->sband;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct rc_pid_sta_info *spinfo = priv_sta;
        int rateidx;
-       u16 fc;
 
        if (txrc->rts)
                info->control.rates[0].count =
@@ -290,16 +288,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
                        txrc->hw->conf.short_frame_max_tx_count;
 
        /* Send management frames and NO_ACK data using lowest rate. */
-       fc = le16_to_cpu(hdr->frame_control);
-       if (!sta || !spinfo ||
-           (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           info->flags & IEEE80211_TX_CTL_NO_ACK) {
-               info->control.rates[0].idx = rate_lowest_index(sband, sta);
-               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
-                       info->control.rates[0].count = 1;
-
+       if (rate_control_send_low(sta, priv_sta, txrc))
                return;
-       }
 
        rateidx = spinfo->txrate_idx;
 
index fe6b990..66c797c 100644 (file)
@@ -833,28 +833,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (!sta)
                return RX_CONTINUE;
 
-       /* Update last_rx only for IBSS packets which are for the current
-        * BSSID to avoid keeping the current IBSS network alive in cases where
-        * other STAs are using different BSSID. */
+       /*
+        * Update last_rx only for IBSS packets which are for the current
+        * BSSID to avoid keeping the current IBSS network alive in cases
+        * where other STAs start using different BSSID.
+        */
        if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
                                                NL80211_IFTYPE_ADHOC);
                if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
                        sta->last_rx = jiffies;
-       } else
-       if (!is_multicast_ether_addr(hdr->addr1) ||
-           rx->sdata->vif.type == NL80211_IFTYPE_STATION) {
-               /* Update last_rx only for unicast frames in order to prevent
-                * the Probe Request frames (the only broadcast frames from a
-                * STA in infrastructure mode) from keeping a connection alive.
+       } else if (!is_multicast_ether_addr(hdr->addr1)) {
+               /*
                 * Mesh beacons will update last_rx when if they are found to
                 * match the current local configuration when processed.
                 */
-               if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
-                   ieee80211_is_beacon(hdr->frame_control)) {
-                       rx->sdata->u.mgd.last_beacon = jiffies;
-               } else
-                       sta->last_rx = jiffies;
+               sta->last_rx = jiffies;
        }
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -1484,10 +1478,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct ieee80211s_hdr *mesh_hdr;
        unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_sub_if_data *sdata;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
        if (!ieee80211_is_data(hdr->frame_control))
                return RX_CONTINUE;
@@ -1497,10 +1494,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
-               struct ieee80211_sub_if_data *sdata;
                struct mesh_path *mppath;
 
-               sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
                rcu_read_lock();
                mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
                if (!mppath) {
@@ -1526,6 +1521,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                                                     dropped_frames_ttl);
                else {
                        struct ieee80211_hdr *fwd_hdr;
+                       struct ieee80211_tx_info *info;
+
                        fwd_skb = skb_copy(skb, GFP_ATOMIC);
 
                        if (!fwd_skb && net_ratelimit())
@@ -1539,9 +1536,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                         */
                        memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
                        memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
-                       fwd_skb->dev = rx->local->mdev;
+                       info = IEEE80211_SKB_CB(fwd_skb);
+                       memset(info, 0, sizeof(*info));
+                       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        fwd_skb->iif = rx->dev->ifindex;
-                       dev_queue_xmit(fwd_skb);
+                       ieee80211_select_queue(local, fwd_skb);
+                       if (is_multicast_ether_addr(fwd_hdr->addr3))
+                               memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+                                               ETH_ALEN);
+                       else {
+                               int err = mesh_nexthop_lookup(fwd_skb, sdata);
+                               /* Failed to immediately resolve next hop:
+                                * fwded frame was dropped or will be added
+                                * later to the pending skb queue.  */
+                               if (err)
+                                       return RX_DROP_MONITOR;
+                       }
+                       IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                    fwded_frames);
+                       ieee80211_add_pending_skb(local, fwd_skb);
                }
        }
 
@@ -1809,8 +1822,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        return RX_DROP_MONITOR;
 }
 
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
-                                           struct ieee80211_hdr *hdr,
+static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
                                            struct ieee80211_rx_data *rx)
 {
        int keyidx;
@@ -2120,7 +2132,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        }
 
        if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-               ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
+               ieee80211_rx_michael_mic_report(hdr, &rx);
                return;
        }
 
@@ -2489,7 +2501,6 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
 
-       skb->dev = local->mdev;
        skb->pkt_type = IEEE80211_RX_MSG;
        skb_queue_tail(&local->skb_queue, skb);
        tasklet_schedule(&local->tasklet);
index 5f4f786..7482065 100644 (file)
@@ -294,16 +294,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        if (was_hw_scan)
                goto done;
 
-       netif_tx_lock_bh(local->mdev);
-       netif_addr_lock(local->mdev);
+       spin_lock_bh(&local->filter_lock);
        local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
        drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
                             &local->filter_flags,
-                            local->mdev->mc_count,
-                            local->mdev->mc_list);
-
-       netif_addr_unlock(local->mdev);
-       netif_tx_unlock_bh(local->mdev);
+                            local->mc_count,
+                            local->mc_list);
+       spin_unlock_bh(&local->filter_lock);
 
        drv_sw_scan_complete(local);
 
@@ -382,13 +379,13 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        local->scan_state = SCAN_SET_CHANNEL;
        local->scan_channel_idx = 0;
 
-       netif_addr_lock_bh(local->mdev);
+       spin_lock_bh(&local->filter_lock);
        local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
        drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
                             &local->filter_flags,
-                            local->mdev->mc_count,
-                            local->mdev->mc_list);
-       netif_addr_unlock_bh(local->mdev);
+                            local->mc_count,
+                            local->mc_list);
+       spin_unlock_bh(&local->filter_lock);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */
        queue_delayed_work(local->hw.workqueue, &local->scan_work,
index 60ae086..2572509 100644 (file)
@@ -451,7 +451,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
-       if (unlikely(tx->skb->do_not_encrypt))
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
                tx->key = NULL;
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
@@ -497,7 +497,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        }
 
        if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               tx->skb->do_not_encrypt = 1;
+               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 
        return TX_CONTINUE;
 }
@@ -512,6 +512,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        int i, len;
        bool inval = false, rts = false, short_preamble = false;
        struct ieee80211_tx_rate_control txrc;
+       u32 sta_flags;
 
        memset(&txrc, 0, sizeof(txrc));
 
@@ -544,7 +545,26 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
             (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
                txrc.short_preamble = short_preamble = true;
 
+       sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+
+       /*
+        * Lets not bother rate control if we're associated and cannot
+        * talk to the sta. This should not happen.
+        */
+       if (WARN((tx->local->sw_scanning) &&
+                (sta_flags & WLAN_STA_ASSOC) &&
+                !rate_usable_index_exists(sband, &tx->sta->sta),
+                "%s: Dropped data frame as no usable bitrate found while "
+                "scanning and associated. Target station: "
+                "%pM on %d GHz band\n",
+                tx->dev->name, hdr->addr1,
+                tx->channel->band ? 5 : 2))
+               return TX_DROP;
 
+       /*
+        * If we're associated with the sta at this point we know we can at
+        * least send the frame at the lowest bit rate.
+        */
        rate_control_get_rate(tx->sdata, tx->sta, &txrc);
 
        if (unlikely(info->control.rates[0].idx < 0))
@@ -754,9 +774,7 @@ static int ieee80211_fragment(struct ieee80211_local *local,
                memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
                skb_copy_queue_mapping(tmp, skb);
                tmp->priority = skb->priority;
-               tmp->do_not_encrypt = skb->do_not_encrypt;
                tmp->dev = skb->dev;
-               tmp->iif = skb->iif;
 
                /* copy header and data */
                memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen);
@@ -784,7 +802,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 
        /*
         * Warn when submitting a fragmented A-MPDU frame and drop it.
-        * This scenario is handled in __ieee80211_tx_prepare but extra
+        * This scenario is handled in ieee80211_tx_prepare but extra
         * caution taken here as fragmented ampdu may cause Tx stop.
         */
        if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
@@ -923,11 +941,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
        struct ieee80211_radiotap_header *rthdr =
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       skb->do_not_encrypt = 1;
+       info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
        /*
@@ -965,7 +984,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                                skb_trim(skb, skb->len - FCS_LEN);
                        }
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
-                               tx->skb->do_not_encrypt = 0;
+                               info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
                                tx->flags |= IEEE80211_TX_FRAGMENTED;
                        break;
@@ -998,13 +1017,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
  * initialises @tx
  */
 static ieee80211_tx_result
-__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
-                      struct sk_buff *skb,
-                      struct net_device *dev)
+ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
+                    struct ieee80211_tx_data *tx,
+                    struct sk_buff *skb)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_hdr *hdr;
-       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int hdrlen, tid;
        u8 *qc, *state;
@@ -1012,9 +1030,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 
        memset(tx, 0, sizeof(*tx));
        tx->skb = skb;
-       tx->dev = dev; /* use original interface */
+       tx->dev = sdata->dev; /* use original interface */
        tx->local = local;
-       tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       tx->sdata = sdata;
        tx->channel = local->hw.conf.channel;
        /*
         * Set this flag (used below to indicate "automatic fragmentation"),
@@ -1023,7 +1041,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        tx->flags |= IEEE80211_TX_FRAGMENTED;
 
        /* process and remove the injection radiotap header */
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
                if (!__ieee80211_parse_tx_radiotap(tx, skb))
                        return TX_DROP;
@@ -1119,50 +1136,28 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        return TX_CONTINUE;
 }
 
-/*
- * NB: @tx is uninitialised when passed in here
- */
-static int ieee80211_tx_prepare(struct ieee80211_local *local,
-                               struct ieee80211_tx_data *tx,
-                               struct sk_buff *skb)
-{
-       struct net_device *dev;
-
-       dev = dev_get_by_index(&init_net, skb->iif);
-       if (unlikely(dev && !is_ieee80211_device(local, dev))) {
-               dev_put(dev);
-               dev = NULL;
-       }
-       if (unlikely(!dev))
-               return -ENODEV;
-       /*
-        * initialises tx with control
-        *
-        * return value is safe to ignore here because this function
-        * can only be invoked for multicast frames
-        *
-        * XXX: clean up
-        */
-       __ieee80211_tx_prepare(tx, skb, dev);
-       dev_put(dev);
-       return 0;
-}
-
 static int __ieee80211_tx(struct ieee80211_local *local,
                          struct sk_buff **skbp,
-                         struct sta_info *sta)
+                         struct sta_info *sta,
+                         bool txpending)
 {
        struct sk_buff *skb = *skbp, *next;
        struct ieee80211_tx_info *info;
+       unsigned long flags;
        int ret, len;
        bool fragm = false;
 
-       local->mdev->trans_start = jiffies;
-
        while (skb) {
-               if (ieee80211_queue_stopped(&local->hw,
-                                           skb_get_queue_mapping(skb)))
-                       return IEEE80211_TX_PENDING;
+               int q = skb_get_queue_mapping(skb);
+
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               ret = IEEE80211_TX_OK;
+               if (local->queue_stop_reasons[q] ||
+                   (!txpending && !skb_queue_empty(&local->pending[q])))
+                       ret = IEEE80211_TX_PENDING;
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+               if (ret != IEEE80211_TX_OK)
+                       return ret;
 
                info = IEEE80211_SKB_CB(skb);
 
@@ -1234,10 +1229,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        return 0;
 }
 
-static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
-                        bool txpending)
+static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+                        struct sk_buff *skb, bool txpending)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_data tx;
        ieee80211_tx_result res_prepare;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1248,8 +1243,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 
        queue = skb_get_queue_mapping(skb);
 
-       WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue]));
-
        if (unlikely(skb->len < 10)) {
                dev_kfree_skb(skb);
                return;
@@ -1258,7 +1251,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
        rcu_read_lock();
 
        /* initialises tx */
-       res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
+       res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
 
        if (unlikely(res_prepare == TX_DROP)) {
                dev_kfree_skb(skb);
@@ -1277,7 +1270,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 
        retries = 0;
  retry:
-       ret = __ieee80211_tx(local, &tx.skb, tx.sta);
+       ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
        switch (ret) {
        case IEEE80211_TX_OK:
                break;
@@ -1295,34 +1288,35 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 
                spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 
-               if (__netif_subqueue_stopped(local->mdev, queue)) {
+               if (local->queue_stop_reasons[queue] ||
+                   !skb_queue_empty(&local->pending[queue])) {
+                       /*
+                        * if queue is stopped, queue up frames for later
+                        * transmission from the tasklet
+                        */
                        do {
                                next = skb->next;
                                skb->next = NULL;
                                if (unlikely(txpending))
-                                       skb_queue_head(&local->pending[queue],
-                                                      skb);
+                                       __skb_queue_head(&local->pending[queue],
+                                                        skb);
                                else
-                                       skb_queue_tail(&local->pending[queue],
-                                                      skb);
+                                       __skb_queue_tail(&local->pending[queue],
+                                                        skb);
                        } while ((skb = next));
 
-                       /*
-                        * Make sure nobody will enable the queue on us
-                        * (without going through the tasklet) nor disable the
-                        * netdev queue underneath the pending handling code.
-                        */
-                       __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
-                                 &local->queue_stop_reasons[queue]);
-
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                               flags);
                } else {
+                       /*
+                        * otherwise retry, but this is a race condition or
+                        * a driver bug (which we warn about if it persists)
+                        */
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                               flags);
 
                        retries++;
-                       if (WARN(retries > 10, "tx refused but queue active"))
+                       if (WARN(retries > 10, "tx refused but queue active\n"))
                                goto drop;
                        goto retry;
                }
@@ -1383,14 +1377,13 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
        return 0;
 }
 
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+                          struct sk_buff *skb)
 {
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct net_device *odev = NULL;
-       struct ieee80211_sub_if_data *osdata;
+       struct ieee80211_sub_if_data *tmp_sdata;
        int headroom;
        bool may_encrypt;
        enum {
@@ -1399,20 +1392,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                UNKNOWN_ADDRESS,
        } monitor_iface = NOT_MONITOR;
 
-       if (skb->iif)
-               odev = dev_get_by_index(&init_net, skb->iif);
-       if (unlikely(odev && !is_ieee80211_device(local, odev))) {
-               dev_put(odev);
-               odev = NULL;
-       }
-       if (unlikely(!odev)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
-                      "originating device\n", dev->name);
-#endif
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
+       dev_hold(sdata->dev);
 
        if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
            local->hw.conf.dynamic_ps_timeout > 0 &&
@@ -1428,26 +1408,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
 
-       memset(info, 0, sizeof(*info));
-
        info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-       osdata = IEEE80211_DEV_TO_SUB_IF(odev);
-
-       if (ieee80211_vif_is_mesh(&osdata->vif) &&
+       if (ieee80211_vif_is_mesh(&sdata->vif) &&
            ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr3))
                        memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
                else
-                       if (mesh_nexthop_lookup(skb, osdata)) {
-                               dev_put(odev);
-                               return NETDEV_TX_OK;
+                       if (mesh_nexthop_lookup(skb, sdata)) {
+                               dev_put(sdata->dev);
+                               return;
                        }
-               if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-                       IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
-                                                           fwded_frames);
-       } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
-               struct ieee80211_sub_if_data *sdata;
+       } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
                int hdrlen;
                u16 len_rthdr;
 
@@ -1471,19 +1443,17 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                         */
 
                        rcu_read_lock();
-                       list_for_each_entry_rcu(sdata, &local->interfaces,
+                       list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
                                                list) {
-                               if (!netif_running(sdata->dev))
+                               if (!netif_running(tmp_sdata->dev))
                                        continue;
-                               if (sdata->vif.type != NL80211_IFTYPE_AP)
+                               if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
                                        continue;
-                               if (compare_ether_addr(sdata->dev->dev_addr,
+                               if (compare_ether_addr(tmp_sdata->dev->dev_addr,
                                                       hdr->addr2)) {
-                                       dev_hold(sdata->dev);
-                                       dev_put(odev);
-                                       osdata = sdata;
-                                       odev = osdata->dev;
-                                       skb->iif = sdata->dev->ifindex;
+                                       dev_hold(tmp_sdata->dev);
+                                       dev_put(sdata->dev);
+                                       sdata = tmp_sdata;
                                        monitor_iface = FOUND_SDATA;
                                        break;
                                }
@@ -1492,31 +1462,31 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       may_encrypt = !skb->do_not_encrypt;
+       may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
 
-       headroom = osdata->local->tx_headroom;
+       headroom = local->tx_headroom;
        if (may_encrypt)
                headroom += IEEE80211_ENCRYPT_HEADROOM;
        headroom -= skb_headroom(skb);
        headroom = max_t(int, 0, headroom);
 
-       if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+       if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
                dev_kfree_skb(skb);
-               dev_put(odev);
-               return NETDEV_TX_OK;
+               dev_put(sdata->dev);
+               return;
        }
 
-       if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               osdata = container_of(osdata->bss,
-                                     struct ieee80211_sub_if_data,
-                                     u.ap);
+       tmp_sdata = sdata;
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               tmp_sdata = container_of(sdata->bss,
+                                        struct ieee80211_sub_if_data,
+                                        u.ap);
        if (likely(monitor_iface != UNKNOWN_ADDRESS))
-               info->control.vif = &osdata->vif;
-
-       ieee80211_tx(odev, skb, false);
-       dev_put(odev);
+               info->control.vif = &tmp_sdata->vif;
 
-       return NETDEV_TX_OK;
+       ieee80211_select_queue(local, skb);
+       ieee80211_tx(sdata, skb, false);
+       dev_put(sdata->dev);
 }
 
 int ieee80211_monitor_start_xmit(struct sk_buff *skb,
@@ -1526,6 +1496,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        struct ieee80211_channel *chan = local->hw.conf.channel;
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        u16 len_rthdr;
 
        /*
@@ -1563,15 +1534,9 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        if (unlikely(skb->len < len_rthdr))
                goto fail; /* skb too short for claimed rt header extent */
 
-       skb->dev = local->mdev;
-
        /* needed because we set skb device to master */
        skb->iif = dev->ifindex;
 
-       /* sometimes we do encrypt injected frames, will be fixed
-        * up in radiotap parser if not wanted */
-       skb->do_not_encrypt = 0;
-
        /*
         * fix up the pointers accounting for the radiotap
         * header still being in there.  We are being given
@@ -1586,8 +1551,10 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        skb_set_network_header(skb, len_rthdr);
        skb_set_transport_header(skb, len_rthdr);
 
-       /* pass the radiotap header up to the next stage intact */
-       dev_queue_xmit(skb);
+       memset(info, 0, sizeof(*info));
+
+       /* pass the radiotap header up to xmit */
+       ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
        return NETDEV_TX_OK;
 
 fail:
@@ -1615,6 +1582,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret = NETDEV_TX_BUSY, head_need;
        u16 ethertype, hdrlen,  meshhdrlen = 0;
        __le16 fc;
@@ -1844,7 +1812,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 
        skb->iif = dev->ifindex;
 
-       skb->dev = local->mdev;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
@@ -1855,8 +1822,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        skb_set_network_header(skb, nh_pos);
        skb_set_transport_header(skb, h_pos);
 
+       memset(info, 0, sizeof(*info));
+
        dev->trans_start = jiffies;
-       dev_queue_xmit(skb);
+       ieee80211_xmit(sdata, skb);
 
        return NETDEV_TX_OK;
 
@@ -1898,7 +1867,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
                return true;
        }
 
-       /* validate info->control.vif against skb->iif */
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                sdata = container_of(sdata->bss,
@@ -1912,12 +1880,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
        }
 
        if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
-               ieee80211_tx(dev, skb, true);
+               /* do not use sdata, it may have been changed above */
+               ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
        } else {
                hdr = (struct ieee80211_hdr *)skb->data;
                sta = sta_info_get(local, hdr->addr1);
 
-               ret = __ieee80211_tx(local, &skb, sta);
+               ret = __ieee80211_tx(local, &skb, sta, true);
                if (ret != IEEE80211_TX_OK)
                        result = false;
        }
@@ -1929,59 +1898,43 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
 }
 
 /*
- * Transmit all pending packets. Called from tasklet, locks master device
- * TX lock so that no new packets can come in.
+ * Transmit all pending packets. Called from tasklet.
  */
 void ieee80211_tx_pending(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *)data;
-       struct net_device *dev = local->mdev;
        unsigned long flags;
        int i;
-       bool next;
+       bool txok;
 
        rcu_read_lock();
-       netif_tx_lock_bh(dev);
 
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        for (i = 0; i < local->hw.queues; i++) {
                /*
                 * If queue is stopped by something other than due to pending
                 * frames, or we have no pending frames, proceed to next queue.
                 */
-               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               next = false;
-               if (local->queue_stop_reasons[i] !=
-                       BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) ||
+               if (local->queue_stop_reasons[i] ||
                    skb_queue_empty(&local->pending[i]))
-                       next = true;
-               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-               if (next)
                        continue;
 
-               /*
-                * start the queue now to allow processing our packets,
-                * we're under the tx lock here anyway so nothing will
-                * happen as a result of this
-                */
-               netif_start_subqueue(local->mdev, i);
-
                while (!skb_queue_empty(&local->pending[i])) {
-                       struct sk_buff *skb = skb_dequeue(&local->pending[i]);
-
-                       if (!ieee80211_tx_pending_skb(local, skb)) {
-                               skb_queue_head(&local->pending[i], skb);
+                       struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
+                       spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+                                               flags);
+
+                       txok = ieee80211_tx_pending_skb(local, skb);
+                       if (!txok)
+                               __skb_queue_head(&local->pending[i], skb);
+                       spin_lock_irqsave(&local->queue_stop_reason_lock,
+                                         flags);
+                       if (!txok)
                                break;
-                       }
                }
-
-               /* Start regular packet processing again. */
-               if (skb_queue_empty(&local->pending[i]))
-                       ieee80211_wake_queue_by_reason(&local->hw, i,
-                                       IEEE80211_QUEUE_STOP_REASON_PENDING);
        }
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
-       netif_tx_unlock_bh(dev);
        rcu_read_unlock();
 }
 
@@ -2156,8 +2109,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 
        info = IEEE80211_SKB_CB(skb);
 
-       skb->do_not_encrypt = 1;
-
+       info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        info->band = band;
        /*
         * XXX: For now, always use the lowest rate
@@ -2228,9 +2180,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        sdata = vif_to_sdata(vif);
        bss = &sdata->u.ap;
 
-       if (!bss)
-               return NULL;
-
        rcu_read_lock();
        beacon = rcu_dereference(bss->beacon);
 
@@ -2256,7 +2205,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
                                cpu_to_le16(IEEE80211_FCTL_MOREDATA);
                }
 
-               if (!ieee80211_tx_prepare(local, &tx, skb))
+               if (!ieee80211_tx_prepare(sdata, &tx, skb))
                        break;
                dev_kfree_skb_any(skb);
        }
@@ -2276,3 +2225,25 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        return skb;
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
+
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+                     int encrypt)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       skb_set_mac_header(skb, 0);
+       skb_set_network_header(skb, 0);
+       skb_set_transport_header(skb, 0);
+
+       skb->iif = sdata->dev->ifindex;
+       if (!encrypt)
+               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+       /*
+        * The other path calling ieee80211_xmit is from the tasklet,
+        * and while we can handle concurrent transmissions locking
+        * requirements are that we do not come into tx with bhs on.
+        */
+       local_bh_disable();
+       ieee80211_xmit(sdata, skb);
+       local_bh_enable();
+}
index 915e777..7fc5584 100644 (file)
@@ -31,6 +31,7 @@
 #include "mesh.h"
 #include "wme.h"
 #include "led.h"
+#include "wep.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
 void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -274,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
 
        __clear_bit(reason, &local->queue_stop_reasons[queue]);
 
-       if (!skb_queue_empty(&local->pending[queue]) &&
-           local->queue_stop_reasons[queue] ==
-                               BIT(IEEE80211_QUEUE_STOP_REASON_PENDING))
-               tasklet_schedule(&local->tx_pending_tasklet);
-
        if (local->queue_stop_reasons[queue] != 0)
                /* someone still has this queue stopped */
                return;
 
-       netif_wake_subqueue(local->mdev, queue);
+       if (!skb_queue_empty(&local->pending[queue]))
+               tasklet_schedule(&local->tx_pending_tasklet);
 }
 
 void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -312,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
        if (WARN_ON(queue >= hw->queues))
                return;
 
-       /*
-        * Only stop if it was previously running, this is necessary
-        * for correct pending packets handling because there we may
-        * start (but not wake) the queue and rely on that.
-        */
-       if (!local->queue_stop_reasons[queue])
-               netif_stop_subqueue(local->mdev, queue);
-
        __set_bit(reason, &local->queue_stop_reasons[queue]);
 }
 
@@ -350,8 +339,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-       __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
-       skb_queue_tail(&local->pending[queue], skb);
+       __skb_queue_tail(&local->pending[queue], skb);
        __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
@@ -372,16 +360,12 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
        while ((skb = skb_dequeue(skbs))) {
                ret++;
                queue = skb_get_queue_mapping(skb);
-               skb_queue_tail(&local->pending[queue], skb);
+               __skb_queue_tail(&local->pending[queue], skb);
        }
 
-       for (i = 0; i < hw->queues; i++) {
-               if (ret)
-                       __ieee80211_stop_queue(hw, i,
-                               IEEE80211_QUEUE_STOP_REASON_PENDING);
+       for (i = 0; i < hw->queues; i++)
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-       }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
        return ret;
@@ -412,11 +396,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
 int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 {
        struct ieee80211_local *local = hw_to_local(hw);
+       unsigned long flags;
+       int ret;
 
        if (WARN_ON(queue >= hw->queues))
                return true;
 
-       return __netif_subqueue_stopped(local->mdev, queue);
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+       ret = !!local->queue_stop_reasons[queue];
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+       return ret;
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 
@@ -760,20 +749,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
        ieee80211_set_wmm_default(sdata);
 }
 
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                     int encrypt)
-{
-       skb->dev = sdata->local->mdev;
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, 0);
-       skb_set_transport_header(skb, 0);
-
-       skb->iif = sdata->dev->ifindex;
-       skb->do_not_encrypt = !encrypt;
-
-       dev_queue_xmit(skb);
-}
-
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
                              enum ieee80211_band band)
 {
@@ -804,12 +779,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg,
-                        u8 *extra, size_t extra_len,
-                        const u8 *bssid, int encrypt)
+                        u8 *extra, size_t extra_len, const u8 *bssid,
+                        const u8 *key, u8 key_len, u8 key_idx)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
+       int err;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            sizeof(*mgmt) + 6 + extra_len);
@@ -824,8 +800,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        memset(mgmt, 0, 24 + 6);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_AUTH);
-       if (encrypt)
-               mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
        memcpy(mgmt->da, bssid, ETH_ALEN);
        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -835,7 +809,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        if (extra)
                memcpy(skb_put(skb, extra_len), extra, extra_len);
 
-       ieee80211_tx_skb(sdata, skb, encrypt);
+       if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+               mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+               err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
+               WARN_ON(err);
+       }
+
+       ieee80211_tx_skb(sdata, skb, 0);
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
@@ -1043,9 +1023,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
 
-       netif_addr_lock_bh(local->mdev);
+       spin_lock_bh(&local->filter_lock);
        ieee80211_configure_filter(local);
-       netif_addr_unlock_bh(local->mdev);
+       spin_unlock_bh(&local->filter_lock);
 
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
index 4fafb2d..8a980f1 100644 (file)
@@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-static int ieee80211_wep_encrypt(struct ieee80211_local *local,
-                                struct sk_buff *skb,
-                                const u8 *key, int keylen, int keyidx)
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+                         struct sk_buff *skb,
+                         const u8 *key, int keylen, int keyidx)
 {
        u8 *iv;
        size_t len;
index 85219de..fe29d7e 100644 (file)
@@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_local *local);
 void ieee80211_wep_free(struct ieee80211_local *local);
 void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
                                size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+                         struct sk_buff *skb,
+                         const u8 *key, int keylen, int keyidx);
 int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
                               size_t klen, u8 *data, size_t data_len);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
index 116a923..b19b769 100644 (file)
@@ -85,10 +85,8 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
        return ieee802_1d_to_ac[skb->priority];
 }
 
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
+void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
 {
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 queue;
        u8 tid;
@@ -113,5 +111,5 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
                *p = 0;
        }
 
-       return queue;
+       skb_set_queue_mapping(skb, queue);
 }
index 7520d2e..d4fd87c 100644 (file)
@@ -20,6 +20,7 @@
 
 extern const int ieee802_1d_to_ac[8];
 
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb);
+void ieee80211_select_queue(struct ieee80211_local *local,
+                           struct sk_buff *skb);
 
 #endif /* _WME_H */
index 1a78b3c..6891cd0 100644 (file)
@@ -548,11 +548,6 @@ void wiphy_unregister(struct wiphy *wiphy)
        /* unlock again before freeing */
        mutex_unlock(&rdev->mtx);
 
-       cancel_work_sync(&rdev->conn_work);
-       cancel_work_sync(&rdev->scan_done_wk);
-       kfree(rdev->scan_req);
-       flush_work(&rdev->event_work);
-
        cfg80211_debugfs_rdev_del(rdev);
 
        /* If this device got a regulatory hint tell core its
@@ -564,6 +559,11 @@ void wiphy_unregister(struct wiphy *wiphy)
        debugfs_remove(rdev->wiphy.debugfsdir);
 
        mutex_unlock(&cfg80211_mutex);
+
+       cancel_work_sync(&rdev->conn_work);
+       cancel_work_sync(&rdev->scan_done_wk);
+       kfree(rdev->scan_req);
+       flush_work(&rdev->event_work);
 }
 EXPORT_SYMBOL(wiphy_unregister);
 
@@ -666,14 +666,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                wdev_lock(wdev);
                switch (wdev->iftype) {
                case NL80211_IFTYPE_ADHOC:
-                       if (wdev->wext.ibss.ssid_len)
-                               __cfg80211_join_ibss(rdev, dev,
-                                                    &wdev->wext.ibss);
+                       cfg80211_ibss_wext_join(rdev, wdev);
                        break;
                case NL80211_IFTYPE_STATION:
-                       if (wdev->wext.connect.ssid_len)
-                               __cfg80211_connect(rdev, dev,
-                                                  &wdev->wext.connect);
+                       cfg80211_mgd_wext_connect(rdev, wdev);
                        break;
                default:
                        break;
@@ -690,6 +686,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                }
                mutex_unlock(&rdev->devlist_mtx);
                mutex_destroy(&wdev->mtx);
+#ifdef CONFIG_WIRELESS_EXT
+               kfree(wdev->wext.keys);
+#endif
                break;
        case NETDEV_PRE_UP:
                if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
index e46cd6e..2ec8ddb 100644 (file)
@@ -238,6 +238,12 @@ struct cfg80211_event {
        };
 };
 
+struct cfg80211_cached_keys {
+       struct key_params params[6];
+       u8 data[6][WLAN_MAX_KEY_LEN];
+       int def, defmgmt;
+};
+
 
 /* free object */
 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -256,14 +262,18 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
 /* IBSS */
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                         struct net_device *dev,
-                        struct cfg80211_ibss_params *params);
+                        struct cfg80211_ibss_params *params,
+                        struct cfg80211_cached_keys *connkeys);
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
-                      struct cfg80211_ibss_params *params);
+                      struct cfg80211_ibss_params *params,
+                      struct cfg80211_cached_keys *connkeys);
 void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, bool nowext);
 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+                           struct wireless_dev *wdev);
 
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -272,12 +282,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         enum nl80211_auth_type auth_type,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
-                        const u8 *ie, int ie_len);
+                        const u8 *ie, int ie_len,
+                        const u8 *key, int key_len, int key_idx);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, struct ieee80211_channel *chan,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
-                      const u8 *ie, int ie_len);
+                      const u8 *ie, int ie_len,
+                      const u8 *key, int key_len, int key_idx);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
@@ -310,10 +322,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
-                      struct cfg80211_connect_params *connect);
+                      struct cfg80211_connect_params *connect,
+                      struct cfg80211_cached_keys *connkeys);
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
                     struct net_device *dev,
-                    struct cfg80211_connect_params *connect);
+                    struct cfg80211_connect_params *connect,
+                    struct cfg80211_cached_keys *connkeys);
 int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
                          struct net_device *dev, u16 reason,
                          bool wextev);
@@ -323,11 +337,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
                       const u8 *req_ie, size_t req_ie_len,
                       const u8 *resp_ie, size_t resp_ie_len);
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev);
 
 void cfg80211_conn_work(struct work_struct *work);
 
 /* internal helpers */
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+                                  struct key_params *params, int key_idx,
                                   const u8 *mac_addr);
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                             size_t ie_len, u16 reason, bool from_ap);
@@ -335,5 +352,6 @@ void cfg80211_sme_scan_done(struct net_device *dev);
 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
 void cfg80211_sme_disassoc(struct net_device *dev, int idx);
 void __cfg80211_scan_done(struct work_struct *wk);
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
 
 #endif /* __NET_WIRELESS_CORE_H */
index 99ef936..8b65e21 100644 (file)
@@ -39,6 +39,8 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
        cfg80211_hold_bss(bss_from_pub(bss));
        wdev->current_bss = bss_from_pub(bss);
 
+       cfg80211_upload_connect_keys(wdev);
+
        nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
                                GFP_KERNEL);
 #ifdef CONFIG_WIRELESS_EXT
@@ -71,7 +73,8 @@ EXPORT_SYMBOL(cfg80211_ibss_joined);
 
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                         struct net_device *dev,
-                        struct cfg80211_ibss_params *params)
+                        struct cfg80211_ibss_params *params,
+                        struct cfg80211_cached_keys *connkeys)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
@@ -81,13 +84,18 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
        if (wdev->ssid_len)
                return -EALREADY;
 
+       if (WARN_ON(wdev->connect_keys))
+               kfree(wdev->connect_keys);
+       wdev->connect_keys = connkeys;
+
 #ifdef CONFIG_WIRELESS_EXT
        wdev->wext.ibss.channel = params->channel;
 #endif
        err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
-
-       if (err)
+       if (err) {
+               wdev->connect_keys = NULL;
                return err;
+       }
 
        memcpy(wdev->ssid, params->ssid, params->ssid_len);
        wdev->ssid_len = params->ssid_len;
@@ -97,13 +105,14 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
-                      struct cfg80211_ibss_params *params)
+                      struct cfg80211_ibss_params *params,
+                      struct cfg80211_cached_keys *connkeys)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
        wdev_lock(wdev);
-       err = __cfg80211_join_ibss(rdev, dev, params);
+       err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
        wdev_unlock(wdev);
 
        return err;
@@ -112,9 +121,22 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       int i;
 
        ASSERT_WDEV_LOCK(wdev);
 
+       kfree(wdev->connect_keys);
+       wdev->connect_keys = NULL;
+
+       /*
+        * Delete all the keys ... pairwise keys can't really
+        * exist any more anyway, but default keys might.
+        */
+       if (rdev->ops->del_key)
+               for (i = 0; i < 6; i++)
+                       rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
                cfg80211_put_bss(&wdev->current_bss->pub);
@@ -172,11 +194,14 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 }
 
 #ifdef CONFIG_WIRELESS_EXT
-static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
-                                  struct wireless_dev *wdev)
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+                           struct wireless_dev *wdev)
 {
+       struct cfg80211_cached_keys *ck = NULL;
        enum ieee80211_band band;
-       int i;
+       int i, err;
+
+       ASSERT_WDEV_LOCK(wdev);
 
        if (!wdev->wext.ibss.beacon_interval)
                wdev->wext.ibss.beacon_interval = 100;
@@ -216,8 +241,24 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
        if (!netif_running(wdev->netdev))
                return 0;
 
-       return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
-                                 wdev->netdev, &wdev->wext.ibss);
+       if (wdev->wext.keys)
+               wdev->wext.keys->def = wdev->wext.default_key;
+
+       wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
+
+       if (wdev->wext.keys) {
+               ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+               if (!ck)
+                       return -ENOMEM;
+               for (i = 0; i < 6; i++)
+                       ck->params[i].key = ck->data[i];
+       }
+       err = __cfg80211_join_ibss(rdev, wdev->netdev,
+                                  &wdev->wext.ibss, ck);
+       if (err)
+               kfree(ck);
+
+       return err;
 }
 
 int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -265,7 +306,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                wdev->wext.ibss.channel_fixed = false;
        }
 
-       return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+       wdev_lock(wdev);
+       err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+       wdev_unlock(wdev);
+
+       return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
@@ -333,7 +378,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
        memcpy(wdev->wext.ibss.ssid, ssid, len);
        wdev->wext.ibss.ssid_len = len;
 
-       return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+       wdev_lock(wdev);
+       err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+       wdev_unlock(wdev);
+
+       return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
@@ -414,7 +463,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
        } else
                wdev->wext.ibss.bssid = NULL;
 
-       return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+       wdev_lock(wdev);
+       err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+       wdev_unlock(wdev);
+
+       return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
@@ -434,8 +487,11 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
        wdev_lock(wdev);
        if (wdev->current_bss)
                memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
-       else
+       else if (wdev->wext.ibss.bssid)
                memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
+       else
+               memset(ap_addr->sa_data, 0, ETH_ALEN);
+
        wdev_unlock(wdev);
 
        return 0;
index 1b2ca1f..5b9b221 100644 (file)
@@ -178,12 +178,12 @@ static void __cfg80211_send_disassoc(struct net_device *dev,
        bool from_ap;
        bool done = false;
 
-       wdev_lock(wdev);
+       ASSERT_WDEV_LOCK(wdev);
 
        nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
 
-       if (!wdev->sme_state == CFG80211_SME_CONNECTED)
-               goto out;
+       if (wdev->sme_state != CFG80211_SME_CONNECTED)
+               return;
 
        if (wdev->current_bss &&
            memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
@@ -205,8 +205,6 @@ static void __cfg80211_send_disassoc(struct net_device *dev,
 
        from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
        __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
- out:
-       wdev_unlock(wdev);
 }
 
 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
@@ -328,7 +326,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         enum nl80211_auth_type auth_type,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
-                        const u8 *ie, int ie_len)
+                        const u8 *ie, int ie_len,
+                        const u8 *key, int key_len, int key_idx)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_auth_request req;
@@ -337,6 +336,10 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 
        ASSERT_WDEV_LOCK(wdev);
 
+       if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+               if (!key || !key_len || key_idx < 0 || key_idx > 4)
+                       return -EINVAL;
+
        if (wdev->current_bss &&
            memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
                return -EALREADY;
@@ -359,6 +362,9 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        req.auth_type = auth_type;
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       req.key = key;
+       req.key_len = key_len;
+       req.key_idx = key_idx;
        if (!req.bss)
                return -ENOENT;
 
@@ -396,13 +402,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, struct ieee80211_channel *chan,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
-                      const u8 *ie, int ie_len)
+                      const u8 *ie, int ie_len,
+                      const u8 *key, int key_len, int key_idx)
 {
        int err;
 
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-                                  ssid, ssid_len, ie, ie_len);
+                                  ssid, ssid_len, ie, ie_len,
+                                  key, key_len, key_idx);
        wdev_unlock(dev->ieee80211_ptr);
 
        return err;
index 4478760..da450ef 100644 (file)
@@ -73,6 +73,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
        [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
 
+       [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
        [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
                                    .len = WLAN_MAX_KEY_LEN },
        [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
@@ -134,6 +135,17 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
 };
 
+/* policy for the attributes */
+static struct nla_policy
+nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
+       [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
+       [NL80211_KEY_IDX] = { .type = NLA_U8 },
+       [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
+       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
+       [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
+};
+
 /* IE validation */
 static bool is_valid_ie_attr(const struct nlattr *attr)
 {
@@ -198,6 +210,177 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
 
 /* netlink command implementations */
 
+struct key_parse {
+       struct key_params p;
+       int idx;
+       bool def, defmgmt;
+};
+
+static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
+{
+       struct nlattr *tb[NL80211_KEY_MAX + 1];
+       int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
+                                  nl80211_key_policy);
+       if (err)
+               return err;
+
+       k->def = !!tb[NL80211_KEY_DEFAULT];
+       k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
+
+       if (tb[NL80211_KEY_IDX])
+               k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
+
+       if (tb[NL80211_KEY_DATA]) {
+               k->p.key = nla_data(tb[NL80211_KEY_DATA]);
+               k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
+       }
+
+       if (tb[NL80211_KEY_SEQ]) {
+               k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
+               k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
+       }
+
+       if (tb[NL80211_KEY_CIPHER])
+               k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
+
+       return 0;
+}
+
+static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
+{
+       if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+               k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+               k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+       }
+
+       if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
+               k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
+               k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
+       }
+
+       if (info->attrs[NL80211_ATTR_KEY_IDX])
+               k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+       if (info->attrs[NL80211_ATTR_KEY_CIPHER])
+               k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+       k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
+       k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
+
+       return 0;
+}
+
+static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
+{
+       int err;
+
+       memset(k, 0, sizeof(*k));
+       k->idx = -1;
+
+       if (info->attrs[NL80211_ATTR_KEY])
+               err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
+       else
+               err = nl80211_parse_key_old(info, k);
+
+       if (err)
+               return err;
+
+       if (k->def && k->defmgmt)
+               return -EINVAL;
+
+       if (k->idx != -1) {
+               if (k->defmgmt) {
+                       if (k->idx < 4 || k->idx > 5)
+                               return -EINVAL;
+               } else if (k->def) {
+                       if (k->idx < 0 || k->idx > 3)
+                               return -EINVAL;
+               } else {
+                       if (k->idx < 0 || k->idx > 5)
+                               return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static struct cfg80211_cached_keys *
+nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
+                      struct nlattr *keys)
+{
+       struct key_parse parse;
+       struct nlattr *key;
+       struct cfg80211_cached_keys *result;
+       int rem, err, def = 0;
+
+       result = kzalloc(sizeof(*result), GFP_KERNEL);
+       if (!result)
+               return ERR_PTR(-ENOMEM);
+
+       result->def = -1;
+       result->defmgmt = -1;
+
+       nla_for_each_nested(key, keys, rem) {
+               memset(&parse, 0, sizeof(parse));
+               parse.idx = -1;
+
+               err = nl80211_parse_key_new(key, &parse);
+               if (err)
+                       goto error;
+               err = -EINVAL;
+               if (!parse.p.key)
+                       goto error;
+               if (parse.idx < 0 || parse.idx > 4)
+                       goto error;
+               if (parse.def) {
+                       if (def)
+                               goto error;
+                       def = 1;
+                       result->def = parse.idx;
+               } else if (parse.defmgmt)
+                       goto error;
+               err = cfg80211_validate_key_settings(rdev, &parse.p,
+                                                    parse.idx, NULL);
+               if (err)
+                       goto error;
+               result->params[parse.idx].cipher = parse.p.cipher;
+               result->params[parse.idx].key_len = parse.p.key_len;
+               result->params[parse.idx].key = result->data[parse.idx];
+               memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
+       }
+
+       return result;
+ error:
+       kfree(result);
+       return ERR_PTR(err);
+}
+
+static int nl80211_key_allowed(struct wireless_dev *wdev)
+{
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (!netif_running(wdev->netdev))
+               return -ENETDOWN;
+
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               if (!wdev->current_bss)
+                       return -ENOLINK;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (wdev->sme_state != CFG80211_SME_CONNECTED)
+                       return -ENOLINK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                              struct cfg80211_registered_device *dev)
 {
@@ -943,10 +1126,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 struct get_key_cookie {
        struct sk_buff *msg;
        int error;
+       int idx;
 };
 
 static void get_key_callback(void *c, struct key_params *params)
 {
+       struct nlattr *key;
        struct get_key_cookie *cookie = c;
 
        if (params->key)
@@ -961,6 +1146,26 @@ static void get_key_callback(void *c, struct key_params *params)
                NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
                            params->cipher);
 
+       key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
+       if (!key)
+               goto nla_put_failure;
+
+       if (params->key)
+               NLA_PUT(cookie->msg, NL80211_KEY_DATA,
+                       params->key_len, params->key);
+
+       if (params->seq)
+               NLA_PUT(cookie->msg, NL80211_KEY_SEQ,
+                       params->seq_len, params->seq);
+
+       if (params->cipher)
+               NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER,
+                           params->cipher);
+
+       NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx);
+
+       nla_nest_end(cookie->msg, key);
+
        return;
  nla_put_failure:
        cookie->error = 1;
@@ -1014,6 +1219,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        }
 
        cookie.msg = msg;
+       cookie.idx = key_idx;
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
@@ -1049,26 +1255,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
+       struct key_parse key;
        int err;
        struct net_device *dev;
-       u8 key_idx;
        int (*func)(struct wiphy *wiphy, struct net_device *netdev,
                    u8 key_index);
 
-       if (!info->attrs[NL80211_ATTR_KEY_IDX])
-               return -EINVAL;
-
-       key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+       err = nl80211_parse_key(info, &key);
+       if (err)
+               return err;
 
-       if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
-               if (key_idx < 4 || key_idx > 5)
-                       return -EINVAL;
-       } else if (key_idx > 3)
+       if (key.idx < 0)
                return -EINVAL;
 
-       /* currently only support setting default key */
-       if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
-           !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
+       /* only support setting default key */
+       if (!key.def && !key.defmgmt)
                return -EINVAL;
 
        rtnl_lock();
@@ -1077,7 +1278,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto unlock_rtnl;
 
-       if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
+       if (key.def)
                func = rdev->ops->set_default_key;
        else
                func = rdev->ops->set_default_mgmt_key;
@@ -1087,15 +1288,20 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = func(&rdev->wiphy, dev, key_idx);
+       wdev_lock(dev->ieee80211_ptr);
+       err = nl80211_key_allowed(dev->ieee80211_ptr);
+       if (!err)
+               err = func(&rdev->wiphy, dev, key.idx);
+
 #ifdef CONFIG_WIRELESS_EXT
        if (!err) {
                if (func == rdev->ops->set_default_key)
-                       dev->ieee80211_ptr->wext.default_key = key_idx;
+                       dev->ieee80211_ptr->wext.default_key = key.idx;
                else
-                       dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
+                       dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
        }
 #endif
+       wdev_unlock(dev->ieee80211_ptr);
 
  out:
        cfg80211_unlock_rdev(rdev);
@@ -1110,58 +1316,43 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
-       int err, i;
+       int err;
        struct net_device *dev;
-       struct key_params params;
-       u8 key_idx = 0;
+       struct key_parse key;
        u8 *mac_addr = NULL;
 
-       memset(&params, 0, sizeof(params));
+       err = nl80211_parse_key(info, &key);
+       if (err)
+               return err;
 
-       if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+       if (!key.p.key)
                return -EINVAL;
 
-       if (info->attrs[NL80211_ATTR_KEY_DATA]) {
-               params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
-               params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
-       }
-
-       if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
-               params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
-               params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
-       }
-
-       if (info->attrs[NL80211_ATTR_KEY_IDX])
-               key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
-       params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
-               return -EINVAL;
-
        rtnl_lock();
 
        err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-               if (params.cipher == rdev->wiphy.cipher_suites[i])
-                       break;
-       if (i == rdev->wiphy.n_cipher_suites) {
-               err = -EINVAL;
+       if (!rdev->ops->add_key) {
+               err = -EOPNOTSUPP;
                goto out;
        }
 
-       if (!rdev->ops->add_key) {
-               err = -EOPNOTSUPP;
+       if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
+               err = -EINVAL;
                goto out;
        }
 
-       err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, &params);
+       wdev_lock(dev->ieee80211_ptr);
+       err = nl80211_key_allowed(dev->ieee80211_ptr);
+       if (!err)
+               err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+                                        mac_addr, &key.p);
+       wdev_unlock(dev->ieee80211_ptr);
 
  out:
        cfg80211_unlock_rdev(rdev);
@@ -1177,14 +1368,12 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
-       u8 key_idx = 0;
        u8 *mac_addr = NULL;
+       struct key_parse key;
 
-       if (info->attrs[NL80211_ATTR_KEY_IDX])
-               key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
-       if (key_idx > 5)
-               return -EINVAL;
+       err = nl80211_parse_key(info, &key);
+       if (err)
+               return err;
 
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -1200,16 +1389,20 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr);
+       wdev_lock(dev->ieee80211_ptr);
+       err = nl80211_key_allowed(dev->ieee80211_ptr);
+       if (!err)
+               err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
        if (!err) {
-               if (key_idx == dev->ieee80211_ptr->wext.default_key)
+               if (key.idx == dev->ieee80211_ptr->wext.default_key)
                        dev->ieee80211_ptr->wext.default_key = -1;
-               else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
+               else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
                        dev->ieee80211_ptr->wext.default_mgmt_key = -1;
        }
 #endif
+       wdev_unlock(dev->ieee80211_ptr);
 
  out:
        cfg80211_unlock_rdev(rdev);
@@ -2901,11 +3094,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                            struct cfg80211_registered_device *rdev,
-                           struct net_device *dev,
-                           struct cfg80211_bss *res)
+                           struct wireless_dev *wdev,
+                           struct cfg80211_internal_bss *intbss)
 {
+       struct cfg80211_bss *res = &intbss->pub;
        void *hdr;
        struct nlattr *bss;
+       int i;
+
+       ASSERT_WDEV_LOCK(wdev);
 
        hdr = nl80211hdr_put(msg, pid, seq, flags,
                             NL80211_CMD_NEW_SCAN_RESULTS);
@@ -2914,7 +3111,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
        NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
                    rdev->bss_generation);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex);
 
        bss = nla_nest_start(msg, NL80211_ATTR_BSS);
        if (!bss)
@@ -2943,6 +3140,28 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                break;
        }
 
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_STATION:
+               if (intbss == wdev->current_bss)
+                       NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+                                   NL80211_BSS_STATUS_ASSOCIATED);
+               else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+                       if (intbss != wdev->auth_bsses[i])
+                               continue;
+                       NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+                                   NL80211_BSS_STATUS_AUTHENTICATED);
+                       break;
+               }
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               if (intbss == wdev->current_bss)
+                       NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+                                   NL80211_BSS_STATUS_IBSS_JOINED);
+               break;
+       default:
+               break;
+       }
+
        nla_nest_end(msg, bss);
 
        return genlmsg_end(msg, hdr);
@@ -2955,9 +3174,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 static int nl80211_dump_scan(struct sk_buff *skb,
                             struct netlink_callback *cb)
 {
-       struct cfg80211_registered_device *dev;
-       struct net_device *netdev;
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
        struct cfg80211_internal_bss *scan;
+       struct wireless_dev *wdev;
        int ifidx = cb->args[0];
        int start = cb->args[1], idx = 0;
        int err;
@@ -2978,39 +3198,43 @@ static int nl80211_dump_scan(struct sk_buff *skb,
                cb->args[0] = ifidx;
        }
 
-       netdev = dev_get_by_index(&init_net, ifidx);
-       if (!netdev)
+       dev = dev_get_by_index(&init_net, ifidx);
+       if (!dev)
                return -ENODEV;
 
-       dev = cfg80211_get_dev_from_ifindex(ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
+       rdev = cfg80211_get_dev_from_ifindex(ifidx);
+       if (IS_ERR(rdev)) {
+               err = PTR_ERR(rdev);
                goto out_put_netdev;
        }
 
-       spin_lock_bh(&dev->bss_lock);
-       cfg80211_bss_expire(dev);
+       wdev = dev->ieee80211_ptr;
+
+       wdev_lock(wdev);
+       spin_lock_bh(&rdev->bss_lock);
+       cfg80211_bss_expire(rdev);
 
-       list_for_each_entry(scan, &dev->bss_list, list) {
+       list_for_each_entry(scan, &rdev->bss_list, list) {
                if (++idx <= start)
                        continue;
                if (nl80211_send_bss(skb,
                                NETLINK_CB(cb->skb).pid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                               dev, netdev, &scan->pub) < 0) {
+                               rdev, wdev, scan) < 0) {
                        idx--;
                        goto out;
                }
        }
 
  out:
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
+       wdev_unlock(wdev);
 
        cb->args[1] = idx;
        err = skb->len;
-       cfg80211_unlock_rdev(dev);
+       cfg80211_unlock_rdev(rdev);
  out_put_netdev:
-       dev_put(netdev);
+       dev_put(dev);
 
        return err;
 }
@@ -3050,6 +3274,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        const u8 *bssid, *ssid, *ie = NULL;
        int err, ssid_len, ie_len = 0;
        enum nl80211_auth_type auth_type;
+       struct key_parse key;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3066,6 +3291,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
 
+       err = nl80211_parse_key(info, &key);
+       if (err)
+               return err;
+
+       if (key.idx >= 0) {
+               if (!key.p.key || !key.p.key_len)
+                       return -EINVAL;
+               if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
+                    key.p.key_len != WLAN_KEY_LEN_WEP40) &&
+                   (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
+                    key.p.key_len != WLAN_KEY_LEN_WEP104))
+                       return -EINVAL;
+               if (key.idx > 4)
+                       return -EINVAL;
+       } else {
+               key.p.key_len = 0;
+               key.p.key = NULL;
+       }
+
        rtnl_lock();
 
        err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
@@ -3110,7 +3354,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        }
 
        err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-                                ssid, ssid_len, ie, ie_len);
+                                ssid, ssid_len, ie, ie_len,
+                                key.p.key, key.p.key_len, key.idx);
 
 out:
        cfg80211_unlock_rdev(rdev);
@@ -3397,6 +3642,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
        struct net_device *dev;
        struct cfg80211_ibss_params ibss;
        struct wiphy *wiphy;
+       struct cfg80211_cached_keys *connkeys = NULL;
        int err;
 
        memset(&ibss, 0, sizeof(ibss));
@@ -3461,13 +3707,26 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
        }
 
        ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+       ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+       if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+               connkeys = nl80211_parse_connkeys(rdev,
+                                       info->attrs[NL80211_ATTR_KEYS]);
+               if (IS_ERR(connkeys)) {
+                       err = PTR_ERR(connkeys);
+                       connkeys = NULL;
+                       goto out;
+               }
+       }
 
-       err = cfg80211_join_ibss(rdev, dev, &ibss);
+       err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
 
 out:
        cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
+       if (err)
+               kfree(connkeys);
        rtnl_unlock();
        return err;
 }
@@ -3637,6 +3896,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        struct net_device *dev;
        struct cfg80211_connect_params connect;
        struct wiphy *wiphy;
+       struct cfg80211_cached_keys *connkeys = NULL;
        int err;
 
        memset(&connect, 0, sizeof(connect));
@@ -3680,10 +3940,6 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        wiphy = &rdev->wiphy;
 
-       connect.bssid = NULL;
-       connect.channel = NULL;
-       connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-
        if (info->attrs[NL80211_ATTR_MAC])
                connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
        connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
@@ -3705,12 +3961,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       err = cfg80211_connect(rdev, dev, &connect);
+       if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+               connkeys = nl80211_parse_connkeys(rdev,
+                                       info->attrs[NL80211_ATTR_KEYS]);
+               if (IS_ERR(connkeys)) {
+                       err = PTR_ERR(connkeys);
+                       connkeys = NULL;
+                       goto out;
+               }
+       }
+
+       err = cfg80211_connect(rdev, dev, &connect, connkeys);
 
 out:
        cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
+       if (err)
+               kfree(connkeys);
        rtnl_unlock();
        return err;
 }
index 2b4a6c6..fb40428 100644 (file)
@@ -113,11 +113,7 @@ static const struct ieee80211_regdomain world_regdom = {
 static const struct ieee80211_regdomain *cfg80211_world_regdom =
        &world_regdom;
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-static char *ieee80211_regdom = "US";
-#else
 static char *ieee80211_regdom = "00";
-#endif
 
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
@@ -2287,22 +2283,12 @@ int regulatory_init(void)
 
        printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
        print_regdomain_info(cfg80211_regdomain);
-       /*
-        * The old code still requests for a new regdomain and if
-        * you have CRDA you get it updated, otherwise you get
-        * stuck with the static values. Since "EU" is not a valid
-        * ISO / IEC 3166 alpha2 code we can't expect userpace to
-        * give us a regulatory domain for it. We need last_request
-        * iniitalized though so lets just send a request which we
-        * know will be ignored... this crap will be removed once
-        * OLD_REG dies.
-        */
-       err = regulatory_hint_core(ieee80211_regdom);
 #else
        cfg80211_regdomain = cfg80211_world_regdom;
 
-       err = regulatory_hint_core(ieee80211_regdom);
 #endif
+       /* We always try to get an update for the static regdomain */
+       err = regulatory_hint_core(cfg80211_regdomain->alpha2);
        if (err) {
                if (err == -ENOMEM)
                        return err;
@@ -2321,6 +2307,13 @@ int regulatory_init(void)
 #endif
        }
 
+       /*
+        * Finally, if the user set the module parameter treat it
+        * as a user hint.
+        */
+       if (!is_world_regdom(ieee80211_regdom))
+               regulatory_hint_user(ieee80211_regdom);
+
        return 0;
 }
 
index df9173f..82de2d9 100644 (file)
@@ -125,7 +125,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                            params->channel, params->auth_type,
                                            params->bssid,
                                            params->ssid, params->ssid_len,
-                                           NULL, 0);
+                                           NULL, 0,
+                                           params->key, params->key_len,
+                                           params->key_idx);
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -225,7 +227,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
        if (wdev->sme_state != CFG80211_SME_CONNECTING)
                return;
 
-       if (WARN_ON(!wdev->conn))
+       if (!wdev->conn)
                return;
 
        if (wdev->conn->state != CFG80211_CONN_SCANNING &&
@@ -279,8 +281,12 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
                /* select automatically between only open, shared, leap */
                switch (wdev->conn->params.auth_type) {
                case NL80211_AUTHTYPE_OPEN_SYSTEM:
-                       wdev->conn->params.auth_type =
-                               NL80211_AUTHTYPE_SHARED_KEY;
+                       if (wdev->connect_keys)
+                               wdev->conn->params.auth_type =
+                                       NL80211_AUTHTYPE_SHARED_KEY;
+                       else
+                               wdev->conn->params.auth_type =
+                                       NL80211_AUTHTYPE_NETWORK_EAP;
                        break;
                case NL80211_AUTHTYPE_SHARED_KEY:
                        wdev->conn->params.auth_type =
@@ -295,9 +301,8 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
                wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
                schedule_work(&rdev->conn_work);
        } else if (status_code != WLAN_STATUS_SUCCESS) {
-               wdev->sme_state = CFG80211_SME_IDLE;
-               kfree(wdev->conn);
-               wdev->conn = NULL;
+               __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
+                                         status_code, false);
        } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
                 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
                wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
@@ -336,7 +341,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                if (req_ie && status == WLAN_STATUS_SUCCESS) {
                        memset(&wrqu, 0, sizeof(wrqu));
                        wrqu.data.length = req_ie_len;
-                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
+                       wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
                }
 
                if (resp_ie && status == WLAN_STATUS_SUCCESS) {
@@ -354,10 +359,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 #endif
 
        if (status == WLAN_STATUS_SUCCESS &&
-           wdev->sme_state == CFG80211_SME_IDLE) {
-               wdev->sme_state = CFG80211_SME_CONNECTED;
-               return;
-       }
+           wdev->sme_state == CFG80211_SME_IDLE)
+               goto success;
 
        if (wdev->sme_state != CFG80211_SME_CONNECTING)
                return;
@@ -371,24 +374,29 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        if (wdev->conn)
                wdev->conn->state = CFG80211_CONN_IDLE;
 
-       if (status == WLAN_STATUS_SUCCESS) {
-               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-                                      wdev->ssid, wdev->ssid_len,
-                                      WLAN_CAPABILITY_ESS,
-                                      WLAN_CAPABILITY_ESS);
-
-               if (WARN_ON(!bss))
-                       return;
-
-               cfg80211_hold_bss(bss_from_pub(bss));
-               wdev->current_bss = bss_from_pub(bss);
-
-               wdev->sme_state = CFG80211_SME_CONNECTED;
-       } else {
+       if (status != WLAN_STATUS_SUCCESS) {
                wdev->sme_state = CFG80211_SME_IDLE;
                kfree(wdev->conn);
                wdev->conn = NULL;
+               kfree(wdev->connect_keys);
+               wdev->connect_keys = NULL;
+               return;
        }
+
+       bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+                              wdev->ssid, wdev->ssid_len,
+                              WLAN_CAPABILITY_ESS,
+                              WLAN_CAPABILITY_ESS);
+
+       if (WARN_ON(!bss))
+               return;
+
+       cfg80211_hold_bss(bss_from_pub(bss));
+       wdev->current_bss = bss_from_pub(bss);
+
+ success:
+       wdev->sme_state = CFG80211_SME_CONNECTED;
+       cfg80211_upload_connect_keys(wdev);
 }
 
 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -466,7 +474,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
        if (req_ie) {
                memset(&wrqu, 0, sizeof(wrqu));
                wrqu.data.length = req_ie_len;
-               wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
+               wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
                                    &wrqu, req_ie);
        }
 
@@ -517,6 +525,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                             size_t ie_len, u16 reason, bool from_ap)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       int i;
 #ifdef CONFIG_WIRELESS_EXT
        union iwreq_data wrqu;
 #endif
@@ -544,8 +554,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                wdev->conn = NULL;
        }
 
-       nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
-                                 reason, ie, ie_len, from_ap);
+       nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
+
+       /*
+        * Delete all the keys ... pairwise keys can't really
+        * exist any more anyway, but default keys might.
+        */
+       if (rdev->ops->del_key)
+               for (i = 0; i < 6; i++)
+                       rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 
 #ifdef CONFIG_WIRELESS_EXT
        memset(&wrqu, 0, sizeof(wrqu));
@@ -581,7 +598,8 @@ EXPORT_SYMBOL(cfg80211_disconnected);
 
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
-                      struct cfg80211_connect_params *connect)
+                      struct cfg80211_connect_params *connect,
+                      struct cfg80211_cached_keys *connkeys)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
@@ -591,6 +609,24 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
        if (wdev->sme_state != CFG80211_SME_IDLE)
                return -EALREADY;
 
+       if (WARN_ON(wdev->connect_keys)) {
+               kfree(wdev->connect_keys);
+               wdev->connect_keys = NULL;
+       }
+
+       if (connkeys && connkeys->def >= 0) {
+               int idx;
+
+               idx = connkeys->def;
+               /* If given a WEP key we may need it for shared key auth */
+               if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
+                   connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
+                       connect->key_idx = idx;
+                       connect->key = connkeys->params[idx].key;
+                       connect->key_len = connkeys->params[idx].key_len;
+               }
+       }
+
        if (!rdev->ops->connect) {
                if (!rdev->ops->auth || !rdev->ops->assoc)
                        return -EOPNOTSUPP;
@@ -641,6 +677,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
                        cfg80211_get_conn_bss(wdev);
 
                wdev->sme_state = CFG80211_SME_CONNECTING;
+               wdev->connect_keys = connkeys;
 
                /* we're good if we have both BSSID and channel */
                if (wdev->conn->params.bssid && wdev->conn->params.channel) {
@@ -663,13 +700,16 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
                        kfree(wdev->conn);
                        wdev->conn = NULL;
                        wdev->sme_state = CFG80211_SME_IDLE;
+                       wdev->connect_keys = NULL;
                }
 
                return err;
        } else {
                wdev->sme_state = CFG80211_SME_CONNECTING;
+               wdev->connect_keys = connkeys;
                err = rdev->ops->connect(&rdev->wiphy, dev, connect);
                if (err) {
+                       wdev->connect_keys = NULL;
                        wdev->sme_state = CFG80211_SME_IDLE;
                        return err;
                }
@@ -683,12 +723,13 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
                     struct net_device *dev,
-                    struct cfg80211_connect_params *connect)
+                    struct cfg80211_connect_params *connect,
+                    struct cfg80211_cached_keys *connkeys)
 {
        int err;
 
        wdev_lock(dev->ieee80211_ptr);
-       err = __cfg80211_connect(rdev, dev, connect);
+       err = __cfg80211_connect(rdev, dev, connect, connkeys);
        wdev_unlock(dev->ieee80211_ptr);
 
        return err;
@@ -705,6 +746,9 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
        if (wdev->sme_state == CFG80211_SME_IDLE)
                return -EINVAL;
 
+       kfree(wdev->connect_keys);
+       wdev->connect_keys = NULL;
+
        if (!rdev->ops->disconnect) {
                if (!rdev->ops->deauth)
                        return -EOPNOTSUPP;
@@ -782,8 +826,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
                return;
 
        memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
-       if (cfg80211_mlme_deauth(rdev, dev, bssid,
-                                NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
+       if (__cfg80211_mlme_deauth(rdev, dev, bssid,
+                                  NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
                /* whatever -- assume gone anyway */
                cfg80211_unhold_bss(wdev->auth_bsses[idx]);
                cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
index 28f8f96..ba387d8 100644 (file)
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
                        set_mandatory_flags_band(wiphy->bands[band], band);
 }
 
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+                                  struct key_params *params, int key_idx,
                                   const u8 *mac_addr)
 {
+       int i;
+
        if (key_idx > 5)
                return -EINVAL;
 
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
                }
        }
 
+       for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
+               if (params->cipher == rdev->wiphy.cipher_suites[i])
+                       break;
+       if (i == rdev->wiphy.n_cipher_suites)
+               return -EINVAL;
+
        return 0;
 }
 
@@ -523,3 +532,37 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
        return NULL;
 }
 EXPORT_SYMBOL(ieee80211_bss_get_ie);
+
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct net_device *dev = wdev->netdev;
+       int i;
+
+       if (!wdev->connect_keys)
+               return;
+
+       for (i = 0; i < 6; i++) {
+               if (!wdev->connect_keys->params[i].cipher)
+                       continue;
+               if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+                                       &wdev->connect_keys->params[i])) {
+                       printk(KERN_ERR "%s: failed to set key %d\n",
+                               dev->name, i);
+                       continue;
+               }
+               if (wdev->connect_keys->def == i)
+                       if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) {
+                               printk(KERN_ERR "%s: failed to set defkey %d\n",
+                                       dev->name, i);
+                               continue;
+                       }
+               if (wdev->connect_keys->defmgmt == i)
+                       if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+                               printk(KERN_ERR "%s: failed to set mgtdef %d\n",
+                                       dev->name, i);
+       }
+
+       kfree(wdev->connect_keys);
+       wdev->connect_keys = NULL;
+}
index 9d101d5..c7351a9 100644 (file)
@@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_device *dev,
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 
-static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
-                                  struct net_device *dev, const u8 *addr,
-                                  bool remove, bool tx_key, int idx,
-                                  struct key_params *params)
+static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+                                    struct net_device *dev, const u8 *addr,
+                                    bool remove, bool tx_key, int idx,
+                                    struct key_params *params)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       int err;
+       int err, i;
+
+       if (!wdev->wext.keys) {
+               wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
+                                             GFP_KERNEL);
+               if (!wdev->wext.keys)
+                       return -ENOMEM;
+               for (i = 0; i < 6; i++)
+                       wdev->wext.keys->params[i].key =
+                               wdev->wext.keys->data[i];
+       }
+
+       if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
+           wdev->iftype != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
 
        if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+               if (!wdev->current_bss)
+                       return -ENOLINK;
+
                if (!rdev->ops->set_default_mgmt_key)
                        return -EOPNOTSUPP;
 
@@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        if (remove) {
-               err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+               err = 0;
+               if (wdev->current_bss)
+                       err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
                if (!err) {
+                       if (!addr) {
+                               wdev->wext.keys->params[idx].key_len = 0;
+                               wdev->wext.keys->params[idx].cipher = 0;
+                       }
                        if (idx == wdev->wext.default_key)
                                wdev->wext.default_key = -1;
                        else if (idx == wdev->wext.default_mgmt_key)
@@ -486,36 +509,65 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
                        return 0;
 
                return err;
-       } else {
-               if (addr)
-                       tx_key = false;
+       }
 
-               if (cfg80211_validate_key_settings(params, idx, addr))
-                       return -EINVAL;
+       if (addr)
+               tx_key = false;
 
+       if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+               return -EINVAL;
+
+       err = 0;
+       if (wdev->current_bss)
                err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
-               if (err)
-                       return err;
+       if (err)
+               return err;
 
-               if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+       if (!addr) {
+               wdev->wext.keys->params[idx] = *params;
+               memcpy(wdev->wext.keys->data[idx],
+                       params->key, params->key_len);
+               wdev->wext.keys->params[idx].key =
+                       wdev->wext.keys->data[idx];
+       }
+
+       if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+           (tx_key || (!addr && wdev->wext.default_key == -1))) {
+               if (wdev->current_bss)
                        err = rdev->ops->set_default_key(&rdev->wiphy,
                                                         dev, idx);
-                       if (!err)
-                               wdev->wext.default_key = idx;
-                       return err;
-               }
+               if (!err)
+                       wdev->wext.default_key = idx;
+               return err;
+       }
 
-               if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
-                   (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+       if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+           (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+               if (wdev->current_bss)
                        err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
                                                              dev, idx);
-                       if (!err)
-                               wdev->wext.default_mgmt_key = idx;
-                       return err;
-               }
-
-               return 0;
+               if (!err)
+                       wdev->wext.default_mgmt_key = idx;
+               return err;
        }
+
+       return 0;
+}
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+                                  struct net_device *dev, const u8 *addr,
+                                  bool remove, bool tx_key, int idx,
+                                  struct key_params *params)
+{
+       int err;
+
+       wdev_lock(dev->ieee80211_ptr);
+       err = __cfg80211_set_encryption(rdev, dev, addr, remove,
+                                       tx_key, idx, params);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       return err;
 }
 
 int cfg80211_wext_siwencode(struct net_device *dev,
@@ -528,6 +580,10 @@ int cfg80211_wext_siwencode(struct net_device *dev,
        bool remove = false;
        struct key_params params;
 
+       if (wdev->iftype != NL80211_IFTYPE_STATION &&
+           wdev->iftype != NL80211_IFTYPE_ADHOC)
+               return -EOPNOTSUPP;
+
        /* no use -- only MFP (set_default_mgmt_key) is optional */
        if (!rdev->ops->del_key ||
            !rdev->ops->add_key ||
@@ -548,9 +604,14 @@ int cfg80211_wext_siwencode(struct net_device *dev,
                remove = true;
        else if (erq->length == 0) {
                /* No key data - just set the default TX key index */
-               err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+               err = 0;
+               wdev_lock(wdev);
+               if (wdev->current_bss)
+                       err = rdev->ops->set_default_key(&rdev->wiphy,
+                                                        dev, idx);
                if (!err)
                        wdev->wext.default_key = idx;
+               wdev_unlock(wdev);
                return err;
        }
 
@@ -583,6 +644,10 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
        struct key_params params;
        u32 cipher;
 
+       if (wdev->iftype != NL80211_IFTYPE_STATION &&
+           wdev->iftype != NL80211_IFTYPE_ADHOC)
+               return -EOPNOTSUPP;
+
        /* no use -- only MFP (set_default_mgmt_key) is optional */
        if (!rdev->ops->del_key ||
            !rdev->ops->add_key ||
@@ -656,37 +721,15 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
 
-struct giwencode_cookie {
-       size_t buflen;
-       char *keybuf;
-};
-
-static void giwencode_get_key_cb(void *cookie, struct key_params *params)
-{
-       struct giwencode_cookie *data = cookie;
-
-       if (!params->key) {
-               data->buflen = 0;
-               return;
-       }
-
-       data->buflen = min_t(size_t, data->buflen, params->key_len);
-       memcpy(data->keybuf, params->key, data->buflen);
-}
-
 int cfg80211_wext_giwencode(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_point *erq, char *keybuf)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-       int idx, err;
-       struct giwencode_cookie data = {
-               .keybuf = keybuf,
-               .buflen = erq->length,
-       };
+       int idx;
 
-       if (!rdev->ops->get_key)
+       if (wdev->iftype != NL80211_IFTYPE_STATION &&
+           wdev->iftype != NL80211_IFTYPE_ADHOC)
                return -EOPNOTSUPP;
 
        idx = erq->flags & IW_ENCODE_INDEX;
@@ -701,21 +744,18 @@ int cfg80211_wext_giwencode(struct net_device *dev,
 
        erq->flags = idx + 1;
 
-       err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
-                                giwencode_get_key_cb);
-       if (!err) {
-               erq->length = data.buflen;
-               erq->flags |= IW_ENCODE_ENABLED;
-               return 0;
-       }
-
-       if (err == -ENOENT) {
+       if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
                erq->flags |= IW_ENCODE_DISABLED;
                erq->length = 0;
                return 0;
        }
 
-       return err;
+       erq->length = min_t(size_t, erq->length,
+                           wdev->wext.keys->params[idx].key_len);
+       memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
+       erq->flags |= IW_ENCODE_ENABLED;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
 
@@ -841,9 +881,19 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
        wdev->wext.connect.crypto.wpa_versions = 0;
 
        if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
-                            IW_AUTH_WPA_VERSION_WPA2))
+                            IW_AUTH_WPA_VERSION_WPA2|
+                            IW_AUTH_WPA_VERSION_DISABLED))
                return -EINVAL;
 
+       if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
+           (wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
+                            IW_AUTH_WPA_VERSION_WPA2)))
+               return -EINVAL;
+
+       if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
+               wdev->wext.connect.crypto.wpa_versions &=
+                       ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
+
        if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
                wdev->wext.connect.crypto.wpa_versions |=
                        NL80211_WPA_VERSION_1;
@@ -1127,7 +1177,7 @@ int cfg80211_wext_giwrate(struct net_device *dev,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        /* we are under RTNL - globally locked - so can use a static struct */
        static struct station_info sinfo;
-       u8 *addr;
+       u8 addr[ETH_ALEN];
        int err;
 
        if (wdev->iftype != NL80211_IFTYPE_STATION)
@@ -1136,12 +1186,15 @@ int cfg80211_wext_giwrate(struct net_device *dev,
        if (!rdev->ops->get_station)
                return -EOPNOTSUPP;
 
+       err = 0;
+       wdev_lock(wdev);
        if (wdev->current_bss)
-               addr = wdev->current_bss->pub.bssid;
-       else if (wdev->wext.connect.bssid)
-               addr = wdev->wext.connect.bssid;
+               memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN);
        else
-               return -EOPNOTSUPP;
+               err = -EOPNOTSUPP;
+       wdev_unlock(wdev);
+       if (err)
+               return err;
 
        err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
        if (err)
@@ -1167,7 +1220,7 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
        /* we are under RTNL - globally locked - so can use static structs */
        static struct iw_statistics wstats;
        static struct station_info sinfo;
-       u8 *addr;
+       u8 bssid[ETH_ALEN];
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
                return NULL;
@@ -1175,11 +1228,16 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
        if (!rdev->ops->get_station)
                return NULL;
 
-       addr = wdev->wext.connect.bssid;
-       if (!addr)
+       /* Grab BSSID of current BSS, if any */
+       wdev_lock(wdev);
+       if (!wdev->current_bss) {
+               wdev_unlock(wdev);
                return NULL;
+       }
+       memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
+       wdev_unlock(wdev);
 
-       if (rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo))
+       if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo))
                return NULL;
 
        memset(&wstats, 0, sizeof(wstats));
index 6f75aaa..4c689fd 100644 (file)
 #include <net/cfg80211.h>
 #include "nl80211.h"
 
-static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
-                                    struct wireless_dev *wdev)
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev)
 {
-       int err;
+       struct cfg80211_cached_keys *ck = NULL;
+       int err, i;
 
        ASSERT_RDEV_LOCK(rdev);
        ASSERT_WDEV_LOCK(wdev);
@@ -25,10 +26,25 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
        wdev->wext.connect.ie_len = wdev->wext.ie_len;
        wdev->wext.connect.privacy = wdev->wext.default_key != -1;
 
-       err = 0;
-       if (wdev->wext.connect.ssid_len != 0)
-               err = __cfg80211_connect(rdev, wdev->netdev,
-                                        &wdev->wext.connect);
+       if (wdev->wext.keys) {
+               wdev->wext.keys->def = wdev->wext.default_key;
+               wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+       }
+
+       if (!wdev->wext.connect.ssid_len)
+               return 0;
+
+       if (wdev->wext.keys) {
+               ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+               if (!ck)
+                       return -ENOMEM;
+               for (i = 0; i < 6; i++)
+                       ck->params[i].key = ck->data[i];
+       }
+       err = __cfg80211_connect(rdev, wdev->netdev,
+                                &wdev->wext.connect, ck);
+       if (err)
+               kfree(ck);
 
        return err;
 }
@@ -56,13 +72,14 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
        cfg80211_lock_rdev(rdev);
        wdev_lock(wdev);
 
-       if (wdev->wext.connect.channel == chan) {
-               err = 0;
-               goto out;
-       }
-
        if (wdev->sme_state != CFG80211_SME_IDLE) {
                bool event = true;
+
+               if (wdev->wext.connect.channel == chan) {
+                       err = 0;
+                       goto out;
+               }
+
                /* if SSID set, we'll try right again, avoid event */
                if (wdev->wext.connect.ssid_len)
                        event = false;
@@ -148,13 +165,14 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
 
        err = 0;
 
-       if (wdev->wext.connect.ssid && len &&
-           len == wdev->wext.connect.ssid_len &&
-           memcmp(wdev->wext.connect.ssid, ssid, len))
-               goto out;
-
        if (wdev->sme_state != CFG80211_SME_IDLE) {
                bool event = true;
+
+               if (wdev->wext.connect.ssid && len &&
+                   len == wdev->wext.connect.ssid_len &&
+                   memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
+                       goto out;
+
                /* if SSID set now, we'll try to connect, avoid event */
                if (len)
                        event = false;
@@ -193,11 +211,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
        data->flags = 0;
 
        wdev_lock(wdev);
-       if (wdev->ssid_len) {
-               data->flags = 1;
-               data->length = wdev->ssid_len;
-               memcpy(ssid, wdev->ssid, data->length);
-       } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
+       if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
                data->flags = 1;
                data->length = wdev->wext.connect.ssid_len;
                memcpy(ssid, wdev->wext.connect.ssid, data->length);
@@ -232,17 +246,17 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
        cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
        wdev_lock(wdev);
 
-       err = 0;
-       /* both automatic */
-       if (!bssid && !wdev->wext.connect.bssid)
-               goto out;
+       if (wdev->sme_state != CFG80211_SME_IDLE) {
+               err = 0;
+               /* both automatic */
+               if (!bssid && !wdev->wext.connect.bssid)
+                       goto out;
 
-       /* fixed already - and no change */
-       if (wdev->wext.connect.bssid && bssid &&
-           compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
-               goto out;
+               /* fixed already - and no change */
+               if (wdev->wext.connect.bssid && bssid &&
+                   compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
+                       goto out;
 
-       if (wdev->sme_state != CFG80211_SME_IDLE) {
                err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
                                            dev, WLAN_REASON_DEAUTH_LEAVING,
                                            false);