mac80211: report tx status for dropped frames, should fix some remaining stability...
authorFelix Fietkau <nbd@openwrt.org>
Mon, 29 Oct 2012 13:29:26 +0000 (13:29 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 29 Oct 2012 13:29:26 +0000 (13:29 +0000)
Backport of r33991

SVN-Revision: 33992

package/mac80211/patches/300-pending_work.patch

index 6f35a07..56f5af9 100644 (file)
        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