From 748427f2e405cb833cc0fb5e92ddec364b61d0d4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 29 Oct 2012 13:29:12 +0000 Subject: [PATCH] mac80211: report tx status for dropped frames, should fix some remaining stability issues SVN-Revision: 33991 --- .../mac80211/patches/300-pending_work.patch | 173 ++++++++++++++---- 1 file changed, 134 insertions(+), 39 deletions(-) diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch index 6f35a07bed..56f5af959b 100644 --- a/package/mac80211/patches/300-pending_work.patch +++ b/package/mac80211/patches/300-pending_work.patch @@ -257,52 +257,43 @@ 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; + - 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, -- cookie, acked, GFP_ATOMIC); -- } else if (skb->dev) { -- cfg80211_mgmt_tx_status( -- skb->dev->ieee80211_ptr, cookie, skb->data, -- 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( -- &p2p_sdata->wdev, cookie, skb->data, -- skb->len, acked, GFP_ATOMIC); -- } -- rcu_read_unlock(); -+ if (skb->dev != sdata->dev) -+ continue; + -+ found = true; -+ break; - } ++ if (skb->dev) { ++ list_for_each_entry_rcu(iter_sdata, &local->interfaces, ++ list) { ++ if (!iter_sdata->dev) ++ continue; + -+ if (!skb->dev) { ++ if (skb->dev == iter_sdata->dev) { ++ sdata = iter_sdata; ++ break; ++ } ++ } ++ } else { + sdata = rcu_dereference(local->p2p_sdata); -+ if (sdata) -+ found = true; + } + -+ if (!found) ++ if (!sdata) + skb->dev = NULL; + else if (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { @@ -314,9 +305,113 @@ + } + + 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 (unlikely(info->ack_frame_id)) { +- 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, +- cookie, acked, GFP_ATOMIC); +- } else if (skb->dev) { +- cfg80211_mgmt_tx_status( +- skb->dev->ieee80211_ptr, cookie, skb->data, +- skb->len, acked, GFP_ATOMIC); +- } else { +- struct ieee80211_sub_if_data *p2p_sdata; +- +- rcu_read_lock(); +- +- p2p_sdata = rcu_dereference(local->p2p_sdata); +- if (p2p_sdata) { +- cfg80211_mgmt_tx_status( +- &p2p_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); +- } + ++ 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