aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-09-29 10:04:35 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-30 15:57:18 -0400
commitdeeaee197b0fa694ba6c8f02cdb57b3be7115b4f (patch)
tree9cdd2ce5786ceb60c68327da441913b56de9726c /net
parentce662b44ce22e3e8886104d5feb2a451d7ba560f (diff)
mac80211: reply only once to each PS-poll
If a PS-poll frame is retried (but was received) there is no way to detect that since it has no sequence number. As a consequence, the standard asks us to not react to PS-poll frames until the response to one made it out (was ACKed or lost). Implement this by using the WLAN_STA_SP flags to also indicate a PS-Poll "service period" and the IEEE80211_TX_STATUS_EOSP flag for the response packet to indicate the end of the "SP" as usual. We could use separate flags, but that will most likely completely confuse drivers, and while the standard doesn't exclude simultaneously polling using uAPSD and PS-Poll, doing that seems quite problematic. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/rx.c10
-rw-r--r--net/mac80211/sta_info.c22
-rw-r--r--net/mac80211/sta_info.h2
3 files changed, 18 insertions, 16 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9a703f00b5f..32c8ee43f72 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1194,10 +1194,12 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
1194 return RX_CONTINUE; 1194 return RX_CONTINUE;
1195 1195
1196 if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) { 1196 if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
1197 if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER)) 1197 if (!test_sta_flags(rx->sta, WLAN_STA_SP)) {
1198 ieee80211_sta_ps_deliver_poll_response(rx->sta); 1198 if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
1199 else 1199 ieee80211_sta_ps_deliver_poll_response(rx->sta);
1200 set_sta_flags(rx->sta, WLAN_STA_PSPOLL); 1200 else
1201 set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
1202 }
1201 1203
1202 /* Free PS Poll skb here instead of returning RX_DROP that would 1204 /* Free PS Poll skb here instead of returning RX_DROP that would
1203 * count as an dropped frame. */ 1205 * count as an dropped frame. */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d9cb56f548a..5732e4d0cc2 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1217,13 +1217,12 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
1217 /* 1217 /*
1218 * Tell TX path to send this frame even though the 1218 * Tell TX path to send this frame even though the
1219 * STA may still remain is PS mode after this frame 1219 * STA may still remain is PS mode after this frame
1220 * exchange. 1220 * exchange. Also set EOSP to indicate this packet
1221 * ends the poll/service period.
1221 */ 1222 */
1222 info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE; 1223 info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
1223 1224 IEEE80211_TX_STATUS_EOSP |
1224 if (uapsd) 1225 IEEE80211_TX_CTL_REQ_TX_STATUS;
1225 info->flags |= IEEE80211_TX_STATUS_EOSP |
1226 IEEE80211_TX_CTL_REQ_TX_STATUS;
1227 1226
1228 ieee80211_xmit(sdata, skb); 1227 ieee80211_xmit(sdata, skb);
1229} 1228}
@@ -1241,6 +1240,9 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1241 unsigned long driver_release_tids = 0; 1240 unsigned long driver_release_tids = 0;
1242 struct sk_buff_head frames; 1241 struct sk_buff_head frames;
1243 1242
1243 /* Service or PS-Poll period starts */
1244 set_sta_flags(sta, WLAN_STA_SP);
1245
1244 __skb_queue_head_init(&frames); 1246 __skb_queue_head_init(&frames);
1245 1247
1246 /* 1248 /*
@@ -1357,10 +1359,11 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1357 /* set EOSP for the frame */ 1359 /* set EOSP for the frame */
1358 u8 *p = ieee80211_get_qos_ctl(hdr); 1360 u8 *p = ieee80211_get_qos_ctl(hdr);
1359 *p |= IEEE80211_QOS_CTL_EOSP; 1361 *p |= IEEE80211_QOS_CTL_EOSP;
1360 info->flags |= IEEE80211_TX_STATUS_EOSP |
1361 IEEE80211_TX_CTL_REQ_TX_STATUS;
1362 } 1362 }
1363 1363
1364 info->flags |= IEEE80211_TX_STATUS_EOSP |
1365 IEEE80211_TX_CTL_REQ_TX_STATUS;
1366
1364 __skb_queue_tail(&pending, skb); 1367 __skb_queue_tail(&pending, skb);
1365 } 1368 }
1366 1369
@@ -1422,9 +1425,6 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta)
1422 if (!delivery_enabled) 1425 if (!delivery_enabled)
1423 return; 1426 return;
1424 1427
1425 /* Ohh, finally, the service period starts :-) */
1426 set_sta_flags(sta, WLAN_STA_SP);
1427
1428 switch (sta->sta.max_sp) { 1428 switch (sta->sta.max_sp) {
1429 case 1: 1429 case 1:
1430 n_frames = 2; 1430 n_frames = 2;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 751ad25f925..348847a3263 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -50,7 +50,7 @@
50 * keeping station in power-save mode, reply when the driver 50 * keeping station in power-save mode, reply when the driver
51 * unblocks the station. 51 * unblocks the station.
52 * @WLAN_STA_SP: Station is in a service period, so don't try to 52 * @WLAN_STA_SP: Station is in a service period, so don't try to
53 * reply to other uAPSD trigger frames. 53 * reply to other uAPSD trigger frames or PS-Poll.
54 */ 54 */
55enum ieee80211_sta_info_flags { 55enum ieee80211_sta_info_flags {
56 WLAN_STA_AUTH = 1<<0, 56 WLAN_STA_AUTH = 1<<0,