]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/mac80211/status.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / net / mac80211 / status.c
index 3153c19893b81ebe1309290b41491010cd296999..071ac95c4aa0faf64a3dcfb1c054d60b2af958fb 100644 (file)
@@ -157,6 +157,15 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
        }
 }
 
+/*
+ * Use a static threshold for now, best value to be determined
+ * by testing ...
+ * Should it depend on:
+ *  - on # of retransmissions
+ *  - current throughput (higher value for higher tpt)?
+ */
+#define STA_LOST_PKT_THRESHOLD 50
+
 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct sk_buff *skb2;
@@ -173,6 +182,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        int retry_count = -1, i;
        int rates_idx = -1;
        bool send_to_cooked;
+       bool acked;
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
                /* the HW cannot have attempted that rate */
@@ -198,8 +208,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
                        continue;
 
-               if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-                   test_sta_flags(sta, WLAN_STA_PS_STA)) {
+               acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
+               if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) {
                        /*
                         * The STA is in power save mode, so assume
                         * that this TX packet failed because of that.
@@ -231,7 +241,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        rcu_read_unlock();
                        return;
                } else {
-                       if (!(info->flags & IEEE80211_TX_STAT_ACK))
+                       if (!acked)
                                sta->tx_retry_failed++;
                        sta->tx_retry_count += retry_count;
                }
@@ -240,9 +250,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (ieee80211_vif_is_mesh(&sta->sdata->vif))
                        ieee80211s_update_metric(local, sta, skb);
 
-               if (!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
-                   (info->flags & IEEE80211_TX_STAT_ACK))
+               if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
                        ieee80211_frame_acked(sta, skb);
+
+               if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
+                   (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
+                       ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked);
+
+               if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+                       if (info->flags & IEEE80211_TX_STAT_ACK) {
+                               if (sta->lost_packets)
+                                       sta->lost_packets = 0;
+                       } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
+                               cfg80211_cqm_pktloss_notify(sta->sdata->dev,
+                                                           sta->sta.addr,
+                                                           sta->lost_packets,
+                                                           GFP_ATOMIC);
+                               sta->lost_packets = 0;
+                       }
+               }
        }
 
        rcu_read_unlock();
@@ -295,10 +321,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                        msecs_to_jiffies(10));
        }
 
-       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
+       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+               struct ieee80211_work *wk;
+               u64 cookie = (unsigned long)skb;
+
+               rcu_read_lock();
+               list_for_each_entry_rcu(wk, &local->work_list, list) {
+                       if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+                               continue;
+                       if (wk->offchan_tx.frame != skb)
+                               continue;
+                       wk->offchan_tx.frame = NULL;
+                       break;
+               }
+               rcu_read_unlock();
+               if (local->hw_roc_skb_for_status == skb) {
+                       cookie = local->hw_roc_cookie ^ 2;
+                       local->hw_roc_skb_for_status = NULL;
+               }
                cfg80211_mgmt_tx_status(
-                       skb->dev, (unsigned long) skb, skb->data, skb->len,
+                       skb->dev, cookie, skb->data, skb->len,
                        !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
+       }
 
        /* this was a transmitted frame, but now we want to reuse it */
        skb_orphan(skb);