git: a1adefb139b3 - main - LinuxKPI; 802.11: start filling rxrate statistics

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Mon, 14 Apr 2025 14:07:44 UTC
The branch main has been updated by bz:

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

commit a1adefb139b3c8f95e5255c67705fb92f4d9fc04
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-13 23:05:46 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-14 14:06:51 +0000

    LinuxKPI; 802.11: start filling rxrate statistics
    
    Start collecting rxrate information from the RX statistics which are
    passed per packet.  Store them in the lsta and upon printing statistics,
    if no RX_BIRATE is provided copy them over from the lsta.
    
    This allows us to see rate information in both directions on modern
    iwlwifi chipsets, which are doing [tx]rate handling in firmware.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/src/linux_80211.c | 72 +++++++++++++++++++++-------
 sys/compat/linuxkpi/common/src/linux_80211.h |  2 +
 2 files changed, 58 insertions(+), 16 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 4690c65df468..78021bd8e44c 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -314,6 +314,13 @@ lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS)
 			continue;
 		}
 
+		/* If no RX_BITRATE is reported, try to fill it in from the lsta sinfo. */
+		if ((sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) == 0 &&
+		    (lsta->sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) != 0) {
+			memcpy(&sinfo.rxrate, &lsta->sinfo.rxrate, sizeof(sinfo.rxrate));
+			sinfo.filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
+		}
+
 		lkpi_nl80211_sta_info_to_str(&s, " nl80211_sta_info (valid fields)", sinfo.filled);
 		sbuf_printf(&s, " connected_time %u inactive_time %u\n",
 		    sinfo.connected_time, sinfo.inactive_time);
@@ -6294,15 +6301,17 @@ lkpi_80211_lhw_rxq_task(void *ctx, int pending)
 }
 
 static void
-lkpi_convert_rx_status(struct ieee80211_hw *hw,
+lkpi_convert_rx_status(struct ieee80211_hw *hw, struct lkpi_sta *lsta,
     struct ieee80211_rx_status *rx_status,
     struct ieee80211_rx_stats *rx_stats,
     uint8_t *rssip)
 {
 	struct ieee80211_supported_band *supband;
+	struct rate_info rxrate;
 	int i;
 	uint8_t rssi;
 
+	memset(&rxrate, 0, sizeof(rxrate));
 	memset(rx_stats, 0, sizeof(*rx_stats));
 	rx_stats->r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI;
 	/* XXX-BZ correct hardcoded noise floor, survey data? */
@@ -6369,30 +6378,56 @@ lkpi_convert_rx_status(struct ieee80211_hw *hw,
 
 	switch (rx_status->encoding) {
 	case RX_ENC_LEGACY:
+	{
+		uint32_t legacy = 0;
+
 		supband = hw->wiphy->bands[rx_status->band];
 		if (supband != NULL)
-			rx_stats->c_rate = supband->bitrates[rx_status->rate_idx].bitrate;
+			legacy = supband->bitrates[rx_status->rate_idx].bitrate;
+		rx_stats->c_rate = legacy;
+		rxrate.legacy = legacy;
 		/* Is there a LinuxKPI way of reporting IEEE80211_RX_F_CCK / _OFDM? */
 		break;
+	}
 	case RX_ENC_HT:
 		rx_stats->c_pktflags |= IEEE80211_RX_F_HT;
-		if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0)
-			rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;
 		rx_stats->c_rate = rx_status->rate_idx;		/* mcs */
+		rxrate.flags |= RATE_INFO_FLAGS_MCS;
+		rxrate.mcs = rx_status->rate_idx;
+		if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0) {
+			rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;
+			rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		}
 		break;
 	case RX_ENC_VHT:
 		rx_stats->c_pktflags |= IEEE80211_RX_F_VHT;
-		if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0)
-			rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;
 		rx_stats->c_rate = rx_status->rate_idx;		/* mcs */
 		rx_stats->c_vhtnss = rx_status->nss;
+		rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
+		rxrate.mcs = rx_status->rate_idx;
+		rxrate.nss = rx_status->nss;
+		if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0) {
+			rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;
+			rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		}
 		break;
 	case RX_ENC_HE:
+		rxrate.flags |= RATE_INFO_FLAGS_HE_MCS;
+		rxrate.mcs = rx_status->rate_idx;
+		rxrate.nss = rx_status->nss;
+		/* XXX TODO */
+		TODO("net80211 has not matching encoding for %u", rx_status->encoding);
+		break;
 	case RX_ENC_EHT:
+		rxrate.flags |= RATE_INFO_FLAGS_EHT_MCS;
+		rxrate.mcs = rx_status->rate_idx;
+		rxrate.nss = rx_status->nss;
+		/* XXX TODO */
 		TODO("net80211 has not matching encoding for %u", rx_status->encoding);
 		break;
 	}
 
+	rxrate.bw = rx_status->bw;
 	switch (rx_status->bw) {
 	case RATE_INFO_BW_20:
 		rx_stats->c_width = IEEE80211_RX_FW_20MHZ;
@@ -6443,6 +6478,11 @@ lkpi_convert_rx_status(struct ieee80211_hw *hw,
 	if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC)
 		rx_stats->c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;
 #endif
+
+	if (lsta != NULL) {
+		memcpy(&lsta->sinfo.rxrate, &rxrate, sizeof(rxrate));
+		lsta->sinfo.filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
+	}
 }
 
 /* For %list see comment towards the end of the function. */
@@ -6545,16 +6585,6 @@ linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
 no_trace_beacons:
 #endif
 
-	rssi = 0;
-	lkpi_convert_rx_status(hw, rx_status, &rx_stats, &rssi);
-
-	ok = ieee80211_add_rx_params(m, &rx_stats);
-	if (ok == 0) {
-		m_freem(m);
-		counter_u64_add(ic->ic_ierrors, 1);
-		goto err;
-	}
-
 	lsta = NULL;
 	if (sta != NULL) {
 		lsta = STA_TO_LSTA(sta);
@@ -6568,6 +6598,16 @@ no_trace_beacons:
 			lsta = ni->ni_drv_data;
 	}
 
+	rssi = 0;
+	lkpi_convert_rx_status(hw, lsta, rx_status, &rx_stats, &rssi);
+
+	ok = ieee80211_add_rx_params(m, &rx_stats);
+	if (ok == 0) {
+		m_freem(m);
+		counter_u64_add(ic->ic_ierrors, 1);
+		goto err;
+	}
+
 	if (ni != NULL)
 		vap = ni->ni_vap;
 	else
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h
index 6d5476ff8852..a5c052c78db0 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -163,6 +163,8 @@ struct lkpi_sta {
 	bool			added_to_drv;			/* Driver knows; i.e. we called ...(). */
 	bool			in_mgd;				/* XXX-BZ should this be per-vif? */
 
+	struct station_info	sinfo;				/* statistics */
+
 	/* Must be last! */
 	struct ieee80211_sta	sta __aligned(CACHE_LINE_SIZE);
 };