mac80211: report tx status for dropped frames, should fix some remaining stability issues

SVN-Revision: 33991
lede-17.01
Felix Fietkau 2012-10-29 13:29:12 +00:00
parent c63de0e888
commit 748427f2e4
1 changed files with 134 additions and 39 deletions

View File

@ -257,52 +257,43 @@
WLAN_STA_BLOCK_BA, WLAN_STA_BLOCK_BA,
--- a/net/mac80211/status.c --- a/net/mac80211/status.c
+++ b/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();
- 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; + if (skb->dev) {
+ break; + 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); + sdata = rcu_dereference(local->p2p_sdata);
+ if (sdata)
+ found = true;
+ } + }
+ +
+ if (!found) + if (!sdata)
+ skb->dev = NULL; + skb->dev = NULL;
+ else if (ieee80211_is_nullfunc(hdr->frame_control) || + else if (ieee80211_is_nullfunc(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control)) { + ieee80211_is_qos_nullfunc(hdr->frame_control)) {
@ -314,9 +305,113 @@
+ } + }
+ +
+ rcu_read_unlock(); + 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 --- a/drivers/net/wireless/p54/main.c
+++ b/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 @@ -139,6 +139,7 @@ static int p54_beacon_format_ie_tim(stru