aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorVivek Natarajan <vnatarajan@atheros.com>2011-02-23 02:34:32 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-23 16:25:29 -0500
commitf3e85b9edeaf8ad0446a37a40c873f3f8898c57d (patch)
tree298ae716ab7215423a4bc1192783c475be769838 /net/mac80211
parent05db8c5729fac2788f45bf327d168f2ea397f6a1 (diff)
mac80211: Fix a race on enabling power save.
There is a race on sending a data frame before the tx completion of nullfunc frame for enabling power save. As the data quickly follows the nullfunc frame, the AP thinks that the station is out of power save and continues to send the frames. Whereas in the station, the nullfunc ack will be processed after the tx completion of data frame and mac80211 goes to powersave. Thus the power save state mismatch between the station and the AP causes some data loss and some applications fail because of that. This patch fixes this issue. Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/mlme.c14
-rw-r--r--net/mac80211/status.c2
2 files changed, 13 insertions, 3 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7b3f9df725bd..abb011660803 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -738,9 +738,19 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
738 return; 738 return;
739 739
740 if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && 740 if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
741 (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) 741 (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) {
742 netif_tx_stop_all_queues(sdata->dev);
743 /*
744 * Flush all the frames queued in the driver before
745 * going to power save
746 */
747 drv_flush(local, false);
742 ieee80211_send_nullfunc(local, sdata, 1); 748 ieee80211_send_nullfunc(local, sdata, 1);
743 749
750 /* Flush once again to get the tx status of nullfunc frame */
751 drv_flush(local, false);
752 }
753
744 if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && 754 if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
745 (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) || 755 (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) ||
746 (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { 756 (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
@@ -748,6 +758,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
748 local->hw.conf.flags |= IEEE80211_CONF_PS; 758 local->hw.conf.flags |= IEEE80211_CONF_PS;
749 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 759 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
750 } 760 }
761
762 netif_tx_start_all_queues(sdata->dev);
751} 763}
752 764
753void ieee80211_dynamic_ps_timer(unsigned long data) 765void ieee80211_dynamic_ps_timer(unsigned long data)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 010a559bd872..865185127f51 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -318,8 +318,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
318 if (info->flags & IEEE80211_TX_STAT_ACK) { 318 if (info->flags & IEEE80211_TX_STAT_ACK) {
319 local->ps_sdata->u.mgd.flags |= 319 local->ps_sdata->u.mgd.flags |=
320 IEEE80211_STA_NULLFUNC_ACKED; 320 IEEE80211_STA_NULLFUNC_ACKED;
321 ieee80211_queue_work(&local->hw,
322 &local->dynamic_ps_enable_work);
323 } else 321 } else
324 mod_timer(&local->dynamic_ps_timer, jiffies + 322 mod_timer(&local->dynamic_ps_timer, jiffies +
325 msecs_to_jiffies(10)); 323 msecs_to_jiffies(10));