diff --git a/src/wifi/model/wifi-default-protection-manager.cc b/src/wifi/model/wifi-default-protection-manager.cc index 3d4b71824..9d63535ea 100644 --- a/src/wifi/model/wifi-default-protection-manager.cc +++ b/src/wifi/model/wifi-default-protection-manager.cc @@ -68,14 +68,22 @@ WifiDefaultProtectionManager::TryAddMpdu(Ptr mpdu, const WifiTxP { NS_LOG_FUNCTION(this << *mpdu << &txParams); - // For a DL MU PPDU containing more than one PSDU, call a separate method. + // Call a separate method that handles MU-RTS/CTS protection in case of DL MU PPDU containing + // more than one PSDU or in case the MPDU being added is addressed to an EMLSR client or in + // case the protection method is already MU-RTS/CTS. // A DL MU PPDU contains more than one PSDU if either the TX params' PSDU info map // contains more than one entry or it contains one entry but the MPDU being added is // addressed to a different receiver (hence generating a new entry if the MPDU is added) - if (const auto& psduInfoMap = txParams.GetPsduInfoMap(); + const auto& psduInfoMap = txParams.GetPsduInfoMap(); + auto dlMuPpdu = txParams.m_txVector.IsDlMu() && (psduInfoMap.size() > 1 || - (psduInfoMap.size() == 1 && psduInfoMap.begin()->first != mpdu->GetHeader().GetAddr1()))) + (psduInfoMap.size() == 1 && psduInfoMap.begin()->first != mpdu->GetHeader().GetAddr1())); + auto isEmlsrDestination = + GetWifiRemoteStationManager()->GetEmlsrEnabled(mpdu->GetHeader().GetAddr1()); + + if (dlMuPpdu || isEmlsrDestination || + (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS)) { return TryAddMpduToMuPpdu(mpdu, txParams); } @@ -208,13 +216,24 @@ WifiDefaultProtectionManager::TryAddMpduToMuPpdu(Ptr mpdu, const WifiTxParameters& txParams) { NS_LOG_FUNCTION(this << *mpdu << &txParams); - NS_ASSERT(txParams.m_txVector.IsDlMu()); auto receiver = mpdu->GetHeader().GetAddr1(); + const auto& psduInfoMap = txParams.GetPsduInfoMap(); + auto dlMuPpdu = txParams.m_txVector.IsDlMu() && + (psduInfoMap.size() > 1 || + (psduInfoMap.size() == 1 && psduInfoMap.begin()->first != receiver)); + auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(receiver); + NS_ASSERT( + dlMuPpdu || isEmlsrDestination || + (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS)); + auto isProtected = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas().count(receiver) == 1; + bool needMuRts = + (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS) || + (dlMuPpdu && m_sendMuRts && !isProtected) || (isEmlsrDestination && !isProtected); - if (!m_sendMuRts || isProtected) + if (!needMuRts) { // No protection needed if (txParams.m_protection && txParams.m_protection->method == WifiProtection::NONE) @@ -235,7 +254,10 @@ WifiDefaultProtectionManager::TryAddMpduToMuPpdu(Ptr mpdu, // we get here if this is the first MPDU for this receiver. NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs"); auto apMac = StaticCast(m_mac); - auto txWidth = txParams.m_txVector.GetChannelWidth(); + auto modClass = txParams.m_txVector.GetModulationClass(); + auto txWidth = modClass == WIFI_MOD_CLASS_DSSS || modClass == WIFI_MOD_CLASS_HR_DSSS + ? 20 + : txParams.m_txVector.GetChannelWidth(); if (protection != nullptr) { @@ -256,15 +278,12 @@ WifiDefaultProtectionManager::TryAddMpduToMuPpdu(Ptr mpdu, protection->muRts.SetType(TriggerFrameType::MU_RTS_TRIGGER); protection->muRts.SetUlBandwidth(txWidth); - NS_ASSERT_MSG(txParams.GetPsduInfoMap().size() == 1, - "There should be one PSDU in the DL MU PPDU when creating a new " - "WifiMuRtsCtsProtection object"); - - // this is the first MPDU for the second receiver added to the DL MU PPDU. - // Add a User Info field for the first receiver - AddUserInfoToMuRts(protection->muRts, - txWidth, - txParams.GetPsduInfoMap().cbegin()->first); + // Add a User Info field for each of the receivers already in the TX params + for (const auto& [address, info] : txParams.GetPsduInfoMap()) + { + NS_ASSERT_MSG(address != receiver, "This must be the first MPDU for " << receiver); + AddUserInfoToMuRts(protection->muRts, txWidth, address); + } // compute the TXVECTOR to use to send the MU-RTS Trigger Frame protection->muRtsTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(receiver); @@ -272,6 +291,20 @@ WifiDefaultProtectionManager::TryAddMpduToMuPpdu(Ptr mpdu, // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax) protection->muRtsTxVector.SetChannelWidth(txWidth); + // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz + const auto modulation = protection->muRtsTxVector.GetModulationClass(); + if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS) + { + protection->muRtsTxVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps()); + } + } + + // The initial Control frame of frame exchanges shall be sent in the non-HT PPDU or + // non-HT duplicate PPDU format using a rate of 6 Mb/s, 12 Mb/s, or 24 Mb/s. + // (Sec. 35.3.17 of 802.11be D3.0) + if (isEmlsrDestination && !isProtected) + { + GetWifiRemoteStationManager()->AdjustTxVectorForIcf(protection->muRtsTxVector); } // Add a User Info field for the new receiver @@ -296,12 +329,6 @@ WifiDefaultProtectionManager::TryUlMuTransmission(Ptr mpdu, NS_LOG_FUNCTION(this << *mpdu << &txParams); NS_ASSERT(mpdu->GetHeader().IsTrigger()); - if (!m_sendMuRts) - { - // No protection because sending MU-RTS is disabled - return std::make_unique(); - } - CtrlTriggerHeader trigger; mpdu->GetPacket()->PeekHeader(trigger); NS_ASSERT(trigger.GetNUserInfoFields() > 0); @@ -321,6 +348,7 @@ WifiDefaultProtectionManager::TryUlMuTransmission(Ptr mpdu, std::remove_reference_t::const_iterator staIt; bool allProtected = true; + bool isUnprotectedEmlsrDst = false; for (const auto& userInfo : trigger) { @@ -330,12 +358,18 @@ WifiDefaultProtectionManager::TryUlMuTransmission(Ptr mpdu, staIt = staList.find(userInfo.GetAid12()); NS_ASSERT(staIt != staList.cend()); AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second); - allProtected = - allProtected && + bool isProtected = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas().count(staIt->second) == 1; + allProtected = allProtected && isProtected; + + isUnprotectedEmlsrDst = + isUnprotectedEmlsrDst || + (!isProtected && GetWifiRemoteStationManager()->GetEmlsrEnabled(staIt->second)); } - if (allProtected) + bool needMuRts = (m_sendMuRts && !allProtected) || isUnprotectedEmlsrDst; + + if (!needMuRts) { // No protection needed return std::make_unique(); @@ -354,6 +388,13 @@ WifiDefaultProtectionManager::TryUlMuTransmission(Ptr mpdu, { protection->muRtsTxVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps()); } + // The initial Control frame of frame exchanges shall be sent in the non-HT PPDU or + // non-HT duplicate PPDU format using a rate of 6 Mb/s, 12 Mb/s, or 24 Mb/s. + // (Sec. 35.3.17 of 802.11be D3.0) + if (isUnprotectedEmlsrDst) + { + GetWifiRemoteStationManager()->AdjustTxVectorForIcf(protection->muRtsTxVector); + } return protection; } diff --git a/src/wifi/model/wifi-remote-station-manager.cc b/src/wifi/model/wifi-remote-station-manager.cc index 73b39fe92..5d315b9e7 100644 --- a/src/wifi/model/wifi-remote-station-manager.cc +++ b/src/wifi/model/wifi-remote-station-manager.cc @@ -30,6 +30,7 @@ #include "ns3/boolean.h" #include "ns3/eht-configuration.h" #include "ns3/enum.h" +#include "ns3/erp-ofdm-phy.h" #include "ns3/he-configuration.h" #include "ns3/ht-configuration.h" #include "ns3/ht-phy.h" @@ -746,6 +747,39 @@ WifiRemoteStationManager::GetCtsTxVector(Mac48Address to, WifiMode rtsTxMode) co return v; } +void +WifiRemoteStationManager::AdjustTxVectorForIcf(WifiTxVector& txVector) const +{ + NS_LOG_FUNCTION(this << txVector); + + auto txMode = txVector.GetMode(); + if (txMode.GetModulationClass() >= WIFI_MOD_CLASS_HT) + { + auto rate = txMode.GetDataRate(txVector); + if (rate >= 24e6) + { + rate = 24e6; + } + else if (rate >= 12e6) + { + rate = 12e6; + } + else + { + rate = 6e6; + } + txVector.SetPreambleType(WIFI_PREAMBLE_LONG); + if (m_wifiPhy->GetPhyBand() == WIFI_PHY_BAND_2_4GHZ) + { + txVector.SetMode(ErpOfdmPhy::GetErpOfdmRate(rate)); + } + else + { + txVector.SetMode(OfdmPhy::GetOfdmRate(rate)); + } + } +} + WifiTxVector WifiRemoteStationManager::GetAckTxVector(Mac48Address to, const WifiTxVector& dataTxVector) const { diff --git a/src/wifi/model/wifi-remote-station-manager.h b/src/wifi/model/wifi-remote-station-manager.h index cec23c5d5..c60403562 100644 --- a/src/wifi/model/wifi-remote-station-manager.h +++ b/src/wifi/model/wifi-remote-station-manager.h @@ -842,6 +842,13 @@ class WifiRemoteStationManager : public Object * transmission of the data packet itself. */ WifiTxVector GetCtsToSelfTxVector(); + /** + * Adjust the TXVECTOR for an initial Control frame to ensure that the modulation class + * is non-HT and the rate is 6 Mbps, 12 Mbps or 24 Mbps. + * + * \param txVector the TXVECTOR to adjust + */ + void AdjustTxVectorForIcf(WifiTxVector& txVector) const; /** * Return a TXVECTOR for the Ack frame given the destination and the mode of the Data * used by the sender.