All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mac80211: handle non-bufferable MMPDUs correctly
@ 2012-02-27 11:18 Johannes Berg
  0 siblings, 0 replies; only message in thread
From: Johannes Berg @ 2012-02-27 11:18 UTC (permalink / raw)
  To: John Linville
  Cc: linux-wireless, Jouni Malinen, Nicolas Cavallari, Christian Lamparter

From: Johannes Berg <johannes.berg@intel.com>

This renames the IEEE80211_TX_CTL_POLL_RESPONSE
TX flag to IEEE80211_TX_CTL_NO_PS_BUFFER and also
uses it for non-bufferable MMPDUs (all MMPDUs but
deauth, disassoc and action frames.)

Previously, mac80211 would let the MMPDU through
but not set the flag so drivers supporting some
hardware aids for avoiding the PS races would
then reject the frame.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/iwlegacy/4965-mac.c  |    2 +-
 drivers/net/wireless/iwlwifi/iwl-agn-tx.c |    6 +++++-
 drivers/net/wireless/p54/txrx.c           |    2 +-
 include/net/mac80211.h                    |   17 ++++++++++-------
 net/mac80211/sta_info.c                   |    4 ++--
 net/mac80211/tx.c                         |   17 +++++++++++------
 6 files changed, 30 insertions(+), 18 deletions(-)

