diff options
-rw-r--r-- | include/net/mac80211.h | 32 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 5 | ||||
-rw-r--r-- | net/mac80211/main.c | 8 | ||||
-rw-r--r-- | net/mac80211/rx.c | 86 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 118 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 23 | ||||
-rw-r--r-- | net/mac80211/tx.c | 13 |
7 files changed, 200 insertions, 85 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7f035d779db9..2c10eac637d8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -2137,6 +2137,38 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | |||
2137 | const u8 *addr); | 2137 | const u8 *addr); |
2138 | 2138 | ||
2139 | /** | 2139 | /** |
2140 | * ieee80211_sta_block_awake - block station from waking up | ||
2141 | * @hw: the hardware | ||
2142 | * @pubsta: the station | ||
2143 | * @block: whether to block or unblock | ||
2144 | * | ||
2145 | * Some devices require that all frames that are on the queues | ||
2146 | * for a specific station that went to sleep are flushed before | ||
2147 | * a poll response or frames after the station woke up can be | ||
2148 | * delivered to that it. Note that such frames must be rejected | ||
2149 | * by the driver as filtered, with the appropriate status flag. | ||
2150 | * | ||
2151 | * This function allows implementing this mode in a race-free | ||
2152 | * manner. | ||
2153 | * | ||
2154 | * To do this, a driver must keep track of the number of frames | ||
2155 | * still enqueued for a specific station. If this number is not | ||
2156 | * zero when the station goes to sleep, the driver must call | ||
2157 | * this function to force mac80211 to consider the station to | ||
2158 | * be asleep regardless of the station's actual state. Once the | ||
2159 | * number of outstanding frames reaches zero, the driver must | ||
2160 | * call this function again to unblock the station. That will | ||
2161 | * cause mac80211 to be able to send ps-poll responses, and if | ||
2162 | * the station queried in the meantime then frames will also | ||
2163 | * be sent out as a result of this. Additionally, the driver | ||
2164 | * will be notified that the station woke up some time after | ||
2165 | * it is unblocked, regardless of whether the station actually | ||
2166 | * woke up while blocked or not. | ||
2167 | */ | ||
2168 | void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | ||
2169 | struct ieee80211_sta *pubsta, bool block); | ||
2170 | |||
2171 | /** | ||
2140 | * ieee80211_beacon_loss - inform hardware does not receive beacons | 2172 | * ieee80211_beacon_loss - inform hardware does not receive beacons |
2141 | * | 2173 | * |
2142 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | 2174 | * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. |
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) | |||
792 | static void ap_sta_ps_end(struct sta_info *sta) | 792 | static 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 | ||
824 | static ieee80211_rx_result debug_noinline | 816 | static 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) | |||
1094 | static ieee80211_rx_result debug_noinline | 1086 | static ieee80211_rx_result debug_noinline |
1095 | ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) | 1087 | ieee80211_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 | ||
264 | static 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 | |||
262 | struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | 279 | struct 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 | } |
827 | EXPORT_SYMBOL(ieee80211_find_sta); | 847 | EXPORT_SYMBOL(ieee80211_find_sta); |
848 | |||
849 | /* powersave support code */ | ||
850 | void 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 | |||
874 | void 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 | |||
933 | void 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 | } | ||
943 | EXPORT_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 | */ |
40 | enum ieee80211_sta_info_flags { | 46 | enum 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 | */ |
220 | struct sta_info { | 230 | struct 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, | |||
430 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | 444 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, |
431 | unsigned long exp_time); | 445 | unsigned long exp_time); |
432 | 446 | ||
447 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); | ||
448 | void 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); |