diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c --- a/sys/net80211/ieee80211_ddb.c +++ b/sys/net80211/ieee80211_ddb.c @@ -317,9 +317,9 @@ #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.h b/sys/net80211/ieee80211_node.h --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -270,8 +270,8 @@ /* 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_node.c b/sys/net80211/ieee80211_node.c --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -1044,8 +1044,7 @@ 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_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_sta.c b/sys/net80211/ieee80211_sta.c --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -1875,7 +1875,7 @@ } 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.h b/sys/net80211/ieee80211_vht.h --- a/sys/net80211/ieee80211_vht.h +++ b/sys/net80211/ieee80211_vht.h @@ -40,8 +40,7 @@ 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); diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c --- a/sys/net80211/ieee80211_vht.c +++ b/sys/net80211/ieee80211_vht.c @@ -284,14 +284,65 @@ 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