aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Natarajan <vnatarajan@atheros.com>2010-03-11 15:59:53 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-01 19:01:57 -0400
commit03d0e14875e0f4151ec039125c15ca46e056b914 (patch)
treed758e4819e099fcc3f97d1da14d28aaf1e6042d0
parent7c74e3f2e97f7bdcb56b72919201af941ea0b4e6 (diff)
mac80211: Retry null data frame for power save
commit 375177bf35efc08e1bd37bbda4cc0c8cc4db8500 upstream. Even if the null data frame is not acked by the AP, mac80211 goes into power save. This might lead to loss of frames from the AP. Prevent this by restarting dynamic_ps_timer when ack is not received for null data frames. Cc: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--include/net/mac80211.h4
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/mlme.c20
-rw-r--r--net/mac80211/status.c17
4 files changed, 35 insertions, 7 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 15bcb56106ec..f39b303944dd 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -926,6 +926,9 @@ enum ieee80211_tkip_key_type {
926 * @IEEE80211_HW_BEACON_FILTER: 926 * @IEEE80211_HW_BEACON_FILTER:
927 * Hardware supports dropping of irrelevant beacon frames to 927 * Hardware supports dropping of irrelevant beacon frames to
928 * avoid waking up cpu. 928 * avoid waking up cpu.
929 * @IEEE80211_HW_REPORTS_TX_ACK_STATUS:
930 * Hardware can provide ack status reports of Tx frames to
931 * the stack.
929 */ 932 */
930enum ieee80211_hw_flags { 933enum ieee80211_hw_flags {
931 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, 934 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -943,6 +946,7 @@ enum ieee80211_hw_flags {
943 IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, 946 IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12,
944 IEEE80211_HW_MFP_CAPABLE = 1<<13, 947 IEEE80211_HW_MFP_CAPABLE = 1<<13,
945 IEEE80211_HW_BEACON_FILTER = 1<<14, 948 IEEE80211_HW_BEACON_FILTER = 1<<14,
949 IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<15,
946}; 950};
947 951
948/** 952/**
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 91dc8636d644..3521c17b2606 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -264,6 +264,7 @@ enum ieee80211_sta_flags {
264 IEEE80211_STA_DISABLE_11N = BIT(4), 264 IEEE80211_STA_DISABLE_11N = BIT(4),
265 IEEE80211_STA_CSA_RECEIVED = BIT(5), 265 IEEE80211_STA_CSA_RECEIVED = BIT(5),
266 IEEE80211_STA_MFP_ENABLED = BIT(6), 266 IEEE80211_STA_MFP_ENABLED = BIT(6),
267 IEEE80211_STA_NULLFUNC_ACKED = BIT(7),
267}; 268};
268 269
269/* flags for MLME request */ 270/* flags for MLME request */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9072a412089e..1a209ac67ffa 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -662,8 +662,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
662 } else { 662 } else {
663 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) 663 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
664 ieee80211_send_nullfunc(local, sdata, 1); 664 ieee80211_send_nullfunc(local, sdata, 1);
665 conf->flags |= IEEE80211_CONF_PS; 665
666 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 666 if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) {
667 conf->flags |= IEEE80211_CONF_PS;
668 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
669 }
667 } 670 }
668} 671}
669 672
@@ -754,6 +757,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
754 container_of(work, struct ieee80211_local, 757 container_of(work, struct ieee80211_local,
755 dynamic_ps_enable_work); 758 dynamic_ps_enable_work);
756 struct ieee80211_sub_if_data *sdata = local->ps_sdata; 759 struct ieee80211_sub_if_data *sdata = local->ps_sdata;
760 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
757 761
758 /* can only happen when PS was just disabled anyway */ 762 /* can only happen when PS was just disabled anyway */
759 if (!sdata) 763 if (!sdata)
@@ -762,11 +766,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
762 if (local->hw.conf.flags & IEEE80211_CONF_PS) 766 if (local->hw.conf.flags & IEEE80211_CONF_PS)
763 return; 767 return;
764 768
765 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) 769 if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
770 (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)))
766 ieee80211_send_nullfunc(local, sdata, 1); 771 ieee80211_send_nullfunc(local, sdata, 1);
767 772
768 local->hw.conf.flags |= IEEE80211_CONF_PS; 773 if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) ||
769 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 774 (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
775 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
776 local->hw.conf.flags |= IEEE80211_CONF_PS;
777 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
778 }
770} 779}
771 780
772void ieee80211_dynamic_ps_timer(unsigned long data) 781void ieee80211_dynamic_ps_timer(unsigned long data)
@@ -2468,6 +2477,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2468 list_add(&wk->list, &ifmgd->work_list); 2477 list_add(&wk->list, &ifmgd->work_list);
2469 2478
2470 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; 2479 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
2480 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
2471 2481
2472 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) 2482 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
2473 if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || 2483 if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index d78f36c64c7b..f5abeec32a00 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -165,6 +165,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
165 rcu_read_lock(); 165 rcu_read_lock();
166 166
167 sband = local->hw.wiphy->bands[info->band]; 167 sband = local->hw.wiphy->bands[info->band];
168 fc = hdr->frame_control;
168 169
169 sta = sta_info_get(local, hdr->addr1); 170 sta = sta_info_get(local, hdr->addr1);
170 171
@@ -180,8 +181,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
180 return; 181 return;
181 } 182 }
182 183
183 fc = hdr->frame_control;
184
185 if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && 184 if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
186 (ieee80211_is_data_qos(fc))) { 185 (ieee80211_is_data_qos(fc))) {
187 u16 tid, ssn; 186 u16 tid, ssn;
@@ -246,6 +245,20 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
246 local->dot11FailedCount++; 245 local->dot11FailedCount++;
247 } 246 }
248 247
248 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
249 (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
250 !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
251 local->ps_sdata && !(local->scanning)) {
252 if (info->flags & IEEE80211_TX_STAT_ACK) {
253 local->ps_sdata->u.mgd.flags |=
254 IEEE80211_STA_NULLFUNC_ACKED;
255 ieee80211_queue_work(&local->hw,
256 &local->dynamic_ps_enable_work);
257 } else
258 mod_timer(&local->dynamic_ps_timer, jiffies +
259 msecs_to_jiffies(10));
260 }
261
249 /* this was a transmitted frame, but now we want to reuse it */ 262 /* this was a transmitted frame, but now we want to reuse it */
250 skb_orphan(skb); 263 skb_orphan(skb);
251 264