The driver can receive several frames in the same USB transfer. Add the code to handle this in rtl8xxxu_parse_rxdesc24(), even though currently all the relevant chips send only one frame per USB transfer (RTL8723BU, RTL8192EU, RTL8188FU, RTL8710BU). This was tested with RTL8188FU, RTL8192EU, RTL8710BU, and RTL8192FU. Signed-off-by: Bitterblue Smith <rtl8821cerfe2@xxxxxxxxx> --- v2: - Suggestion by Ping-Ke Shih: - Add variable hdr to make a long line shorter. - Don't say rtl8xxxu_parse_rxdesc16() already handles RX aggregation. That function needs more work. --- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 119 ++++++++++++------ 1 file changed, 78 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index fd8c8c6d53d6..1ce18dc8a41e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6197,61 +6197,98 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct ieee80211_hw *hw = priv->hw; - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct rtl8xxxu_rxdesc24 *rx_desc = - (struct rtl8xxxu_rxdesc24 *)skb->data; + struct ieee80211_rx_status *rx_status; + struct rtl8xxxu_rxdesc24 *rx_desc; struct rtl8723au_phy_stats *phy_stats; - __le32 *_rx_desc_le = (__le32 *)skb->data; - u32 *_rx_desc = (u32 *)skb->data; + struct sk_buff *next_skb = NULL; + __le32 *_rx_desc_le; + u32 *_rx_desc; int drvinfo_sz, desc_shift; - int i; + int i, pkt_len, urb_len, pkt_offset; - for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++) - _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); + urb_len = skb->len; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + if (urb_len < sizeof(struct rtl8xxxu_rxdesc24)) { + kfree_skb(skb); + return RX_TYPE_ERROR; + } - skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24)); + do { + rx_desc = (struct rtl8xxxu_rxdesc24 *)skb->data; + _rx_desc_le = (__le32 *)skb->data; + _rx_desc = (u32 *)skb->data; - phy_stats = (struct rtl8723au_phy_stats *)skb->data; + for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++) + _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); - drvinfo_sz = rx_desc->drvinfo_sz * 8; - desc_shift = rx_desc->shift; - skb_pull(skb, drvinfo_sz + desc_shift); + pkt_len = rx_desc->pktlen; - if (rx_desc->rpt_sel) { - struct device *dev = &priv->udev->dev; - dev_dbg(dev, "%s: C2H packet\n", __func__); - rtl8723bu_handle_c2h(priv, skb); - return RX_TYPE_C2H; - } + drvinfo_sz = rx_desc->drvinfo_sz * 8; + desc_shift = rx_desc->shift; + pkt_offset = roundup(pkt_len + drvinfo_sz + desc_shift + + sizeof(struct rtl8xxxu_rxdesc24), 8); + + /* + * Only clone the skb if there's enough data at the end to + * at least cover the rx descriptor + */ + if (urb_len >= (pkt_offset + sizeof(struct rtl8xxxu_rxdesc24))) + next_skb = skb_clone(skb, GFP_ATOMIC); - if (rx_desc->phy_stats) - priv->fops->parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data, - rx_desc->crc32 || rx_desc->icverr); + rx_status = IEEE80211_SKB_RXCB(skb); + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - rx_status->mactime = rx_desc->tsfl; - rx_status->flag |= RX_FLAG_MACTIME_START; + skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24)); - if (!rx_desc->swdec) - rx_status->flag |= RX_FLAG_DECRYPTED; - if (rx_desc->crc32) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_desc->bw) - rx_status->bw = RATE_INFO_BW_40; + phy_stats = (struct rtl8723au_phy_stats *)skb->data; - if (rx_desc->rxmcs >= DESC_RATE_MCS0) { - rx_status->encoding = RX_ENC_HT; - rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; - } else { - rx_status->rate_idx = rx_desc->rxmcs; - } + skb_pull(skb, drvinfo_sz + desc_shift); - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->band = hw->conf.chandef.chan->band; + skb_trim(skb, pkt_len); + + if (rx_desc->rpt_sel) { + struct device *dev = &priv->udev->dev; + dev_dbg(dev, "%s: C2H packet\n", __func__); + rtl8723bu_handle_c2h(priv, skb); + } else { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (rx_desc->phy_stats) + priv->fops->parse_phystats(priv, rx_status, phy_stats, + rx_desc->rxmcs, hdr, + rx_desc->crc32 || rx_desc->icverr); + + rx_status->mactime = rx_desc->tsfl; + rx_status->flag |= RX_FLAG_MACTIME_START; + + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->bw = RATE_INFO_BW_40; + + if (rx_desc->rxmcs >= DESC_RATE_MCS0) { + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } + + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; + + ieee80211_rx_irqsafe(hw, skb); + } + + skb = next_skb; + if (skb) + skb_pull(next_skb, pkt_offset); + + urb_len -= pkt_offset; + next_skb = NULL; + } while (skb && urb_len >= sizeof(struct rtl8xxxu_rxdesc24)); - ieee80211_rx_irqsafe(hw, skb); return RX_TYPE_DATA_PKT; } -- 2.39.2