[RFT/RFC 2/5] mac80211: add option to handle amsdu as a list of skb
Janusz Dziedzic
janusz.dziedzic at tieto.com
Thu Jul 10 04:45:11 PDT 2014
Initial version.
Allow to report amsdu frames as a skb list.
Signed-off-by: Janusz Dziedzic <janusz.dziedzic at tieto.com>
---
include/net/mac80211.h | 4 +++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/main.c | 2 +-
net/mac80211/rx.c | 70 +++++++++++++++++++++++++++++++++++++++++---
4 files changed, 72 insertions(+), 5 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e7362f0..9ec8ad1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -873,6 +873,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* subframes share the same sequence number. Reported subframes can be
* either regular MSDU or singly A-MSDUs. Subframes must not be
* interleaved with other frames.
+ * @RX_FLAG_AMSDU_LIST: Some drivers report A-MSDU subframes as a skb list,
+ * with skb->next set. In such case we have one skb that will describe
+ * mpdu frame. All, but last MSDU from A-MSDU should have this flag set.
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = BIT(0),
@@ -902,6 +905,7 @@ enum mac80211_rx_flags {
RX_FLAG_10MHZ = BIT(28),
RX_FLAG_5MHZ = BIT(29),
RX_FLAG_AMSDU_MORE = BIT(30),
+ RX_FLAG_AMSDU_LIST = BIT(31),
};
#define RX_FLAG_STBC_SHIFT 26
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ae35bf1..3dd3133 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1862,6 +1862,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, enum nl80211_tdls_operation oper);
+struct sk_buff * ieee80211_dequeue_mpdu(struct sk_buff_head *frames);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d17c26d..6ac1af4 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -222,7 +222,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
- while ((skb = skb_dequeue(&local->skb_queue)) ||
+ while ((skb = ieee80211_dequeue_mpdu(&local->skb_queue)) ||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
switch (skb->pkt_type) {
case IEEE80211_RX_MSG:
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 394e201..9034a65 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -683,6 +683,68 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}
+static void __ieee80211_queue_mpdu(struct sk_buff_head *frames,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct sk_buff *next = skb->next;
+
+ __skb_queue_tail(frames, skb);
+
+ if (status->flag & RX_FLAG_AMSDU_LIST) {
+ /* Check if amsdu list and queue frames */
+ while (next) {
+ skb = next;
+ next = next->next;
+ __skb_queue_tail(frames, skb);
+ }
+ }
+}
+
+static void ieee80211_queue_mpdu(struct sk_buff_head *frames,
+ struct sk_buff *skb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&frames->lock, flags);
+ __ieee80211_queue_mpdu(frames, skb);
+ spin_unlock_irqrestore(&frames->lock, flags);
+}
+
+static struct sk_buff * __ieee80211_dequeue_mpdu(struct sk_buff_head *frames)
+{
+ struct sk_buff *first, *next;
+
+ first = __skb_dequeue(frames);
+
+ if (!first)
+ goto out;
+
+ next = first;
+ if (IEEE80211_SKB_RXCB(next)->flag & RX_FLAG_AMSDU_LIST) {
+ do {
+ /* Dequeue frames when amsdu list */
+ next->next = __skb_dequeue(frames);
+ next = next->next;
+ } while (next && IEEE80211_SKB_RXCB(next)->flag & RX_FLAG_AMSDU_LIST);
+ }
+
+out:
+ return first;
+}
+
+struct sk_buff * ieee80211_dequeue_mpdu(struct sk_buff_head *frames)
+{
+ struct sk_buff *mpdu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&frames->lock, flags);
+ mpdu = __ieee80211_dequeue_mpdu(frames);
+ spin_unlock_irqrestore(&frames->lock, flags);
+
+ return mpdu;
+}
+
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
struct tid_ampdu_rx *tid_agg_rx,
int index,
@@ -701,7 +763,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
tid_agg_rx->reorder_buf[index] = NULL;
status = IEEE80211_SKB_RXCB(skb);
status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
- __skb_queue_tail(frames, skb);
+ __ieee80211_queue_mpdu(frames, skb);
no_frame:
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
@@ -951,7 +1013,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
return;
dont_reorder:
- __skb_queue_tail(frames, skb);
+ __ieee80211_queue_mpdu(frames, skb);
}
static ieee80211_rx_result debug_noinline
@@ -2950,7 +3012,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
spin_lock_bh(&rx->local->rx_path_lock);
- while ((skb = __skb_dequeue(frames))) {
+ while ((skb = __ieee80211_dequeue_mpdu(frames))) {
/*
* all the other fields are valid across frames
* that belong to an aMPDU since they are on the
@@ -3426,7 +3488,7 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
skb->pkt_type = IEEE80211_RX_MSG;
- skb_queue_tail(&local->skb_queue, skb);
+ ieee80211_queue_mpdu(&local->skb_queue, skb);
tasklet_schedule(&local->tasklet);
}
EXPORT_SYMBOL(ieee80211_rx_irqsafe);
--
1.7.9.5
More information about the ath10k
mailing list