aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Natarajan <vnatarajan@atheros.com>2010-02-09 04:20:28 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-02-09 14:10:05 -0500
commit375177bf35efc08e1bd37bbda4cc0c8cc4db8500 (patch)
tree88774b1a46072fd3b0418b36d39d447b78fbfc51
parente15276a4b220c54db665cf46a92bd9ceb9aeb052 (diff)
mac80211: Retry null data frame for power save.
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>
-rw-r--r--include/net/mac80211.h6
-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, 37 insertions, 7 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 414d774028ba..314e98173166 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -945,6 +945,11 @@ enum ieee80211_tkip_key_type {
945 * Hardware supports Unscheduled Automatic Power Save Delivery 945 * Hardware supports Unscheduled Automatic Power Save Delivery
946 * (U-APSD) in managed mode. The mode is configured with 946 * (U-APSD) in managed mode. The mode is configured with
947 * conf_tx() operation. 947 * conf_tx() operation.
948 *
949 * @IEEE80211_HW_REPORTS_TX_ACK_STATUS:
950 * Hardware can provide ack status reports of Tx frames to
951 * the stack.
952 *
948 */ 953 */
949enum ieee80211_hw_flags { 954enum ieee80211_hw_flags {
950 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, 955 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -965,6 +970,7 @@ enum ieee80211_hw_flags {
965 IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, 970 IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15,
966 IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, 971 IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16,
967 IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, 972 IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
973 IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
968}; 974};
969 975
970/** 976/**
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a5911191f224..9dd98b674cbc 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -316,6 +316,7 @@ enum ieee80211_sta_flags {
316 IEEE80211_STA_CSA_RECEIVED = BIT(5), 316 IEEE80211_STA_CSA_RECEIVED = BIT(5),
317 IEEE80211_STA_MFP_ENABLED = BIT(6), 317 IEEE80211_STA_MFP_ENABLED = BIT(6),
318 IEEE80211_STA_UAPSD_ENABLED = BIT(7), 318 IEEE80211_STA_UAPSD_ENABLED = BIT(7),
319 IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
319}; 320};
320 321
321struct ieee80211_if_managed { 322struct ieee80211_if_managed {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7a7921476582..ee9443dc20ff 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -434,8 +434,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
434 } else { 434 } else {
435 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) 435 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
436 ieee80211_send_nullfunc(local, sdata, 1); 436 ieee80211_send_nullfunc(local, sdata, 1);
437 conf->flags |= IEEE80211_CONF_PS; 437
438 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 438 if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) {
439 conf->flags |= IEEE80211_CONF_PS;
440 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
441 }
439 } 442 }
440} 443}
441 444
@@ -541,6 +544,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
541 container_of(work, struct ieee80211_local, 544 container_of(work, struct ieee80211_local,
542 dynamic_ps_enable_work); 545 dynamic_ps_enable_work);
543 struct ieee80211_sub_if_data *sdata = local->ps_sdata; 546 struct ieee80211_sub_if_data *sdata = local->ps_sdata;
547 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
544 548
545 /* can only happen when PS was just disabled anyway */ 549 /* can only happen when PS was just disabled anyway */
546 if (!sdata) 550 if (!sdata)
@@ -549,11 +553,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
549 if (local->hw.conf.flags & IEEE80211_CONF_PS) 553 if (local->hw.conf.flags & IEEE80211_CONF_PS)
550 return; 554 return;
551 555
552 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) 556 if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
557 (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)))
553 ieee80211_send_nullfunc(local, sdata, 1); 558 ieee80211_send_nullfunc(local, sdata, 1);
554 559
555 local->hw.conf.flags |= IEEE80211_CONF_PS; 560 if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) ||
556 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 561 (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
562 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
563 local->hw.conf.flags |= IEEE80211_CONF_PS;
564 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
565 }
557} 566}
558 567
559void ieee80211_dynamic_ps_timer(unsigned long data) 568void ieee80211_dynamic_ps_timer(unsigned long data)
@@ -1892,6 +1901,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
1892 return -ENOMEM; 1901 return -ENOMEM;
1893 1902
1894 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; 1903 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
1904 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
1895 1905
1896 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) 1906 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
1897 if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || 1907 if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index e57ad6b1d7ea..ded98730c111 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -188,6 +188,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
188 rcu_read_lock(); 188 rcu_read_lock();
189 189
190 sband = local->hw.wiphy->bands[info->band]; 190 sband = local->hw.wiphy->bands[info->band];
191 fc = hdr->frame_control;
191 192
192 for_each_sta_info(local, hdr->addr1, sta, tmp) { 193 for_each_sta_info(local, hdr->addr1, sta, tmp) {
193 /* skip wrong virtual interface */ 194 /* skip wrong virtual interface */
@@ -205,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
205 return; 206 return;
206 } 207 }
207 208
208 fc = hdr->frame_control;
209
210 if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && 209 if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
211 (ieee80211_is_data_qos(fc))) { 210 (ieee80211_is_data_qos(fc))) {
212 u16 tid, ssn; 211 u16 tid, ssn;
@@ -275,6 +274,20 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
275 local->dot11FailedCount++; 274 local->dot11FailedCount++;
276 } 275 }
277 276
277 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
278 (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
279 !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
280 local->ps_sdata && !(local->scanning)) {
281 if (info->flags & IEEE80211_TX_STAT_ACK) {
282 local->ps_sdata->u.mgd.flags |=
283 IEEE80211_STA_NULLFUNC_ACKED;
284 ieee80211_queue_work(&local->hw,
285 &local->dynamic_ps_enable_work);
286 } else
287 mod_timer(&local->dynamic_ps_timer, jiffies +
288 msecs_to_jiffies(10));
289 }
290
278 /* this was a transmitted frame, but now we want to reuse it */ 291 /* this was a transmitted frame, but now we want to reuse it */
279 skb_orphan(skb); 292 skb_orphan(skb);
280 293