git: 1c746222c2ef - main - net80211: Implement ieee80211_setup_vht_rates()

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Wed, 26 Feb 2025 19:31:41 UTC
The branch main has been updated by adrian:

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

commit 1c746222c2ef25d2caa7578217ce92b637a1ee3d
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2025-01-13 05:17:36 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2025-02-26 19:30:23 +0000

    net80211: Implement ieee80211_setup_vht_rates()
    
    Implement ieee80211_setup_vht_rates() - calculate the intersection between
    the peers advertised RX VHT MCS map and the vap's configured TX map.
    
    Whilst here, remove the unused vhtcap/vhtinfo fields; they're
    already populated in the ieee80211_node before ieee80211_setup_vht_rates()
    is called.
    
    Differential Revision:  https://reviews.freebsd.org/D48607
    Reviewed by:    bz
---
 sys/net80211/ieee80211_ddb.c  |  4 +--
 sys/net80211/ieee80211_node.c |  7 ++---
 sys/net80211/ieee80211_node.h |  4 +--
 sys/net80211/ieee80211_sta.c  |  2 +-
 sys/net80211/ieee80211_vht.c  | 61 +++++++++++++++++++++++++++++++++++++++----
 sys/net80211/ieee80211_vht.h  |  3 +--
 6 files changed, 64 insertions(+), 17 deletions(-)

diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c
index 5dbb20dfe8e0..3c57b03ddc65 100644
--- a/sys/net80211/ieee80211_ddb.c
+++ b/sys/net80211/ieee80211_ddb.c
@@ -317,9 +317,9 @@ _db_show_sta(const struct ieee80211_node *ni)
 #endif
 
 	/* VHT state */
-	db_printf("\tvhtcap %b vht_basicmcs %#06x vht_pad2 %#06x\n",
+	db_printf("\tvhtcap %b vht_basicmcs %#06x vht_tx_map %#06x\n",
 	    ni->ni_vhtcap, IEEE80211_VHTCAP_BITS,
-	    ni->ni_vht_basicmcs, ni->ni_vht_pad2);
+	    ni->ni_vht_basicmcs, ni->ni_vht_tx_map);
 	db_printf("\tvht_mcsinfo: { rx_mcs_map %#06x rx_highest %#06x "
 	    "tx_mcs_map %#06x tx_highest %#06x }\n",
 	    ni->ni_vht_mcsinfo.rx_mcs_map, ni->ni_vht_mcsinfo.rx_highest,
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index c781280d5e8a..5a239bbd30f6 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -1044,8 +1044,7 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
 			ieee80211_vht_updateparams(ni,
 			    ni->ni_ies.vhtcap_ie,
 			    ni->ni_ies.vhtopmode_ie);
-			ieee80211_setup_vht_rates(ni, ni->ni_ies.vhtcap_ie,
-			    ni->ni_ies.vhtopmode_ie);
+			ieee80211_setup_vht_rates(ni);
 			do_ht = 1;
 		}
 	}
@@ -1874,9 +1873,7 @@ ieee80211_init_neighbor(struct ieee80211_node *ni,
 				ieee80211_vht_updateparams(ni,
 				    ni->ni_ies.vhtcap_ie,
 				    ni->ni_ies.vhtopmode_ie);
-				ieee80211_setup_vht_rates(ni,
-				    ni->ni_ies.vhtcap_ie,
-				    ni->ni_ies.vhtopmode_ie);
+				ieee80211_setup_vht_rates(ni);
 			}
 		}
 
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index bb14c8c4bb42..969d8e563fa9 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -274,8 +274,8 @@ struct ieee80211_node {
 
 	/* VHT state */
 	uint32_t		ni_vhtcap;
-	uint16_t		ni_vht_basicmcs;
-	uint16_t		ni_vht_pad2;
+	uint16_t		ni_vht_basicmcs;	/* Basic VHT MCS bitmap from IE */
+	uint16_t		ni_vht_tx_map;		/* Negotiated MCS TX map with peer */
 	struct ieee80211_vht_mcs_info	ni_vht_mcsinfo;
 	uint8_t			ni_vht_chan1;	/* 20/40/80/160 - VHT chan1 */
 	uint8_t			ni_vht_chan2;	/* 80+80 - VHT chan2 */
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 96603f339710..48d56d0ad217 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -1875,7 +1875,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
 				} else {
 					ieee80211_vht_node_init(ni);
 					ieee80211_vht_updateparams(ni, vhtcap, vhtopmode);
-					ieee80211_setup_vht_rates(ni, vhtcap, vhtopmode);
+					ieee80211_setup_vht_rates(ni);
 				}
 			}
 
diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c
index 82879f90c67b..e704e0cbd176 100644
--- a/sys/net80211/ieee80211_vht.c
+++ b/sys/net80211/ieee80211_vht.c
@@ -284,14 +284,65 @@ ieee80211_vht_updateparams(struct ieee80211_node *ni,
 	return (0);
 }
 
+/**
+ * @brief calculate the supported MCS rates for this node
+ *
+ * This is called once a node has finished association /
+ * joined a BSS.  The vhtcap / vhtop IEs are from the
+ * peer.  The transmit rate tables need to be combined
+ * together to setup the list of available rates.
+ *
+ * This must be called after the ieee80211_node VHT fields
+ * have been parsed / populated by either ieee80211_vht_updateparams() or
+ * ieee80211_parse_vhtcap(),
+ *
+ * This does not take into account the channel bandwidth,
+ * which (a) may change during operation, and (b) depends
+ * upon packet to packet rate transmission selection.
+ * There are various rate combinations which are not
+ * available in various channel widths and those will
+ * need to be masked off separately.
+ *
+ * (See 802.11-2020 21.5 Parameters for VHT-MCSs for the
+ * tables and supported rates.)
+ *
+ * ALSO: i need to do some filtering based on the HT set too.
+ * (That should be done here too, and in the negotiation, sigh.)
+ * (See 802.11-2016 10.7.12.3 Additional rate selection constraints
+ * for VHT PPDUs)
+ *
+ * @param ni	struct ieee80211_node to configure
+ */
 void
-ieee80211_setup_vht_rates(struct ieee80211_node *ni,
-    const uint8_t *vhtcap_ie,
-    const uint8_t *vhtop_ie)
+ieee80211_setup_vht_rates(struct ieee80211_node *ni)
 {
+	struct ieee80211vap *vap = ni->ni_vap;
+	uint32_t val, val1, val2;
+	uint16_t tx_mcs_map = 0;
+	int i;
 
-	//printf("%s: called\n", __func__);
-	/* XXX TODO */
+	/*
+	 * Merge our tx_mcs_map with the peer rx_mcs_map to determine what
+	 * can be actually transmitted to the peer.
+	 */
+
+	for (i = 0; i < 8; i++) {
+		/*
+		 * Merge the two together; remember that 0..2 is in order
+		 * of increasing MCS support, but 3 equals
+		 * IEEE80211_VHT_MCS_NOT_SUPPORTED so must "win".
+		 */
+		val1 = (vap->iv_vht_cap.supp_mcs.tx_mcs_map >> (i*2)) & 0x3;
+		val2 = (ni->ni_vht_mcsinfo.rx_mcs_map >> (i*2)) & 0x3;
+		val = MIN(val1, val2);
+		if (val1 == IEEE80211_VHT_MCS_NOT_SUPPORTED ||
+		    val2 == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+			val = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+		tx_mcs_map |= (val << (i*2));
+	}
+
+	/* Store the TX MCS map somewhere in the node that can be used */
+	ni->ni_vht_tx_map = tx_mcs_map;
 }
 
 void
diff --git a/sys/net80211/ieee80211_vht.h b/sys/net80211/ieee80211_vht.h
index bcb61020c5a1..a61804a43059 100644
--- a/sys/net80211/ieee80211_vht.h
+++ b/sys/net80211/ieee80211_vht.h
@@ -40,8 +40,7 @@ void	ieee80211_parse_vhtcap(struct ieee80211_node *, const uint8_t *);
 
 int	ieee80211_vht_updateparams(struct ieee80211_node *,
 	    const uint8_t *, const uint8_t *);
-void	ieee80211_setup_vht_rates(struct ieee80211_node *,
-	    const uint8_t *, const uint8_t *);
+void	ieee80211_setup_vht_rates(struct ieee80211_node *);
 
 void	ieee80211_vht_timeout(struct ieee80211vap *vap);