From: Johannes Berg <johannes@sipsolutions.net>
To: linux-wireless@vger.kernel.org
Subject: [RFC 09/15] mac80211: send (QoS) Null if no buffered frames
Date: Thu, 22 Sep 2011 17:47:35 +0200 [thread overview]
Message-ID: <20110922154851.015675840@sipsolutions.net> (raw)
In-Reply-To: 20110922154726.521122680@sipsolutions.net
From: Johannes Berg <johannes.berg@intel.com>
For PS-poll, there's a possible race between
us expiring a frame and the station polling
for it -- send it a null frame in that case.
For uAPSD, the standard says that we have to
send a frame in each SP, so send null if we
don't have any other frames.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/ieee80211_i.h | 1
net/mac80211/sta_info.c | 100 ++++++++++++++++++++++++++++++++++++++++-----
net/mac80211/tx.c | 3 -
3 files changed, 92 insertions(+), 12 deletions(-)
--- a/net/mac80211/tx.c 2011-09-22 17:14:51.000000000 +0200
+++ b/net/mac80211/tx.c 2011-09-22 17:16:17.000000000 +0200
@@ -1520,8 +1520,7 @@ static int ieee80211_skb_resize(struct i
return 0;
}
-static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
--- a/net/mac80211/ieee80211_i.h 2011-09-22 17:13:04.000000000 +0200
+++ b/net/mac80211/ieee80211_i.h 2011-09-22 17:16:17.000000000 +0200
@@ -1271,6 +1271,7 @@ void mac80211_ev_michael_mic_failure(str
struct ieee80211_hdr *hdr, const u8 *tsc,
gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems);
--- a/net/mac80211/sta_info.c 2011-09-22 17:15:35.000000000 +0200
+++ b/net/mac80211/sta_info.c 2011-09-22 17:16:17.000000000 +0200
@@ -24,6 +24,7 @@
#include "sta_info.h"
#include "debugfs_sta.h"
#include "mesh.h"
+#include "wme.h"
/**
* DOC: STA information lifetime rules
@@ -247,10 +248,16 @@ static void sta_unblock(struct work_stru
ieee80211_sta_ps_deliver_wakeup(sta);
else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
+
+ local_bh_disable();
ieee80211_sta_ps_deliver_poll_response(sta);
+ local_bh_enable();
} else if (test_and_clear_sta_flags(sta, WLAN_STA_UAPSD)) {
clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
+
+ local_bh_disable();
ieee80211_sta_ps_deliver_uapsd(sta);
+ local_bh_enable();
} else
clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
}
@@ -1145,6 +1152,70 @@ void ieee80211_sta_ps_deliver_wakeup(str
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
+static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, int tid,
+ bool uapsd)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_qos_hdr *nullfunc;
+ struct sk_buff *skb;
+ int size = sizeof(*nullfunc);
+ __le16 fc;
+ bool qos = test_sta_flags(sta, WLAN_STA_WME);
+ struct ieee80211_tx_info *info;
+
+ if (qos) {
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_QOS_NULLFUNC |
+ IEEE80211_FCTL_FROMDS);
+ } else {
+ size -= 2;
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_FROMDS);
+ }
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (void *) skb_put(skb, size);
+ nullfunc->frame_control = fc;
+ nullfunc->duration_id = 0;
+ memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+
+ if (qos) {
+ skb->priority = tid;
+
+ skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
+
+ nullfunc->qos_ctrl = cpu_to_le16(tid);
+
+ if (uapsd)
+ nullfunc->qos_ctrl |=
+ cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+
+ /*
+ * Tell TX path to send this frame even though the
+ * STA may still remain is PS mode after this frame
+ * exchange.
+ */
+ info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
+
+ if (uapsd)
+ info->flags |= IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+ ieee80211_xmit(sdata, skb);
+}
+
static void
ieee80211_sta_ps_deliver_response(struct sta_info *sta,
int n_frames, u8 ignored_acs,
@@ -1216,19 +1287,28 @@ ieee80211_sta_ps_deliver_response(struct
}
if (!found) {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ int tid;
+
/*
- * FIXME: This can be the result of a race condition between
- * us expiring a frame and the station polling for it.
- * Should we send it a null-func frame indicating we
- * have nothing buffered for it?
+ * For PS-Poll, this can only happen due to a race condition
+ * when we set the TIM bit and the station notices it, but
+ * before it can poll for the frame we expire it.
+ *
+ * For uAPSD, this is said in the standard (11.2.1.5 h):
+ * At each unscheduled SP for a non-AP STA, the AP shall
+ * attempt to transmit at least one MSDU or MMPDU, but no
+ * more than the value specified in the Max SP Length field
+ * in the QoS Capability element from delivery-enabled ACs,
+ * that are destined for the non-AP STA.
+ *
+ * Since we have no other MSDU/MMPDU, transmit a QoS null frame.
*/
- if (reason == IEEE80211_FRAME_RELEASE_PSPOLL)
- printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
- "though there are no buffered frames for it\n",
- sdata->name, sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ /* This will evaluate to 1, 3, 5 or 7. */
+ tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
+
+ ieee80211_send_null_response(sdata, sta, tid,
+ reason == IEEE80211_FRAME_RELEASE_UAPSD);
return;
}
next prev parent reply other threads:[~2011-09-22 15:50 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-22 15:47 [RFC 00/15] mac80211 uAPSD support Johannes Berg
2011-09-22 15:47 ` [RFC 01/15] mac80211: let drivers inform it about per TID buffered frames Johannes Berg
2011-09-22 15:47 ` [RFC 02/15] mac80211: unify TIM bit handling Johannes Berg
2011-09-22 15:47 ` [RFC 03/15] mac80211: also expire filtered frames Johannes Berg
2011-09-26 22:30 ` Luis R. Rodriguez
2011-09-27 2:26 ` Adrian Chadd
2011-09-27 7:50 ` Johannes Berg
2011-09-27 12:24 ` Adrian Chadd
2011-09-27 12:25 ` Adrian Chadd
2011-09-27 7:47 ` Johannes Berg
2011-09-22 15:47 ` [RFC 04/15] mac80211: split PS buffers into ACs Johannes Berg
2011-09-27 20:51 ` Luis R. Rodriguez
2011-09-28 7:10 ` Johannes Berg
2011-09-22 15:47 ` [RFC 05/15] mac80211: remove return value from add_pending_skbs Johannes Berg
2011-09-22 15:47 ` [RFC 06/15] mac80211: clear more-data bit on filtered frames Johannes Berg
2011-09-22 15:47 ` [RFC 07/15] mac80211: allow releasing driver-buffered frames Johannes Berg
2011-09-22 15:47 ` [RFC 08/15] mac80211: implement uAPSD Johannes Berg
2011-09-22 15:47 ` Johannes Berg [this message]
2011-09-22 15:47 ` [RFC 10/15] mac80211: reply only once to each PS-poll Johannes Berg
2011-09-22 15:47 ` [RFC 11/15] mac80211: optimise station flags Johannes Berg
2011-09-22 15:47 ` [RFC 12/15] mac80211: add missing station flags to debugfs Johannes Berg
2011-09-22 15:47 ` [RFC 13/15] mac80211: explicitly notify drivers of frame release Johannes Berg
2011-09-22 15:47 ` [RFC 14/15] mac80211: allow out-of-band EOSP notification Johannes Berg
2011-09-22 15:47 ` [RFC 15/15] mac80211: document client powersave Johannes Berg
2011-09-22 15:52 ` [RFC 00/15] mac80211 uAPSD support Johannes Berg
2011-09-22 23:25 ` Luis R. Rodriguez
2011-09-23 8:59 ` Johannes Berg
2011-09-23 18:06 ` Dmitry Tarnyagin
2011-09-23 18:14 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110922154851.015675840@sipsolutions.net \
--to=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.