svcrpc: don't hold sv_lock over svc_xprt_put()
[safe/jmp/linux-2.6] / net / mac80211 / status.c
index 9e171b1..56d5b9a 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
- * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008-2010 Johannes Berg <johannes@sipsolutions.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -45,38 +45,20 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        /*
-        * XXX: This is temporary!
-        *
-        *      The problem here is that when we get here, the driver will
-        *      quite likely have pretty much overwritten info->control by
-        *      using info->driver_data or info->rate_driver_data. Thus,
-        *      when passing out the frame to the driver again, we would be
-        *      passing completely bogus data since the driver would then
-        *      expect a properly filled info->control. In mac80211 itself
-        *      the same problem occurs, since we need info->control.vif
-        *      internally.
-        *
-        *      To fix this, we should send the frame through TX processing
-        *      again. However, it's not that simple, since the frame will
-        *      have been software-encrypted (if applicable) already, and
-        *      encrypting it again doesn't do much good. So to properly do
-        *      that, we not only have to skip the actual 'raw' encryption
-        *      (key selection etc. still has to be done!) but also the
-        *      sequence number assignment since that impacts the crypto
-        *      encapsulation, of course.
-        *
-        *      Hence, for now, fix the bug by just dropping the frame.
-        */
-       goto drop;
-
-       /*
         * This skb 'survived' a round-trip through the driver, and
         * hopefully the driver didn't mangle it too badly. However,
         * we can definitely not rely on the the control information
-        * being correct. Clear it so we don't get junk there.
+        * being correct. Clear it so we don't get junk there, and
+        * indicate that it needs new processing, but must not be
+        * modified/encrypted again.
         */
        memset(&info->control, 0, sizeof(info->control));
 
+       info->control.jiffies = jiffies;
+       info->control.vif = &sta->sdata->vif;
+       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
+                      IEEE80211_TX_INTFL_RETRANSMISSION;
+
        sta->tx_filtered_count++;
 
        /*
@@ -130,7 +112,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
- drop:
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (net_ratelimit())
                printk(KERN_DEBUG "%s: dropped TX filtered frame, "
@@ -207,6 +188,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        rcu_read_lock();
 
        sband = local->hw.wiphy->bands[info->band];
+       fc = hdr->frame_control;
 
        for_each_sta_info(local, hdr->addr1, sta, tmp) {
                /* skip wrong virtual interface */
@@ -224,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        return;
                }
 
-               fc = hdr->frame_control;
-
                if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
                    (ieee80211_is_data_qos(fc))) {
                        u16 tid, ssn;
@@ -294,6 +274,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        local->dot11FailedCount++;
        }
 
+       if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
+           (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
+           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+           local->ps_sdata && !(local->scanning)) {
+               if (info->flags & IEEE80211_TX_STAT_ACK) {
+                       local->ps_sdata->u.mgd.flags |=
+                                       IEEE80211_STA_NULLFUNC_ACKED;
+                       ieee80211_queue_work(&local->hw,
+                                       &local->dynamic_ps_enable_work);
+               } else
+                       mod_timer(&local->dynamic_ps_timer, jiffies +
+                                       msecs_to_jiffies(10));
+       }
+
+       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
+               cfg80211_action_tx_status(
+                       skb->dev, (unsigned long) skb, 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);