WLAN_STA_BLOCK_BA,
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
-@@ -517,29 +517,41 @@ void ieee80211_tx_status(struct ieee8021
+@@ -324,6 +324,75 @@ static void ieee80211_add_tx_radiotap_he
- if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
- u64 cookie = (unsigned long)skb;
-+ bool found = false;
+ }
+
++static void ieee80211_report_used_skb(struct ieee80211_local *local,
++ struct sk_buff *skb, bool dropped)
++{
++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++ struct ieee80211_hdr *hdr = (void *)skb->data;
++ bool acked = info->flags & IEEE80211_TX_STAT_ACK;
++
++ if (dropped)
++ acked = false;
++
++ if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
++ struct ieee80211_sub_if_data *sdata = NULL;
++ struct ieee80211_sub_if_data *iter_sdata;
++ u64 cookie = (unsigned long)skb;
++
++ rcu_read_lock();
++
++ if (skb->dev) {
++ list_for_each_entry_rcu(iter_sdata, &local->interfaces,
++ list) {
++ if (!iter_sdata->dev)
++ continue;
++
++ if (skb->dev == iter_sdata->dev) {
++ sdata = iter_sdata;
++ break;
++ }
++ }
++ } else {
++ sdata = rcu_dereference(local->p2p_sdata);
++ }
+
- acked = info->flags & IEEE80211_TX_STAT_ACK;
++ if (!sdata)
++ skb->dev = NULL;
++ else if (ieee80211_is_nullfunc(hdr->frame_control) ||
++ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
++ cfg80211_probe_status(sdata->dev, hdr->addr1,
++ cookie, acked, GFP_ATOMIC);
++ } else {
++ cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
++ skb->len, acked, GFP_ATOMIC);
++ }
++
++ rcu_read_unlock();
++ }
++
++ if (unlikely(info->ack_frame_id)) {
++ struct sk_buff *ack_skb;
++ unsigned long flags;
++
++ spin_lock_irqsave(&local->ack_status_lock, flags);
++ ack_skb = idr_find(&local->ack_status_frames,
++ info->ack_frame_id);
++ if (ack_skb)
++ idr_remove(&local->ack_status_frames,
++ info->ack_frame_id);
++ spin_unlock_irqrestore(&local->ack_status_lock, flags);
++
++ if (ack_skb) {
++ if (!dropped) {
++ /* consumes ack_skb */
++ skb_complete_wifi_ack(ack_skb, acked);
++ } else {
++ dev_kfree_skb_any(ack_skb);
++ }
++ }
++ }
++}
++
+ /*
+ * Use a static threshold for now, best value to be determined
+ * by testing ...
+@@ -515,50 +584,7 @@ void ieee80211_tx_status(struct ieee8021
+ msecs_to_jiffies(10));
+ }
+- if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+- u64 cookie = (unsigned long)skb;
+- acked = info->flags & IEEE80211_TX_STAT_ACK;
+-
- if (ieee80211_is_nullfunc(hdr->frame_control) ||
- ieee80211_is_qos_nullfunc(hdr->frame_control)) {
- cfg80211_probe_status(skb->dev, hdr->addr1,
- skb->len, acked, GFP_ATOMIC);
- } else {
- struct ieee80211_sub_if_data *p2p_sdata;
-+ rcu_read_lock();
-
+-
- rcu_read_lock();
-+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-+ if (!sdata->dev)
-+ continue;
-
+-
- p2p_sdata = rcu_dereference(local->p2p_sdata);
- if (p2p_sdata) {
- cfg80211_mgmt_tx_status(
- skb->len, acked, GFP_ATOMIC);
- }
- rcu_read_unlock();
-+ if (skb->dev != sdata->dev)
-+ continue;
-+
-+ found = true;
-+ break;
- }
-+
-+ if (!skb->dev) {
-+ sdata = rcu_dereference(local->p2p_sdata);
-+ if (sdata)
-+ found = true;
-+ }
-+
-+ if (!found)
-+ skb->dev = NULL;
-+ else if (ieee80211_is_nullfunc(hdr->frame_control) ||
-+ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-+ cfg80211_probe_status(sdata->dev, hdr->addr1,
-+ cookie, acked, GFP_ATOMIC);
-+ } else {
-+ cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
-+ skb->len, acked, GFP_ATOMIC);
-+ }
-+
-+ rcu_read_unlock();
- }
+- }
+- }
+-
+- if (unlikely(info->ack_frame_id)) {
+- struct sk_buff *ack_skb;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&local->ack_status_lock, flags);
+- ack_skb = idr_find(&local->ack_status_frames,
+- info->ack_frame_id);
+- if (ack_skb)
+- idr_remove(&local->ack_status_frames,
+- info->ack_frame_id);
+- spin_unlock_irqrestore(&local->ack_status_lock, flags);
+-
+- /* consumes ack_skb */
+- if (ack_skb)
+- skb_complete_wifi_ack(ack_skb,
+- info->flags & IEEE80211_TX_STAT_ACK);
+- }
++ ieee80211_report_used_skb(local, skb, false);
+
+ /* this was a transmitted frame, but now we want to reuse it */
+ skb_orphan(skb);
+@@ -634,25 +660,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
+ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
+ {
+ struct ieee80211_local *local = hw_to_local(hw);
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-
+- if (unlikely(info->ack_frame_id)) {
+- struct sk_buff *ack_skb;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&local->ack_status_lock, flags);
+- ack_skb = idr_find(&local->ack_status_frames,
+- info->ack_frame_id);
+- if (ack_skb)
+- idr_remove(&local->ack_status_frames,
+- info->ack_frame_id);
+- spin_unlock_irqrestore(&local->ack_status_lock, flags);
+-
+- /* consumes ack_skb */
+- if (ack_skb)
+- dev_kfree_skb_any(ack_skb);
+- }
- if (unlikely(info->ack_frame_id)) {
++ ieee80211_report_used_skb(local, skb, true);
+ dev_kfree_skb_any(skb);
+ }
+ EXPORT_SYMBOL(ieee80211_free_txskb);
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -139,6 +139,7 @@ static int p54_beacon_format_ie_tim(stru