Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[deliverable/linux.git] / drivers / net / wireless / ath / carl9170 / rx.c
index 7a8e90eaad83332bb7eb2107c4faa7963fca5c44..6f6a34155667d0da84fdb5c9d63824ce7d1ac37b 100644 (file)
@@ -576,6 +576,53 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
        }
 }
 
+static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
+{
+       struct ieee80211_bar *bar = (void *) data;
+       struct carl9170_bar_list_entry *entry;
+       unsigned int queue;
+
+       if (likely(!ieee80211_is_back(bar->frame_control)))
+               return;
+
+       if (len <= sizeof(*bar) + FCS_LEN)
+               return;
+
+       queue = TID_TO_WME_AC(((le16_to_cpu(bar->control) &
+               IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+               IEEE80211_BAR_CTRL_TID_INFO_SHIFT) & 7);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) {
+               struct sk_buff *entry_skb = entry->skb;
+               struct _carl9170_tx_superframe *super = (void *)entry_skb->data;
+               struct ieee80211_bar *entry_bar = (void *)super->frame_data;
+
+#define TID_CHECK(a, b) (                                              \
+       ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) ==        \
+       ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)))          \
+
+               if (bar->start_seq_num == entry_bar->start_seq_num &&
+                   TID_CHECK(bar->control, entry_bar->control) &&
+                   compare_ether_addr(bar->ra, entry_bar->ta) == 0 &&
+                   compare_ether_addr(bar->ta, entry_bar->ra) == 0) {
+                       struct ieee80211_tx_info *tx_info;
+
+                       tx_info = IEEE80211_SKB_CB(entry_skb);
+                       tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+                       spin_lock_bh(&ar->bar_list_lock[queue]);
+                       list_del_rcu(&entry->list);
+                       spin_unlock_bh(&ar->bar_list_lock[queue]);
+                       kfree_rcu(entry, head);
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+#undef TID_CHECK
+}
+
 static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms)
 {
        __le16 fc;
@@ -738,6 +785,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
 
        carl9170_ps_beacon(ar, buf, mpdu_len);
 
+       carl9170_ba_check(ar, buf, mpdu_len);
+
        skb = carl9170_rx_copy_data(buf, mpdu_len);
        if (!skb)
                goto drop;
This page took 0.02814 seconds and 5 git commands to generate.