diff --git a/src/wifi/model/wifi-remote-station-manager.cc b/src/wifi/model/wifi-remote-station-manager.cc index 1ee231491..965a2ae6f 100644 --- a/src/wifi/model/wifi-remote-station-manager.cc +++ b/src/wifi/model/wifi-remote-station-manager.cc @@ -9,6 +9,7 @@ #include "wifi-remote-station-manager.h" #include "ap-wifi-mac.h" +#include "gcr-manager.h" #include "sta-wifi-mac.h" #include "wifi-mac-header.h" #include "wifi-mac-trailer.h" @@ -604,21 +605,10 @@ WifiTxVector WifiRemoteStationManager::GetDataTxVector(const WifiMacHeader& header, MHz_u allowedWidth) { NS_LOG_FUNCTION(this << header << allowedWidth); - Mac48Address address = header.GetAddr1(); + const auto address = header.GetAddr1(); if (!header.IsMgt() && address.IsGroup()) { - WifiMode mode = GetNonUnicastMode(); - WifiTxVector v; - v.SetMode(mode); - v.SetPreambleType( - GetPreambleForTransmission(mode.GetModulationClass(), GetShortPreambleEnabled())); - v.SetTxPowerLevel(m_defaultTxPowerLevel); - v.SetChannelWidth(m_wifiPhy->GetTxBandwidth(mode, allowedWidth)); - v.SetGuardInterval(GetGuardIntervalForMode(mode, m_wifiPhy->GetDevice())); - v.SetNTx(GetNumberOfAntennas()); - v.SetNss(1); - v.SetNess(0); - return v; + return GetGroupcastTxVector(header, allowedWidth); } WifiTxVector txVector; if (header.IsMgt()) @@ -1945,6 +1935,112 @@ WifiRemoteStationManager::GetNonUnicastMode() const } } +WifiTxVector +WifiRemoteStationManager::GetGroupcastTxVector(const WifiMacHeader& header, MHz_u allowedWidth) +{ + const auto& to = header.GetAddr1(); + NS_ASSERT(to.IsGroup()); + + WifiTxVector groupcastTxVector{}; + const auto mode = GetNonUnicastMode(); + groupcastTxVector.SetMode(mode); + groupcastTxVector.SetPreambleType( + GetPreambleForTransmission(mode.GetModulationClass(), GetShortPreambleEnabled())); + groupcastTxVector.SetTxPowerLevel(m_defaultTxPowerLevel); + groupcastTxVector.SetChannelWidth(m_wifiPhy->GetTxBandwidth(mode, allowedWidth)); + groupcastTxVector.SetNTx(GetNumberOfAntennas()); + + if (to.IsBroadcast()) + { + return groupcastTxVector; + } + + auto apMac = DynamicCast(m_wifiMac); + if (!apMac) + { + return groupcastTxVector; + } + + auto gcrManager = apMac->GetGcrManager(); + if (!gcrManager) + { + return groupcastTxVector; + } + + const auto& groupStas = gcrManager->GetMemberStasForGroupAddress(to); + if (groupStas.empty()) + { + return groupcastTxVector; + } + + // If we are here, that means the mode will be used for the transmission of a groupcast frame + // using the GCR service. We should loop over each member STA that is going to receive the + // groupcast frame and select the highest possible mode over all STAs. + std::optional groupcastMode; + auto maxWidth = allowedWidth; + auto maxNss = m_wifiPhy->GetMaxSupportedTxSpatialStreams(); + std::map minGisPerMc{/* non-HT OFDM is always 800 ns */ + {WIFI_MOD_CLASS_HT, NanoSeconds(400)}, + {WIFI_MOD_CLASS_HE, NanoSeconds(800)}}; + const std::map giRefModClass{ + /* HT/VHT: short or long GI */ + {WIFI_MOD_CLASS_HT, WIFI_MOD_CLASS_HT}, + {WIFI_MOD_CLASS_VHT, WIFI_MOD_CLASS_HT}, + /* HE/EHT: 3 possible GIs */ + {WIFI_MOD_CLASS_HE, WIFI_MOD_CLASS_HE}, + {WIFI_MOD_CLASS_EHT, WIFI_MOD_CLASS_HE}}; + for (const auto& staAddress : groupStas) + { + // Get the equivalent TXVECTOR if the frame would be a unicast frame to that STA in order to + // get what rate would be selected for that STA. + WifiMacHeader hdr(WIFI_MAC_QOSDATA); + hdr.SetAddr1(staAddress); + const auto unicastTxVector = GetDataTxVector(hdr, allowedWidth); + + // update the groupcast mode if: + // - this is the first mode to inspect; + // - this mode has a lower modulation class than the currently selected groupcast mode; + // - when the modulation class is similar, this mode has a lower MCS than the currently + // selected groupcast mode. + if (!groupcastMode.has_value() || + (unicastTxVector.GetModulationClass() < groupcastMode->GetModulationClass()) || + ((unicastTxVector.GetModulationClass() == groupcastMode->GetModulationClass()) && + (unicastTxVector.GetMode().GetMcsValue() < groupcastMode->GetMcsValue()))) + { + groupcastMode = unicastTxVector.GetMode(); + } + maxWidth = std::min(unicastTxVector.GetChannelWidth(), maxWidth); + maxNss = std::min(unicastTxVector.GetNss(), maxNss); + auto mc = unicastTxVector.GetModulationClass(); + if (const auto it = giRefModClass.find(mc); it != giRefModClass.cend()) + { + mc = it->second; + } + if (auto it = minGisPerMc.find(mc); it != minGisPerMc.end()) + { + it->second = std::max(unicastTxVector.GetGuardInterval(), it->second); + } + } + NS_ASSERT(groupcastMode.has_value()); + + groupcastTxVector.SetMode(*groupcastMode); + groupcastTxVector.SetPreambleType( + GetPreambleForTransmission(groupcastMode->GetModulationClass(), GetShortPreambleEnabled())); + groupcastTxVector.SetChannelWidth(maxWidth); + groupcastTxVector.SetNss(maxNss); + auto mc = groupcastMode->GetModulationClass(); + if (const auto it = giRefModClass.find(mc); it != giRefModClass.cend()) + { + mc = it->second; + } + if (const auto it = minGisPerMc.find(mc); it != minGisPerMc.cend()) + { + groupcastTxVector.SetGuardInterval(it->second); + } + + return groupcastTxVector; +} + bool WifiRemoteStationManager::DoNeedRts(WifiRemoteStation* station, uint32_t size, bool normally) { diff --git a/src/wifi/model/wifi-remote-station-manager.h b/src/wifi/model/wifi-remote-station-manager.h index a4be1148b..82ca0900e 100644 --- a/src/wifi/model/wifi-remote-station-manager.h +++ b/src/wifi/model/wifi-remote-station-manager.h @@ -697,6 +697,15 @@ class WifiRemoteStationManager : public Object */ WifiMode GetNonUnicastMode() const; + /** + * Return the TXVECTOR to use for a groupcast packet. + * + * @param header the MAC header of the groupcast packet + * @param allowedWidth the allowed width in MHz to send this packet + * @return the TXVECTOR to use to send the groupcast packet + */ + WifiTxVector GetGroupcastTxVector(const WifiMacHeader& header, MHz_u allowedWidth); + /** * Invoked in a STA or AP to store the set of * modes supported by a destination which is