summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@googlemail.com>2012-02-25 21:36:36 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-12 12:31:40 -0700
commit2cfb4e5c22726c099645a7e5fc447d4ffcfca85c (patch)
treed267d141113d52b837c4eec070d580ff05290147
parent273c20d42332bbbf368a0c61c330055b5fd695dc (diff)
downloadlinux-stable-2cfb4e5c22726c099645a7e5fc447d4ffcfca85c.tar.gz
linux-stable-2cfb4e5c22726c099645a7e5fc447d4ffcfca85c.tar.bz2
linux-stable-2cfb4e5c22726c099645a7e5fc447d4ffcfca85c.zip
carl9170: fix frame delivery if sta is in powersave mode
commit 9926a67557532acb6cddb1c1add02952175b5c72 upstream. 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. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 3e9f0f67c4ed..f6384afcdfb7 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -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);