diff --git a/sys/net80211/ieee80211_ht.h b/sys/net80211/ieee80211_ht.h --- a/sys/net80211/ieee80211_ht.h +++ b/sys/net80211/ieee80211_ht.h @@ -240,5 +240,11 @@ 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(struct ieee80211_node *ni); +int ieee80211_ht_get_node_ampdu_limit(struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_shortgi_20(struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_shortgi_40(struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_ht40(struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_ht(struct ieee80211_node *ht); #endif /* _NET80211_IEEE80211_HT_H_ */ diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -3604,3 +3604,127 @@ 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(struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + int peer_mpdudensity; + + 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(struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + int peer_mpdulimit; + + 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(struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return false; + + /* Note: always assume the node can do HT20 here */ + 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. + */ +bool +ieee80211_ht_check_tx_shortgi_40(struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return false; + + return (ni->ni_chw == 40) + && (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(struct ieee80211_node *ni) +{ + + if (ni->ni_chan == NULL) + return false; + if (ni->ni_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(struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_channel *c = vap->iv_bss->ni_chan; + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return false; + if (c == IEEE80211_CHAN_ANYC) + return false; + + return IEEE80211_IS_CHAN_HT40(c) + && IEEE80211_IS_CHAN_HT40(ni->ni_chan) + && (ni->ni_chw == 40); +}