diff options
| author | Adrian Chadd <adrian@FreeBSD.org> | 2024-11-25 23:00:24 +0000 |
|---|---|---|
| committer | Adrian Chadd <adrian@FreeBSD.org> | 2024-12-03 05:30:45 +0000 |
| commit | c6b44f64c33010501aee2fd99016aeca54a09a1e (patch) | |
| tree | 15b2628445f5499ba31ba21463edfde618a20472 | |
| parent | 850f78d5a191d0058fcd20beb8b1309b795ecdbd (diff) | |
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
| -rw-r--r-- | sys/net80211/ieee80211_ht.c | 140 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_ht.h | 6 |
2 files changed, 146 insertions, 0 deletions
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_ */ |
