git: 4d29178e7154 - main - iwx: tag RX frames as A_MPDU RX; tag A-MSDU frames appropriately

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Fri, 21 Nov 2025 07:11:05 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=4d29178e715449c25b94f115946dc4e021f41cdb

commit 4d29178e715449c25b94f115946dc4e021f41cdb
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2025-11-16 04:26:22 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2025-11-21 07:09:47 +0000

    iwx: tag RX frames as A_MPDU RX; tag A-MSDU frames appropriately
    
    * tag packets for 11n/11ac associated nodes with A_MPDU so they
      get passed into the reordering logic
    
    * tag A-MSDU frames with AMSDU and AMSDU_MORE so they don't get
      dropped due to duplicate sequence numbers.
    
    Note: I haven't yet elicited A-MSDU in A-MPDU to fully test this,
    but I do see the net80211 reordering logic kick in (which you can
    see via wlanstats -i wlan0 -o ampdu 1).
    
    I've checked with Johannes Berg at Intel (who maintains the linux
    iwlwifi stuff); he replied saying none of the firmware versions are
    doing AMPDU reorder offloading.
    
    Differential Revision:  https://reviews.freebsd.org/D53781
    
    Locally tested:
    
     * AX210, STA mode, > 200mbit bidirectional traffic testing on
       5GHz VHT/40.
---
 sys/dev/iwx/if_iwx.c | 62 +++++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/sys/dev/iwx/if_iwx.c b/sys/dev/iwx/if_iwx.c
index e317ff9e271c..3c953e522973 100644
--- a/sys/dev/iwx/if_iwx.c
+++ b/sys/dev/iwx/if_iwx.c
@@ -4607,37 +4607,39 @@ iwx_rx_mpdu_mq(struct iwx_softc *sc, struct mbuf *m, void *pktdata,
 		pad = 1;
 	}
 
-//	/*
-//	 * Hardware de-aggregates A-MSDUs and copies the same MAC header
-//	 * in place for each subframe. But it leaves the 'A-MSDU present'
-//	 * bit set in the frame header. We need to clear this bit ourselves.
-//	 * (XXX This workaround is not required on AX200/AX201 devices that
-//	 * have been tested by me, but it's unclear when this problem was
-//	 * fixed in the hardware. It definitely affects the 9k generation.
-//	 * Leaving this in place for now since some 9k/AX200 hybrids seem
-//	 * to exist that we may eventually add support for.)
-//	 *
-//	 * And we must allow the same CCMP PN for subframes following the
-//	 * first subframe. Otherwise they would be discarded as replays.
-//	 */
+	/* If it's a HT node then perform re-order processing */
+	if (ni->ni_flags & IEEE80211_NODE_HT)
+		m->m_flags |= M_AMPDU;
+
+	/*
+	 * Hardware de-aggregates A-MSDUs and copies the same MAC header
+	 * in place for each subframe. But it leaves the 'A-MSDU present'
+	 * bit set in the frame header. We need to clear this bit ourselves.
+	 * (XXX This workaround is not required on AX200/AX201 devices that
+	 * have been tested by me, but it's unclear when this problem was
+	 * fixed in the hardware. It definitely affects the 9k generation.
+	 * Leaving this in place for now since some 9k/AX200 hybrids seem
+	 * to exist that we may eventually add support for.)
+	 *
+	 * And we must allow the same CCMP PN for subframes following the
+	 * first subframe. Otherwise they would be discarded as replays.
+	 */
 	if (desc->mac_flags2 & IWX_RX_MPDU_MFLG2_AMSDU) {
-		DPRINTF(("%s: === IWX_RX_MPDU_MFLG2_AMSDU\n", __func__));
-//		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
-//		uint8_t subframe_idx = (desc->amsdu_info &
-//		    IWX_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK);
-//		if (subframe_idx > 0)
-//			rxi.rxi_flags |= IEEE80211_RXI_HWDEC_SAME_PN;
-//		if (ieee80211_has_qos(wh) && ieee80211_has_addr4(wh) &&
-//		    m->m_len >= sizeof(struct ieee80211_qosframe_addr4)) {
-//			struct ieee80211_qosframe_addr4 *qwh4 = mtod(m,
-//			    struct ieee80211_qosframe_addr4 *);
-//			qwh4->i_qos[0] &= htole16(~IEEE80211_QOS_AMSDU);
-//		} else if (ieee80211_has_qos(wh) &&
-//		    m->m_len >= sizeof(struct ieee80211_qosframe)) {
-//			struct ieee80211_qosframe *qwh = mtod(m,
-//			    struct ieee80211_qosframe *);
-//			qwh->i_qos[0] &= htole16(~IEEE80211_QOS_AMSDU);
-//		}
+		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
+		uint8_t subframe_idx = (desc->amsdu_info &
+		    IWX_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK);
+		uint8_t *qos;
+
+		rxs.c_pktflags |= IEEE80211_RX_F_AMSDU;
+		if (subframe_idx > 0)
+			rxs.c_pktflags |= IEEE80211_RX_F_AMSDU_MORE;
+
+		/* XXX should keep driver statistics about this */
+		IWX_DPRINTF(sc, IWX_DEBUG_AMPDU_MGMT,
+		    "%s: === IWX_RX_MPDU_MFLG2_AMSDU\n", __func__);
+
+		qos = ieee80211_getqos(wh);
+		qos[0] &= ~IEEE80211_QOS_AMSDU;
 	}
 
 	/*