summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h9
-rw-r--r--net/mac80211/rx.c10
-rw-r--r--net/mac80211/sta_info.c22
-rw-r--r--net/mac80211/sta_info.h2
4 files changed, 26 insertions, 17 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dd07964ef154..ee6449eff7dc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -370,7 +370,8 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period,
* when its status is reported the service period ends. For frames in
* an SP that mac80211 transmits, it is already set; for driver frames
- * the driver may set this flag.
+ * the driver may set this flag. It is also used to do the same for
+ * PS-Poll responses.
*
* Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -1959,6 +1960,12 @@ enum ieee80211_frame_release_type {
* more-data bit must always be set.
* The @tids parameter tells the driver which TIDs to release frames
* from, for PS-poll it will always have only a single bit set.
+ * In the case this is used for a PS-poll initiated release, the
+ * @num_frames parameter will always be 1 so code can be shared. In
+ * this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag
+ * on the TX status (and must report TX status) so that the PS-poll
+ * period is properly ended. This is used to avoid sending multiple
+ * responses for a retried PS-poll frame.
* In the case this is used for uAPSD, the @num_frames parameter may be
* bigger than one, but the driver may send fewer frames (it must send
* at least one, however). In this case it is also responsible for
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9a703f00b5fb..32c8ee43f720 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)
return RX_CONTINUE;
if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
- if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
- ieee80211_sta_ps_deliver_poll_response(rx->sta);
- else
- set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
+ if (!test_sta_flags(rx->sta, WLAN_STA_SP)) {
+ if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
+ ieee80211_sta_ps_deliver_poll_response(rx->sta);
+ else
+ set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
+ }
/* Free PS Poll skb here instead of returning RX_DROP that would
* count as an dropped frame. */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d9cb56f548a9..5732e4d0cc21 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,
/*
* Tell TX path to send this frame even though the
* STA may still remain is PS mode after this frame
- * exchange.
+ * exchange. Also set EOSP to indicate this packet
+ * ends the poll/service period.
*/
- info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
-
- if (uapsd)
- info->flags |= IEEE80211_TX_STATUS_EOSP |
- IEEE80211_TX_CTL_REQ_TX_STATUS;
+ info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
+ IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
ieee80211_xmit(sdata, skb);
}
@@ -1241,6 +1240,9 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
unsigned long driver_release_tids = 0;
struct sk_buff_head frames;
+ /* Service or PS-Poll period starts */
+ set_sta_flags(sta, WLAN_STA_SP);
+
__skb_queue_head_init(&frames);
/*
@@ -1357,10 +1359,11 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
/* set EOSP for the frame */
u8 *p = ieee80211_get_qos_ctl(hdr);
*p |= IEEE80211_QOS_CTL_EOSP;
- info->flags |= IEEE80211_TX_STATUS_EOSP |
- IEEE80211_TX_CTL_REQ_TX_STATUS;
}
+ info->flags |= IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+
__skb_queue_tail(&pending, skb);
}
@@ -1422,9 +1425,6 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta)
if (!delivery_enabled)
return;
- /* Ohh, finally, the service period starts :-) */
- set_sta_flags(sta, WLAN_STA_SP);
-
switch (sta->sta.max_sp) {
case 1:
n_frames = 2;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 751ad25f925f..348847a32630 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -50,7 +50,7 @@
* keeping station in power-save mode, reply when the driver
* unblocks the station.
* @WLAN_STA_SP: Station is in a service period, so don't try to
- * reply to other uAPSD trigger frames.
+ * reply to other uAPSD trigger frames or PS-Poll.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,