diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-24 07:23:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-27 15:24:19 -0400 |
commit | 3fa52056f3a8e755708241d5795e6d3e6f55ad85 (patch) | |
tree | 17986e56e775dc55627e4ba9aa0639182ee34339 /net/mac80211/rx.c | |
parent | 91a3bd76155085d41520cf41ede39e8b7f01aeff (diff) |
mac80211: fix PS-poll response, race
When a station queries us for a PS-poll response, we wrongly
queue the frame on the virtual interface's queue rather than
the pending queue.
Additionally, fix a race condition where we could potentially
send multiple frames to the sleeping station due to using a
station flag rather than a packet flag. When converting to a
packet flag, we can also convert p54 and remove the filter
clearing we added for it.
(Also remove a now dead function)
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Reported-by: Bob Copeland <me@bobcopeland.com>
Tested-by: Bob Copeland <me@bobcopeland.com>
Cc: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cb95a3116034..f195705146bd 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -783,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
783 | struct ieee80211_local *local = sdata->local; | 783 | struct ieee80211_local *local = sdata->local; |
784 | 784 | ||
785 | atomic_inc(&sdata->bss->num_sta_ps); | 785 | atomic_inc(&sdata->bss->num_sta_ps); |
786 | set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); | 786 | set_sta_flags(sta, WLAN_STA_PS); |
787 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); | 787 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); |
788 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 788 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
789 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", | 789 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", |
@@ -799,7 +799,7 @@ static int ap_sta_ps_end(struct sta_info *sta) | |||
799 | 799 | ||
800 | atomic_dec(&sdata->bss->num_sta_ps); | 800 | atomic_dec(&sdata->bss->num_sta_ps); |
801 | 801 | ||
802 | clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); | 802 | clear_sta_flags(sta, WLAN_STA_PS); |
803 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); | 803 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); |
804 | 804 | ||
805 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 805 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
@@ -1117,14 +1117,15 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) | |||
1117 | skb_queue_empty(&rx->sta->ps_tx_buf); | 1117 | skb_queue_empty(&rx->sta->ps_tx_buf); |
1118 | 1118 | ||
1119 | if (skb) { | 1119 | if (skb) { |
1120 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1120 | struct ieee80211_hdr *hdr = | 1121 | struct ieee80211_hdr *hdr = |
1121 | (struct ieee80211_hdr *) skb->data; | 1122 | (struct ieee80211_hdr *) skb->data; |
1122 | 1123 | ||
1123 | /* | 1124 | /* |
1124 | * Tell TX path to send one frame even though the STA may | 1125 | * Tell TX path to send this frame even though the STA may |
1125 | * still remain is PS mode after this frame exchange. | 1126 | * still remain is PS mode after this frame exchange. |
1126 | */ | 1127 | */ |
1127 | set_sta_flags(rx->sta, WLAN_STA_PSPOLL); | 1128 | info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; |
1128 | 1129 | ||
1129 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1130 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1130 | printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", | 1131 | printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", |
@@ -1139,7 +1140,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) | |||
1139 | else | 1140 | else |
1140 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1141 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
1141 | 1142 | ||
1142 | dev_queue_xmit(skb); | 1143 | ieee80211_add_pending_skb(rx->local, skb); |
1143 | 1144 | ||
1144 | if (no_pending_pkts) | 1145 | if (no_pending_pkts) |
1145 | sta_info_clear_tim_bit(rx->sta); | 1146 | sta_info_clear_tim_bit(rx->sta); |