carl9170: fix frame delivery if sta is in powersave mode
authorChristian Lamparter <chunkeey@googlemail.com>
Sat, 25 Feb 2012 20:36:36 +0000 (21:36 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 29 Feb 2012 18:08:51 +0000 (13:08 -0500)
Nicolas Cavallari discovered that carl9170 has some
serious problems delivering data to sleeping stations.

It turns out that the driver was not honoring two
important flags (IEEE80211_TX_CTL_POLL_RESPONSE and
IEEE80211_TX_CTL_CLEAR_PS_FILT) which are set on
frames that should be sent although the receiving
station is still in powersave mode.

Cc: stable <stable@vger.kernel.org>
Reported-by: Nicolas Cavallari <Nicolas.Cavallari@lri.fr>
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/carl9170/tx.c

index 22a793121bd3b48a4a70f5625fc46c1c646ec1d3..bbc813dee983f83c0e73062d7485898da704420b 100644 (file)
@@ -1234,6 +1234,7 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ieee80211_sta *sta;
        struct carl9170_sta_info *sta_info;
+       struct ieee80211_tx_info *tx_info;
 
        rcu_read_lock();
        sta = __carl9170_get_tx_sta(ar, skb);
@@ -1241,12 +1242,13 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
                goto out_rcu;
 
        sta_info = (void *) sta->drv_priv;
-       if (unlikely(sta_info->sleeping)) {
-               struct ieee80211_tx_info *tx_info;
+       tx_info = IEEE80211_SKB_CB(skb);
 
+       if (unlikely(sta_info->sleeping) &&
+           !(tx_info->flags & (IEEE80211_TX_CTL_POLL_RESPONSE |
+                               IEEE80211_TX_CTL_CLEAR_PS_FILT))) {
                rcu_read_unlock();
 
-               tx_info = IEEE80211_SKB_CB(skb);
                if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
                        atomic_dec(&ar->tx_ampdu_upload);