aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-06 05:35:50 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-06 16:49:10 -0500
commitaf81858172cc0f3da81946aab919c26e4b364efc (patch)
tree8e7a4bf30ff7c23636d810c5a912ff7e3ddb7333 /net/mac80211
parent70d9f405d09e334b609702d88ee03b6119c4b45e (diff)
mac80211: async station powersave handling
Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/main.c8
-rw-r--r--net/mac80211/rx.c86
-rw-r--r--net/mac80211/sta_info.c118
-rw-r--r--net/mac80211/sta_info.h23
-rw-r--r--net/mac80211/tx.c13
6 files changed, 168 insertions, 85 deletions
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 4425b613552c..f043c29070d7 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -66,10 +66,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
66 char buf[100]; 66 char buf[100];
67 struct sta_info *sta = file->private_data; 67 struct sta_info *sta = file->private_data;
68 u32 staflags = get_sta_flags(sta); 68 u32 staflags = get_sta_flags(sta);
69 int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", 69 int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
70 staflags & WLAN_STA_AUTH ? "AUTH\n" : "", 70 staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
71 staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", 71 staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
72 staflags & WLAN_STA_PS ? "PS\n" : "", 72 staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
73 staflags & WLAN_STA_PS_DRIVER ? "PS (driver)\n" : "",
73 staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", 74 staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
74 staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", 75 staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
75 staflags & WLAN_STA_WME ? "WME\n" : "", 76 staflags & WLAN_STA_WME ? "WME\n" : "",
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 9e6703ff7fbb..beb8718d905e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -385,13 +385,13 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
385 * can be unknown, for example with different interrupt status 385 * can be unknown, for example with different interrupt status
386 * bits. 386 * bits.
387 */ 387 */
388 if (test_sta_flags(sta, WLAN_STA_PS) && 388 if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
389 skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { 389 skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
390 skb_queue_tail(&sta->tx_filtered, skb); 390 skb_queue_tail(&sta->tx_filtered, skb);
391 return; 391 return;
392 } 392 }
393 393
394 if (!test_sta_flags(sta, WLAN_STA_PS) && 394 if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
395 !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { 395 !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
396 /* Software retry the packet once */ 396 /* Software retry the packet once */
397 info->flags |= IEEE80211_TX_INTFL_RETRIED; 397 info->flags |= IEEE80211_TX_INTFL_RETRIED;
@@ -406,7 +406,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
406 "queue_len=%d PS=%d @%lu\n", 406 "queue_len=%d PS=%d @%lu\n",
407 wiphy_name(local->hw.wiphy), 407 wiphy_name(local->hw.wiphy),
408 skb_queue_len(&sta->tx_filtered), 408 skb_queue_len(&sta->tx_filtered),
409 !!test_sta_flags(sta, WLAN_STA_PS), jiffies); 409 !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
410#endif 410#endif
411 dev_kfree_skb(skb); 411 dev_kfree_skb(skb);
412} 412}
@@ -446,7 +446,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
446 446
447 if (sta) { 447 if (sta) {
448 if (!(info->flags & IEEE80211_TX_STAT_ACK) && 448 if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
449 test_sta_flags(sta, WLAN_STA_PS)) { 449 test_sta_flags(sta, WLAN_STA_PS_STA)) {
450 /* 450 /*
451 * The STA is in power save mode, so assume 451 * The STA is in power save mode, so assume
452 * that this TX packet failed because of that. 452 * that this TX packet failed because of that.
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c06496f0b76d..28316b2a585f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -781,7 +781,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
781 struct ieee80211_local *local = sdata->local; 781 struct ieee80211_local *local = sdata->local;
782 782
783 atomic_inc(&sdata->bss->num_sta_ps); 783 atomic_inc(&sdata->bss->num_sta_ps);
784 set_sta_flags(sta, WLAN_STA_PS); 784 set_sta_flags(sta, WLAN_STA_PS_STA);
785 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); 785 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
786#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 786#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
787 printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", 787 printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
@@ -792,33 +792,25 @@ static void ap_sta_ps_start(struct sta_info *sta)
792static void ap_sta_ps_end(struct sta_info *sta) 792static void ap_sta_ps_end(struct sta_info *sta)
793{ 793{
794 struct ieee80211_sub_if_data *sdata = sta->sdata; 794 struct ieee80211_sub_if_data *sdata = sta->sdata;
795 struct ieee80211_local *local = sdata->local;
796 int sent, buffered;
797 795
798 atomic_dec(&sdata->bss->num_sta_ps); 796 atomic_dec(&sdata->bss->num_sta_ps);
799 797
800 clear_sta_flags(sta, WLAN_STA_PS); 798 clear_sta_flags(sta, WLAN_STA_PS_STA);
801 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
802
803 if (!skb_queue_empty(&sta->ps_tx_buf))
804 sta_info_clear_tim_bit(sta);
805 799
806#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 800#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
807 printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", 801 printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
808 sdata->dev->name, sta->sta.addr, sta->sta.aid); 802 sdata->dev->name, sta->sta.addr, sta->sta.aid);
809#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 803#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
810 804
811 /* Send all buffered frames to the station */ 805 if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
812 sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
813 buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
814 sent += buffered;
815 local->total_ps_buffered -= buffered;
816
817#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 806#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
818 printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " 807 printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
819 "since STA not sleeping anymore\n", sdata->dev->name, 808 sdata->dev->name, sta->sta.addr, sta->sta.aid);
820 sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
821#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 809#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
810 return;
811 }
812
813 ieee80211_sta_ps_deliver_wakeup(sta);
822} 814}
823 815
824static ieee80211_rx_result debug_noinline 816static ieee80211_rx_result debug_noinline
@@ -866,7 +858,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
866 if (!ieee80211_has_morefrags(hdr->frame_control) && 858 if (!ieee80211_has_morefrags(hdr->frame_control) &&
867 (rx->sdata->vif.type == NL80211_IFTYPE_AP || 859 (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
868 rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { 860 rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
869 if (test_sta_flags(sta, WLAN_STA_PS)) { 861 if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
870 /* 862 /*
871 * Ignore doze->wake transitions that are 863 * Ignore doze->wake transitions that are
872 * indicated by non-data frames, the standard 864 * indicated by non-data frames, the standard
@@ -1094,9 +1086,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
1094static ieee80211_rx_result debug_noinline 1086static ieee80211_rx_result debug_noinline
1095ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) 1087ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
1096{ 1088{
1097 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); 1089 struct ieee80211_sub_if_data *sdata = rx->sdata;
1098 struct sk_buff *skb;
1099 int no_pending_pkts;
1100 __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; 1090 __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
1101 1091
1102 if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || 1092 if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
@@ -1107,56 +1097,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
1107 (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) 1097 (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
1108 return RX_DROP_UNUSABLE; 1098 return RX_DROP_UNUSABLE;
1109 1099
1110 skb = skb_dequeue(&rx->sta->tx_filtered); 1100 if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
1111 if (!skb) { 1101 ieee80211_sta_ps_deliver_poll_response(rx->sta);
1112 skb = skb_dequeue(&rx->sta->ps_tx_buf); 1102 else
1113 if (skb) 1103 set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
1114 rx->local->total_ps_buffered--;
1115 }
1116 no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
1117 skb_queue_empty(&rx->sta->ps_tx_buf);
1118
1119 if (skb) {
1120 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1121 struct ieee80211_hdr *hdr =
1122 (struct ieee80211_hdr *) skb->data;
1123
1124 /*
1125 * Tell TX path to send this frame even though the STA may
1126 * still remain is PS mode after this frame exchange.
1127 */
1128 info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
1129
1130#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
1131 printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
1132 rx->sta->sta.addr, rx->sta->sta.aid,
1133 skb_queue_len(&rx->sta->ps_tx_buf));
1134#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
1135
1136 /* Use MoreData flag to indicate whether there are more
1137 * buffered frames for this STA */
1138 if (no_pending_pkts)
1139 hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
1140 else
1141 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
1142
1143 ieee80211_add_pending_skb(rx->local, skb);
1144
1145 if (no_pending_pkts)
1146 sta_info_clear_tim_bit(rx->sta);
1147#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
1148 } else {
1149 /*
1150 * FIXME: This can be the result of a race condition between
1151 * us expiring a frame and the station polling for it.
1152 * Should we send it a null-func frame indicating we
1153 * have nothing buffered for it?
1154 */
1155 printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
1156 "though there are no buffered frames for it\n",
1157 rx->dev->name, rx->sta->sta.addr);
1158#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
1159 }
1160 1104
1161 /* Free PS Poll skb here instead of returning RX_DROP that would 1105 /* Free PS Poll skb here instead of returning RX_DROP that would
1162 * count as an dropped frame. */ 1106 * count as an dropped frame. */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index cde2da7a74df..be59456e8a42 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -171,6 +171,8 @@ void sta_info_destroy(struct sta_info *sta)
171 171
172 local = sta->local; 172 local = sta->local;
173 173
174 cancel_work_sync(&sta->drv_unblock_wk);
175
174 rate_control_remove_sta_debugfs(sta); 176 rate_control_remove_sta_debugfs(sta);
175 ieee80211_sta_debugfs_remove(sta); 177 ieee80211_sta_debugfs_remove(sta);
176 178
@@ -259,6 +261,21 @@ static void sta_info_hash_add(struct ieee80211_local *local,
259 rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); 261 rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
260} 262}
261 263
264static void sta_unblock(struct work_struct *wk)
265{
266 struct sta_info *sta;
267
268 sta = container_of(wk, struct sta_info, drv_unblock_wk);
269
270 if (sta->dead)
271 return;
272
273 if (!test_sta_flags(sta, WLAN_STA_PS_STA))
274 ieee80211_sta_ps_deliver_wakeup(sta);
275 else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL))
276 ieee80211_sta_ps_deliver_poll_response(sta);
277}
278
262struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, 279struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
263 u8 *addr, gfp_t gfp) 280 u8 *addr, gfp_t gfp)
264{ 281{
@@ -272,6 +289,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
272 289
273 spin_lock_init(&sta->lock); 290 spin_lock_init(&sta->lock);
274 spin_lock_init(&sta->flaglock); 291 spin_lock_init(&sta->flaglock);
292 INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
275 293
276 memcpy(sta->sta.addr, addr, ETH_ALEN); 294 memcpy(sta->sta.addr, addr, ETH_ALEN);
277 sta->local = local; 295 sta->local = local;
@@ -478,8 +496,10 @@ static void __sta_info_unlink(struct sta_info **sta)
478 } 496 }
479 497
480 list_del(&(*sta)->list); 498 list_del(&(*sta)->list);
499 (*sta)->dead = true;
481 500
482 if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { 501 if (test_and_clear_sta_flags(*sta,
502 WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) {
483 BUG_ON(!sdata->bss); 503 BUG_ON(!sdata->bss);
484 504
485 atomic_dec(&sdata->bss->num_sta_ps); 505 atomic_dec(&sdata->bss->num_sta_ps);
@@ -825,3 +845,99 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
825 return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); 845 return ieee80211_find_sta_by_hw(&sdata->local->hw, addr);
826} 846}
827EXPORT_SYMBOL(ieee80211_find_sta); 847EXPORT_SYMBOL(ieee80211_find_sta);
848
849/* powersave support code */
850void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
851{
852 struct ieee80211_sub_if_data *sdata = sta->sdata;
853 struct ieee80211_local *local = sdata->local;
854 int sent, buffered;
855
856 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
857
858 if (!skb_queue_empty(&sta->ps_tx_buf))
859 sta_info_clear_tim_bit(sta);
860
861 /* Send all buffered frames to the station */
862 sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
863 buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
864 sent += buffered;
865 local->total_ps_buffered -= buffered;
866
867#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
868 printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
869 "since STA not sleeping anymore\n", sdata->dev->name,
870 sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
871#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
872}
873
874void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
875{
876 struct ieee80211_sub_if_data *sdata = sta->sdata;
877 struct ieee80211_local *local = sdata->local;
878 struct sk_buff *skb;
879 int no_pending_pkts;
880
881 skb = skb_dequeue(&sta->tx_filtered);
882 if (!skb) {
883 skb = skb_dequeue(&sta->ps_tx_buf);
884 if (skb)
885 local->total_ps_buffered--;
886 }
887 no_pending_pkts = skb_queue_empty(&sta->tx_filtered) &&
888 skb_queue_empty(&sta->ps_tx_buf);
889
890 if (skb) {
891 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
892 struct ieee80211_hdr *hdr =
893 (struct ieee80211_hdr *) skb->data;
894
895 /*
896 * Tell TX path to send this frame even though the STA may
897 * still remain is PS mode after this frame exchange.
898 */
899 info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
900
901#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
902 printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
903 sta->sta.addr, sta->sta.aid,
904 skb_queue_len(&sta->ps_tx_buf));
905#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
906
907 /* Use MoreData flag to indicate whether there are more
908 * buffered frames for this STA */
909 if (no_pending_pkts)
910 hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
911 else
912 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
913
914 ieee80211_add_pending_skb(local, skb);
915
916 if (no_pending_pkts)
917 sta_info_clear_tim_bit(sta);
918#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
919 } else {
920 /*
921 * FIXME: This can be the result of a race condition between
922 * us expiring a frame and the station polling for it.
923 * Should we send it a null-func frame indicating we
924 * have nothing buffered for it?
925 */
926 printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
927 "though there are no buffered frames for it\n",
928 sdata->dev->name, sta->sta.addr);
929#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
930 }
931}
932
933void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
934 struct ieee80211_sta *pubsta, bool block)
935{
936 struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
937
938 if (block)
939 set_sta_flags(sta, WLAN_STA_PS_DRIVER);
940 else
941 ieee80211_queue_work(hw, &sta->drv_unblock_wk);
942}
943EXPORT_SYMBOL(ieee80211_sta_block_awake);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 703f5492ee65..4673454176ed 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -12,6 +12,7 @@
12#include <linux/list.h> 12#include <linux/list.h>
13#include <linux/types.h> 13#include <linux/types.h>
14#include <linux/if_ether.h> 14#include <linux/if_ether.h>
15#include <linux/workqueue.h>
15#include "key.h" 16#include "key.h"
16 17
17/** 18/**
@@ -21,7 +22,7 @@
21 * 22 *
22 * @WLAN_STA_AUTH: Station is authenticated. 23 * @WLAN_STA_AUTH: Station is authenticated.
23 * @WLAN_STA_ASSOC: Station is associated. 24 * @WLAN_STA_ASSOC: Station is associated.
24 * @WLAN_STA_PS: Station is in power-save mode 25 * @WLAN_STA_PS_STA: Station is in power-save mode
25 * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic. 26 * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic.
26 * This bit is always checked so needs to be enabled for all stations 27 * This bit is always checked so needs to be enabled for all stations
27 * when virtual port control is not in use. 28 * when virtual port control is not in use.
@@ -36,11 +37,16 @@
36 * @WLAN_STA_MFP: Management frame protection is used with this STA. 37 * @WLAN_STA_MFP: Management frame protection is used with this STA.
37 * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle. 38 * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle.
38 * Used to deny ADDBA requests (both TX and RX). 39 * Used to deny ADDBA requests (both TX and RX).
40 * @WLAN_STA_PS_DRIVER: driver requires keeping this station in
41 * power-save mode logically to flush frames that might still
42 * be in the queues
43 * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
44 * station in power-save mode, reply when the driver unblocks.
39 */ 45 */
40enum ieee80211_sta_info_flags { 46enum ieee80211_sta_info_flags {
41 WLAN_STA_AUTH = 1<<0, 47 WLAN_STA_AUTH = 1<<0,
42 WLAN_STA_ASSOC = 1<<1, 48 WLAN_STA_ASSOC = 1<<1,
43 WLAN_STA_PS = 1<<2, 49 WLAN_STA_PS_STA = 1<<2,
44 WLAN_STA_AUTHORIZED = 1<<3, 50 WLAN_STA_AUTHORIZED = 1<<3,
45 WLAN_STA_SHORT_PREAMBLE = 1<<4, 51 WLAN_STA_SHORT_PREAMBLE = 1<<4,
46 WLAN_STA_ASSOC_AP = 1<<5, 52 WLAN_STA_ASSOC_AP = 1<<5,
@@ -48,7 +54,9 @@ enum ieee80211_sta_info_flags {
48 WLAN_STA_WDS = 1<<7, 54 WLAN_STA_WDS = 1<<7,
49 WLAN_STA_CLEAR_PS_FILT = 1<<9, 55 WLAN_STA_CLEAR_PS_FILT = 1<<9,
50 WLAN_STA_MFP = 1<<10, 56 WLAN_STA_MFP = 1<<10,
51 WLAN_STA_SUSPEND = 1<<11 57 WLAN_STA_SUSPEND = 1<<11,
58 WLAN_STA_PS_DRIVER = 1<<12,
59 WLAN_STA_PSPOLL = 1<<13,
52}; 60};
53 61
54#define STA_TID_NUM 16 62#define STA_TID_NUM 16
@@ -216,6 +224,8 @@ struct sta_ampdu_mlme {
216 * @plink_timer_was_running: used by suspend/resume to restore timers 224 * @plink_timer_was_running: used by suspend/resume to restore timers
217 * @debugfs: debug filesystem info 225 * @debugfs: debug filesystem info
218 * @sta: station information we share with the driver 226 * @sta: station information we share with the driver
227 * @dead: set to true when sta is unlinked
228 * @drv_unblock_wk used for driver PS unblocking
219 */ 229 */
220struct sta_info { 230struct sta_info {
221 /* General information, mostly static */ 231 /* General information, mostly static */
@@ -229,8 +239,12 @@ struct sta_info {
229 spinlock_t lock; 239 spinlock_t lock;
230 spinlock_t flaglock; 240 spinlock_t flaglock;
231 241
242 struct work_struct drv_unblock_wk;
243
232 u16 listen_interval; 244 u16 listen_interval;
233 245
246 bool dead;
247
234 /* 248 /*
235 * for use by the internal lifetime management, 249 * for use by the internal lifetime management,
236 * see __sta_info_unlink 250 * see __sta_info_unlink
@@ -430,4 +444,7 @@ int sta_info_flush(struct ieee80211_local *local,
430void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, 444void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
431 unsigned long exp_time); 445 unsigned long exp_time);
432 446
447void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
448void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
449
433#endif /* STA_INFO_H */ 450#endif /* STA_INFO_H */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c7dc8ccff5b2..bfaa43e096d2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -374,7 +374,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
374 374
375 staflags = get_sta_flags(sta); 375 staflags = get_sta_flags(sta);
376 376
377 if (unlikely((staflags & WLAN_STA_PS) && 377 if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
378 !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { 378 !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
379#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 379#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
380 printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " 380 printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
@@ -397,8 +397,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
397 } else 397 } else
398 tx->local->total_ps_buffered++; 398 tx->local->total_ps_buffered++;
399 399
400 /* Queue frame to be sent after STA sends an PS Poll frame */ 400 /*
401 if (skb_queue_empty(&sta->ps_tx_buf)) 401 * Queue frame to be sent after STA wakes up/polls,
402 * but don't set the TIM bit if the driver is blocking
403 * wakeup or poll response transmissions anyway.
404 */
405 if (skb_queue_empty(&sta->ps_tx_buf) &&
406 !(staflags & WLAN_STA_PS_DRIVER))
402 sta_info_set_tim_bit(sta); 407 sta_info_set_tim_bit(sta);
403 408
404 info->control.jiffies = jiffies; 409 info->control.jiffies = jiffies;
@@ -408,7 +413,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
408 return TX_QUEUED; 413 return TX_QUEUED;
409 } 414 }
410#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 415#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
411 else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { 416 else if (unlikely(staflags & WLAN_STA_PS_STA)) {
412 printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " 417 printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
413 "set -> send frame\n", tx->dev->name, 418 "set -> send frame\n", tx->dev->name,
414 sta->sta.addr); 419 sta->sta.addr);