git: c6b44f64c330 - main - net80211: add helper functions for determining HT transmit parameters

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Tue, 03 Dec 2024 05:32:34 UTC
The branch main has been updated by adrian:

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

commit c6b44f64c33010501aee2fd99016aeca54a09a1e
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2024-11-25 23:00:24 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2024-12-03 05:30:45 +0000

    net80211: add helper functions for determining HT transmit parameters
    
    This adds helper functions to determine a variety of HT related
    transmit parameters:
    
    * AMPDU density and size;
    * short-GI for 20 and 40MHz;
    * Whether 40MHz transmit is allowed;
    * Whether HT rates have been negotiated for transmit.
    
    It should be done here rather than drivers having to re-invent the wheel
    each time.
    
    This is doubly important for AP modes where each node will hvae
    different supported features and this needs to be used when
    assembling transmit frames / configuring transmit parameters.
    
    Differential Revision: https://reviews.freebsd.org/D47747
    
    Reviewed by:    bz
---
 sys/net80211/ieee80211_ht.c | 140 ++++++++++++++++++++++++++++++++++++++++++++
 sys/net80211/ieee80211_ht.h |   6 ++
 2 files changed, 146 insertions(+)

diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 28c329ce3d32..1f97b7b9927a 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -3604,3 +3604,143 @@ ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
 	frm[5] = BCM_OUI_HTINFO;
 	return ieee80211_add_htinfo_body(frm + 6, ni);
 }
+
+/*
+ * Get the HT density for the given 802.11n node.
+ *
+ * Take into account the density advertised from the peer.
+ * Larger values are longer A-MPDU density spacing values, and
+ * we want to obey them per station if we get them.
+ */
+int
+ieee80211_ht_get_node_ampdu_density(const struct ieee80211_node *ni)
+{
+	struct ieee80211vap *vap;
+	int peer_mpdudensity;
+
+	vap = ni->ni_vap;
+	peer_mpdudensity =
+	    _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
+	if (vap->iv_ampdu_density > peer_mpdudensity)
+		peer_mpdudensity = vap->iv_ampdu_density;
+	return (peer_mpdudensity);
+}
+
+/*
+ * Get the transmit A-MPDU limit for the given 802.11n node.
+ *
+ * Take into account the limit advertised from the peer.
+ * Smaller values indicate smaller maximum A-MPDU sizes, and
+ * should be used when forming an A-MPDU to the given peer.
+ */
+int
+ieee80211_ht_get_node_ampdu_limit(const struct ieee80211_node *ni)
+{
+	struct ieee80211vap *vap;
+	int peer_mpdulimit;
+
+	vap = ni->ni_vap;
+	peer_mpdulimit =
+	    _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
+
+	return (MIN(vap->iv_ampdu_limit, peer_mpdulimit));
+}
+
+/*
+ * Return true if short-GI is available when transmitting to
+ * the given node at 20MHz.
+ *
+ * Ensure it's configured and available in the VAP / driver as
+ * well as the node.
+ */
+bool
+ieee80211_ht_check_tx_shortgi_20(const struct ieee80211_node *ni)
+{
+	const struct ieee80211vap *vap;
+	const struct ieee80211com *ic;
+
+	if (! ieee80211_ht_check_tx_ht(ni))
+		return (false);
+
+	vap = ni->ni_vap;
+	ic = ni->ni_ic;
+
+	return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) &&
+	    (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
+	    (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20));
+}
+
+/*
+ * Return true if short-GI is available when transmitting to
+ * the given node at 40MHz.
+ *
+ * Ensure it's configured and available in the VAP / driver as
+ * well as the node and BSS.
+ */
+bool
+ieee80211_ht_check_tx_shortgi_40(const struct ieee80211_node *ni)
+{
+	const struct ieee80211vap *vap;
+	const struct ieee80211com *ic;
+
+	if (! ieee80211_ht_check_tx_ht40(ni))
+		return (false);
+
+	vap = ni->ni_vap;
+	ic = ni->ni_ic;
+
+	return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40) &&
+	    (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
+	    (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40));
+}
+
+/*
+ * Return true if HT rates can be used for the given node.
+ *
+ * There are some situations seen in the wild, wild past where
+ * HT APs would announce HT but no HT rates.
+ */
+bool
+ieee80211_ht_check_tx_ht(const struct ieee80211_node *ni)
+{
+	const struct ieee80211vap *vap;
+	const struct ieee80211_channel *bss_chan;
+
+	if (ni == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC ||
+	    ni->ni_vap == NULL || ni->ni_vap->iv_bss == NULL)
+		return (false);
+
+	vap = ni->ni_vap;
+	bss_chan = vap->iv_bss->ni_chan;
+
+	if (bss_chan == IEEE80211_CHAN_ANYC)
+		return (false);
+
+	if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
+	    ni->ni_htrates.rs_nrates == 0)
+		return (false);
+	return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
+}
+
+/*
+ * Return true if HT40 rates can be transmitted to the given node.
+ *
+ * This verifies that the BSS is HT40 capable and the current
+ * node channel width is 40MHz.
+ */
+bool
+ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni)
+{
+	struct ieee80211vap *vap;
+	struct ieee80211_channel *bss_chan;
+
+	if (! ieee80211_ht_check_tx_ht(ni))
+		return (false);
+
+	vap = ni->ni_vap;
+	bss_chan = vap->iv_bss->ni_chan;
+
+	return (IEEE80211_IS_CHAN_HT40(bss_chan) &&
+	    IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
+	    (ni->ni_chw == 40));
+}
diff --git a/sys/net80211/ieee80211_ht.h b/sys/net80211/ieee80211_ht.h
index 6ba791065d15..0f4c1025695e 100644
--- a/sys/net80211/ieee80211_ht.h
+++ b/sys/net80211/ieee80211_ht.h
@@ -240,5 +240,11 @@ int	ieee80211_ampdu_tx_request_ext(struct ieee80211_node *ni, int tid);
 int	ieee80211_ampdu_tx_request_active_ext(struct ieee80211_node *ni,
 	    int tid, int status);
 void	ieee80211_htinfo_notify(struct ieee80211vap *vap);
+int	ieee80211_ht_get_node_ampdu_density(const struct ieee80211_node *ni);
+int	ieee80211_ht_get_node_ampdu_limit(const struct ieee80211_node *ni);
+bool	ieee80211_ht_check_tx_shortgi_20(const struct ieee80211_node *ni);
+bool	ieee80211_ht_check_tx_shortgi_40(const struct ieee80211_node *ni);
+bool	ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni);
+bool	ieee80211_ht_check_tx_ht(const struct ieee80211_node *ht);
 
 #endif /* _NET80211_IEEE80211_HT_H_ */