--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c	2012-02-24 16:39:05.000000000 +0100
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c	2012-02-27 12:14:43.000000000 +0100
@@ -322,7 +322,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
 		sta_priv = (void *)info->control.sta->drv_priv;
 
 	if (sta_priv && sta_priv->asleep &&
-	    (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
+	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
 		/*
 		 * This sends an asynchronous command to the device,
 		 * but we can rely on it being processed before the
@@ -331,6 +331,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
 		 * counter.
 		 * For now set the counter to just 1 since we do not
 		 * support uAPSD yet.
+		 *
+		 * FIXME: If we get two non-bufferable frames one
+		 * after the other, we might only send out one of
+		 * them because this is racy.
 		 */
 		iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
 	}
--- a/include/net/mac80211.h	2012-02-24 16:39:05.000000000 +0100
+++ b/include/net/mac80211.h	2012-02-27 12:14:43.000000000 +0100
@@ -341,9 +341,9 @@ struct ieee80211_bss_conf {
  *	used to indicate that a frame was already retried due to PS
  * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
  *	used to indicate frame should not be encrypted
- * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
- *	frame (PS-Poll or uAPSD) and should be sent although the station
- *	is in powersave mode.
+ * @IEEE80211_TX_CTL_NO_PS_BUFFER: This frame is a response to a poll
+ *	frame (PS-Poll or uAPSD) or a non-bufferable MMPDU and must
+ *	be sent although the station is in powersave mode.
  * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
  *	transmit function after the current frame, this can be used
  *	by drivers to kick the DMA queue only if unset or when the
@@ -399,7 +399,7 @@ enum mac80211_tx_control_flags {
 	IEEE80211_TX_INTFL_NEED_TXPROCESSING	= BIT(14),
 	IEEE80211_TX_INTFL_RETRIED		= BIT(15),
 	IEEE80211_TX_INTFL_DONT_ENCRYPT		= BIT(16),
-	IEEE80211_TX_CTL_POLL_RESPONSE		= BIT(17),
+	IEEE80211_TX_CTL_NO_PS_BUFFER		= BIT(17),
 	IEEE80211_TX_CTL_MORE_FRAMES		= BIT(18),
 	IEEE80211_TX_INTFL_RETRANSMISSION	= BIT(19),
 	/* hole at 20, use later */
@@ -425,7 +425,7 @@ enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU |	      \
 	IEEE80211_TX_STAT_TX_FILTERED |	IEEE80211_TX_STAT_ACK |		      \
 	IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK |	      \
-	IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE |   \
+	IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_NO_PS_BUFFER |    \
 	IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC |		      \
 	IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
 
@@ -1634,7 +1634,7 @@ void ieee80211_free_txskb(struct ieee802
  * the station sends a PS-Poll or a uAPSD trigger frame, mac80211
  * will inform the driver of this with the @allow_buffered_frames
  * callback; this callback is optional. mac80211 will then transmit
- * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE
+ * the frames as usual and set the %IEEE80211_TX_CTL_NO_PS_BUFFER
  * on each frame. The last frame in the service period (or the only
  * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to
  * indicate that it ends the service period; as this frame must have
@@ -1642,6 +1642,9 @@ void ieee80211_free_txskb(struct ieee802
  * When TX status is reported for this frame, the service period is
  * marked has having ended and a new one can be started by the peer.
  *
+ * Additionally, non-bufferable MMPDUs can also be transmitted by
+ * mac80211 with the %IEEE80211_TX_CTL_NO_PS_BUFFER set in them.
+ *
  * Another race condition can happen on some devices like iwlwifi
  * when there are frames queued for the station and it wakes up
  * or polls; the frames that are already queued could end up being
@@ -2140,7 +2143,7 @@ enum ieee80211_frame_release_type {
  * @allow_buffered_frames: Prepare device to allow the given number of frames
  *	to go out to the given station. The frames will be sent by mac80211
  *	via the usual TX path after this call. The TX information for frames
- *	released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set
+ *	released will also have the %IEEE80211_TX_CTL_NO_PS_BUFFER flag set
  *	and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
  *	frames from multiple TIDs are released and the driver might reorder
  *	them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
--- a/net/mac80211/sta_info.c	2012-02-24 16:39:06.000000000 +0100
+++ b/net/mac80211/sta_info.c	2012-02-27 12:14:43.000000000 +0100
@@ -1048,7 +1048,7 @@ static void ieee80211_send_null_response
 	 * exchange. Also set EOSP to indicate this packet
 	 * ends the poll/service period.
 	 */
-	info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
+	info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
 		       IEEE80211_TX_STATUS_EOSP |
 		       IEEE80211_TX_CTL_REQ_TX_STATUS;
 
@@ -1175,7 +1175,7 @@ ieee80211_sta_ps_deliver_response(struct
 			 * STA may still remain is PS mode after this frame
 			 * exchange.
 			 */
-			info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
+			info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
 
 			/*
 			 * Use MoreData flag to indicate whether there are
--- a/net/mac80211/tx.c	2012-02-25 10:21:14.000000000 +0100
+++ b/net/mac80211/tx.c	2012-02-27 12:14:43.000000000 +0100
@@ -448,18 +448,23 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	struct ieee80211_local *local = tx->local;
 
-	if (unlikely(!sta ||
-		     ieee80211_is_probe_resp(hdr->frame_control) ||
-		     ieee80211_is_auth(hdr->frame_control) ||
-		     ieee80211_is_assoc_resp(hdr->frame_control) ||
-		     ieee80211_is_reassoc_resp(hdr->frame_control)))
+	if (unlikely(!sta))
 		return TX_CONTINUE;
 
 	if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
 		      test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
-		     !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) {
+		     !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
 		int ac = skb_get_queue_mapping(tx->skb);
 
+		/* only deauth, disassoc and action are bufferable MMPDUs */
+		if (ieee80211_is_mgmt(hdr->frame_control) &&
+		    !ieee80211_is_deauth(hdr->frame_control) &&
+		    !ieee80211_is_disassoc(hdr->frame_control) &&
+		    !ieee80211_is_action(hdr->frame_control)) {
+			info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+			return TX_CONTINUE;
+		}
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
 		       sta->sta.addr, sta->sta.aid, ac);
--- a/drivers/net/wireless/iwlegacy/4965-mac.c	2012-02-25 10:21:14.000000000 +0100
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c	2012-02-27 12:15:03.000000000 +0100
@@ -1693,7 +1693,7 @@ il4965_tx_skb(struct il_priv *il, struct
 		sta_priv = (void *)sta->drv_priv;
 
 	if (sta_priv && sta_priv->asleep &&
-	    (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
+	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
 		/*
 		 * This sends an asynchronous command to the device,
 		 * but we can rely on it being processed before the
--- a/drivers/net/wireless/p54/txrx.c	2012-02-23 17:03:18.000000000 +0100
+++ b/drivers/net/wireless/p54/txrx.c	2012-02-27 12:15:08.000000000 +0100
@@ -690,7 +690,7 @@ static void p54_tx_80211_header(struct p
 	if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
 		*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
 
-	if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
+	if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
 		*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
 
 	if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2012-02-27 11:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-27 11:18 [PATCH] mac80211: handle non-bufferable MMPDUs correctly Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.