diff --git a/src/wifi/model/eht/eht-capabilities.cc b/src/wifi/model/eht/eht-capabilities.cc index 20f48806d..082688d8e 100644 --- a/src/wifi/model/eht/eht-capabilities.cc +++ b/src/wifi/model/eht/eht-capabilities.cc @@ -363,6 +363,111 @@ EhtCapabilities::GetMaxAmpduLength() const 15523200); } +void +EhtCapabilities::SetSupportedRxEhtMcsAndNss(EhtMcsAndNssSet::EhtMcsMapType mapType, + uint8_t upperMcs, + uint8_t maxNss) +{ + NS_ASSERT_MSG(maxNss <= 8, "Invalid maximum NSS " << maxNss); + std::size_t index = 0; + switch (upperMcs) + { + case 7: + NS_ASSERT(mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY); + index = 0; + break; + case 9: + index = (mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY) ? 1 : 0; + break; + case 11: + index = (mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY) ? 2 : 1; + break; + case 13: + index = (mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY) ? 3 : 2; + break; + default: + NS_ASSERT_MSG(false, "Invalid upper MCS " << +upperMcs); + } + uint8_t nBytes = 0; + switch (mapType) + { + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY: + nBytes = 4; + break; + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_NOT_LARGER_THAN_80_MHZ: + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_160_MHZ: + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_320_MHZ: + nBytes = 3; + break; + default: + NS_ASSERT_MSG(false, "Invalid map type " << mapType); + } + auto it = m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet.find(mapType); + if (it == m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet.end()) + { + m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet[mapType].resize(nBytes); + m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet[mapType][index] = (maxNss & 0x0f); + } + else + { + NS_ASSERT(it->second.size() == nBytes); + it->second[index] |= (maxNss & 0x0f); + } +} + +void +EhtCapabilities::SetSupportedTxEhtMcsAndNss(EhtMcsAndNssSet::EhtMcsMapType mapType, + uint8_t upperMcs, + uint8_t maxNss) +{ + NS_ASSERT_MSG(maxNss <= 8, "Invalid maximum NSS " << maxNss); + std::size_t index = 0; + switch (upperMcs) + { + case 7: + NS_ASSERT(mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY); + index = 0; + break; + case 9: + index = (mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY) ? 1 : 0; + break; + case 11: + index = (mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY) ? 2 : 1; + break; + case 13: + index = (mapType == EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY) ? 3 : 2; + break; + default: + NS_ASSERT_MSG(false, "Invalid upper MCS " << upperMcs); + } + uint8_t nBytes = 0; + switch (mapType) + { + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY: + nBytes = 4; + break; + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_NOT_LARGER_THAN_80_MHZ: + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_160_MHZ: + case EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_320_MHZ: + nBytes = 3; + break; + default: + NS_ASSERT_MSG(false, "Invalid map type " << mapType); + } + auto it = m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet.find(mapType); + if (it == m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet.end()) + { + m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet[mapType].resize(nBytes); + m_supportedEhtMcsAndNssSet.supportedEhtMcsAndNssSet[mapType][index] = + ((maxNss & 0x0f) << 4); + } + else + { + NS_ASSERT(it->second.size() == nBytes); + it->second[index] |= ((maxNss & 0x0f) << 4); + } +} + void EhtCapabilities::SerializeInformationField(Buffer::Iterator start) const { diff --git a/src/wifi/model/eht/eht-capabilities.h b/src/wifi/model/eht/eht-capabilities.h index 61837b2c4..d8d8c21f2 100644 --- a/src/wifi/model/eht/eht-capabilities.h +++ b/src/wifi/model/eht/eht-capabilities.h @@ -249,6 +249,27 @@ class EhtCapabilities : public WifiInformationElement */ uint16_t GetMaxMpduLength() const; + /** + * Set a subfield of the Supported EHT-MCS And NSS Set. + * + * \param mapType the type of the subfield + * \param upperMcs the upper MCS of the range + * \param maxNss the maximum NSS supported for transmission in the MCS range + */ + void SetSupportedTxEhtMcsAndNss(EhtMcsAndNssSet::EhtMcsMapType mapType, + uint8_t upperMcs, + uint8_t maxNss); + /** + * Set a subfield of the Supported EHT-MCS And NSS Set. + * + * \param mapType the type of the subfield + * \param upperMcs the upper MCS of the range + * \param maxNss the maximum NSS supported for reception in the MCS range + */ + void SetSupportedRxEhtMcsAndNss(EhtMcsAndNssSet::EhtMcsMapType mapType, + uint8_t upperMcs, + uint8_t maxNss); + EhtMacCapabilities m_macCapabilities; //!< EHT MAC Capabilities Info subfield EhtPhyCapabilities m_phyCapabilities; //!< EHT PHY Capabilities Info subfield EhtMcsAndNssSet m_supportedEhtMcsAndNssSet; //!< Supported EHT-MCS And NSS Set subfield diff --git a/src/wifi/model/wifi-mac.cc b/src/wifi/model/wifi-mac.cc index 2f8313a20..fdc6de3e8 100644 --- a/src/wifi/model/wifi-mac.cc +++ b/src/wifi/model/wifi-mac.cc @@ -1616,6 +1616,58 @@ WifiMac::GetEhtCapabilities(uint8_t linkId) const capabilities.m_phyCapabilities.supportRx1024And4096QamForRuSmallerThan242Tones = support4096Qam ? 1 : 0; + const uint8_t maxTxNss = phy->GetMaxSupportedTxSpatialStreams(); + const uint8_t maxRxNss = phy->GetMaxSupportedRxSpatialStreams(); + if (phy->GetChannelWidth() == 20) + { + for (auto maxMcs : {7, 9, 11, 13}) + { + capabilities.SetSupportedRxEhtMcsAndNss( + EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY, + maxMcs, + phy->IsMcsSupported(WIFI_MOD_CLASS_EHT, maxMcs) ? maxRxNss : 0); + capabilities.SetSupportedTxEhtMcsAndNss( + EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_20_MHZ_ONLY, + maxMcs, + phy->IsMcsSupported(WIFI_MOD_CLASS_EHT, maxMcs) ? maxTxNss : 0); + } + } + else + { + if (phy->GetPhyBand() != WIFI_PHY_BAND_2_4GHZ) + { + NS_ABORT_MSG_IF(phy->GetChannelWidth() == 40, + "A 802.11be STA cannot support 40 MHz without supporting 80 MHz except " + "in 2.4 GHz band"); + } + for (auto maxMcs : {9, 11, 13}) + { + capabilities.SetSupportedRxEhtMcsAndNss( + EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_NOT_LARGER_THAN_80_MHZ, + maxMcs, + phy->IsMcsSupported(WIFI_MOD_CLASS_EHT, maxMcs) ? maxRxNss : 0); + capabilities.SetSupportedTxEhtMcsAndNss( + EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_NOT_LARGER_THAN_80_MHZ, + maxMcs, + phy->IsMcsSupported(WIFI_MOD_CLASS_EHT, maxMcs) ? maxTxNss : 0); + } + } + if (phy->GetChannelWidth() >= 160) + { + for (auto maxMcs : {9, 11, 13}) + { + capabilities.SetSupportedRxEhtMcsAndNss( + EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_160_MHZ, + maxMcs, + phy->IsMcsSupported(WIFI_MOD_CLASS_EHT, maxMcs) ? maxRxNss : 0); + capabilities.SetSupportedTxEhtMcsAndNss( + EhtMcsAndNssSet::EHT_MCS_MAP_TYPE_160_MHZ, + maxMcs, + phy->IsMcsSupported(WIFI_MOD_CLASS_EHT, maxMcs) ? maxTxNss : 0); + } + } + // 320 MHz not supported yet + return capabilities; }