From 5a1761615c5bc819639710044e5dd72889fbbce6 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Sun, 6 Jul 2014 10:18:06 +0200 Subject: [RFC/RFT] ath10k: amsdu rx, buid one big frame Temporary patch, to check if will solve ampdu reordering issue. Signed-off-by: Janusz Dziedzic --- drivers/net/wireless/ath/ath10k/htt_rx.c | 72 +++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 57d5a97..2553f52 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -874,12 +874,15 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, { struct htt_rx_desc *rxd; struct sk_buff *skb = skb_in; - struct sk_buff *first; + struct sk_buff *first, *frame = NULL, *tmp; enum rx_msdu_decap_format fmt; enum htt_rx_mpdu_encrypt_type enctype; struct ieee80211_hdr *hdr; - u8 hdr_buf[64], addr[ETH_ALEN], *qos; + u8 hdr_buf[64], addr[ETH_ALEN]; unsigned int hdr_len; + struct amsdu_subframe_hdr subframe_hdr; + unsigned int size = 0; + u8 padding; rxd = (void *)skb->data - sizeof(*rxd); enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), @@ -890,6 +893,22 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, memcpy(hdr_buf, hdr, hdr_len); hdr = (struct ieee80211_hdr *)hdr_buf; + /* Check size we will need */ + tmp = skb_in; + while (tmp) { + size = size + tmp->len; + tmp = tmp->next; + } + + frame = alloc_skb(size + skb_headroom(skb_in), GFP_KERNEL); + if (!frame) { + dev_kfree_skb_any(skb_in); + return; + } + + skb_reserve(frame, skb_headroom(skb_in)); + frame->dev = skb_in->dev; + first = skb; while (skb) { void *decap_hdr; @@ -922,19 +941,28 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN); skb_pull(skb, hdr_len); - /* push original 802.11 header */ - hdr = (struct ieee80211_hdr *)hdr_buf; - hdr_len = ieee80211_hdrlen(hdr->frame_control); - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); + /* cfg80211 expect this padding */ + padding = (4 - (skb->len + sizeof(subframe_hdr))) & 0x3; + skb_put(skb, padding); - /* original A-MSDU header has the bit set but we're - * not including A-MSDU subframe header */ - hdr = (struct ieee80211_hdr *)skb->data; - qos = ieee80211_get_qos_ctl(hdr); - qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + /* build amsdu subframe header */ + memcpy(&subframe_hdr.dst, addr, ETH_ALEN); + memcpy(&subframe_hdr.src, ieee80211_get_SA(hdr), ETH_ALEN); + subframe_hdr.len = __cpu_to_be16(skb->len) ; - /* original 802.11 header has a different DA */ - memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN); + /* push back amsdu hdr */ + memcpy(skb_push(skb, sizeof(subframe_hdr)), &subframe_hdr, + sizeof(subframe_hdr)); + + if (skb == first) { + /* push back orginal 80211 header */ + hdr = (struct ieee80211_hdr *)hdr_buf; + hdr_len = ieee80211_hdrlen(hdr->frame_control); + memcpy(skb_push(skb, hdr_len), hdr, hdr_len); + + /* original 802.11 header has a different DA */ + memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN); + } break; case RX_MSDU_DECAP_ETHERNET2_DIX: /* strip ethernet header and insert decapped 802.11 @@ -956,19 +984,21 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, } skb_in = skb; - ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt, - false); + + if (skb_in == first) + ath10k_htt_rx_h_protected(htt, rx_status, skb_in, + enctype, fmt, false); + + memcpy(skb_put(frame, skb_in->len), skb_in->data, skb_in->len); + skb = skb->next; skb_in->next = NULL; - if (skb) - rx_status->flag |= RX_FLAG_AMSDU_MORE; - else - rx_status->flag &= ~RX_FLAG_AMSDU_MORE; - - ath10k_process_rx(htt->ar, rx_status, skb_in); + /* We don't need this skb anymore */ + dev_kfree_skb(skb_in); } + ath10k_process_rx(htt->ar, rx_status, frame); /* FIXME: It might be nice to re-assemble the A-MSDU when there's a * monitor interface active for sniffing purposes. */ } -- 1.7.9.5