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 | 171 ++++++++++++++---- 1 file changed, 133 insertions(+), 38 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,14 +257,90 @@ 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, @@ -275,13 +351,9 @@ - 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( @@ -289,34 +361,57 @@ - 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 -- 2.25.1