From bc77d7b4daa34f6b2df7cee48f4c87f4b97d81d3 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Sat, 31 Dec 2022 16:03:25 +0100 Subject: [PATCH] wifi: Add MU-RTS support to the HE Frame Exchange Manager --- src/wifi/model/frame-exchange-manager.cc | 6 +- .../model/he/he-frame-exchange-manager.cc | 397 ++++++++++++++++-- src/wifi/model/he/he-frame-exchange-manager.h | 58 +++ 3 files changed, 418 insertions(+), 43 deletions(-) diff --git a/src/wifi/model/frame-exchange-manager.cc b/src/wifi/model/frame-exchange-manager.cc index df3df1456..4af61078e 100644 --- a/src/wifi/model/frame-exchange-manager.cc +++ b/src/wifi/model/frame-exchange-manager.cc @@ -1141,10 +1141,12 @@ FrameExchangeManager::UpdateNav(Ptr psdu, const WifiTxVector& tx // (IEEE 802.11-2016 sec. 10.3.2.4) if (psdu->GetHeader(0).IsRts()) { + WifiTxVector ctsTxVector = + GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode()); Time navResetDelay = 2 * m_phy->GetSifs() + - WifiPhy::CalculateTxDuration(GetCtsSize(), txVector, m_phy->GetPhyBand()) + - m_phy->CalculatePhyPreambleAndHeaderDuration(txVector) + 2 * m_phy->GetSlot(); + WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) + + m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot(); m_navResetEvent = Simulator::Schedule(navResetDelay, &FrameExchangeManager::NavResetTimeout, this); } diff --git a/src/wifi/model/he/he-frame-exchange-manager.cc b/src/wifi/model/he/he-frame-exchange-manager.cc index 3c63bd01b..af5c84763 100644 --- a/src/wifi/model/he/he-frame-exchange-manager.cc +++ b/src/wifi/model/he/he-frame-exchange-manager.cc @@ -25,11 +25,13 @@ #include "ns3/abort.h" #include "ns3/ap-wifi-mac.h" +#include "ns3/erp-ofdm-phy.h" #include "ns3/log.h" #include "ns3/recipient-block-ack-agreement.h" #include "ns3/snr-tag.h" #include "ns3/sta-wifi-mac.h" #include "ns3/wifi-mac-queue.h" +#include "ns3/wifi-mac-trailer.h" #include #include @@ -224,22 +226,6 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar m_psduMap = std::move(psduMap); m_txParams = std::move(txParams); -#ifdef NS3_BUILD_PROFILE_DEBUG - // If protection is required, the MPDUs must be stored in some queue because - // they are not put back in a queue if the MU-RTS/CTS exchange fails - if (m_txParams.m_protection->method != WifiProtection::NONE) - { - for (const auto& psdu : psduMap) - { - for (const auto& mpdu : *PeekPointer(psdu.second)) - { - NS_ASSERT(mpdu->GetHeader().IsCtl() || !mpdu->GetHeader().HasData() || - mpdu->IsQueued()); - } - } - } -#endif - // Make sure that the acknowledgment time has been computed, so that SendMuRts() // can reuse this value. NS_ASSERT(m_txParams.m_acknowledgment); @@ -249,6 +235,30 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar CalculateAcknowledgmentTime(m_txParams.m_acknowledgment.get()); } + // in case we are sending a Trigger Frame, update the acknowledgment time so that + // the Duration/ID of the MU-RTS is correctly computed + if (!m_txParams.m_txVector.IsUlMu() && m_psduMap.size() == 1 && + m_psduMap.begin()->first == SU_STA_ID && + m_psduMap.begin()->second->GetHeader(0).IsTrigger()) + { + NS_ASSERT(m_muScheduler); + const auto& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger; + NS_ASSERT_MSG(!trigger.IsBasic() || m_txParams.m_acknowledgment->method == + WifiAcknowledgment::UL_MU_MULTI_STA_BA, + "Acknowledgment (" << m_txParams.m_acknowledgment.get() + << ") incompatible with Basic Trigger Frame"); + NS_ASSERT_MSG(!trigger.IsBsrp() || + m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE, + "Acknowledgment (" << m_txParams.m_acknowledgment.get() + << ") incompatible with BSRP Trigger Frame"); + // Add a SIFS and the TB PPDU duration to the acknowledgment time of the Trigger Frame + auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12()); + m_txParams.m_acknowledgment->acknowledgmentTime += + m_phy->GetSifs() + HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.GetUlLength(), + txVector, + m_phy->GetPhyBand()); + } + // Set QoS Ack policy for (auto& psdu : m_psduMap) { @@ -260,6 +270,10 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar NS_ABORT_MSG_IF(m_psduMap.size() > 1, "Cannot use RTS/CTS with MU PPDUs"); SendRts(m_txParams); } + else if (m_txParams.m_protection->method == WifiProtection::MU_RTS_CTS) + { + SendMuRts(m_txParams); + } else if (m_txParams.m_protection->method == WifiProtection::NONE) { SendPsduMap(); @@ -270,6 +284,136 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar } } +Time +HeFrameExchangeManager::GetMuRtsDurationId(uint32_t muRtsSize, + const WifiTxVector& muRtsTxVector, + Time txDuration, + Time response) const +{ + NS_LOG_FUNCTION(this << muRtsSize << muRtsTxVector << txDuration << response); + + if (m_edca->GetTxopLimit(m_linkId).IsZero()) + { + WifiTxVector txVector; + txVector.SetMode(GetCtsModeAfterMuRts()); + return VhtFrameExchangeManager::GetRtsDurationId(txVector, txDuration, response); + } + + // under multiple protection settings, if the TXOP limit is not null, Duration/ID + // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016). + // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 + // of 802.11-2016) + return std::max(m_edca->GetRemainingTxop(m_linkId) - + m_phy->CalculateTxDuration(muRtsSize, muRtsTxVector, m_phy->GetPhyBand()), + Seconds(0)); +} + +void +HeFrameExchangeManager::SendMuRts(const WifiTxParameters& txParams) +{ + NS_LOG_FUNCTION(this << &txParams); + WifiMacHeader hdr; + hdr.SetType(WIFI_MAC_CTL_TRIGGER); + hdr.SetAddr1(Mac48Address::GetBroadcast()); + hdr.SetAddr2(m_self); + hdr.SetDsNotTo(); + hdr.SetDsNotFrom(); + hdr.SetNoRetry(); + hdr.SetNoMoreFragments(); + + NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS); + WifiMuRtsCtsProtection* protection = + static_cast(txParams.m_protection.get()); + + NS_ASSERT(protection->muRts.IsMuRts()); + protection->muRts.SetCsRequired(true); + Ptr payload = Create(); + payload->AddHeader(protection->muRts); + + auto mpdu = Create(payload, hdr); + + NS_ASSERT(txParams.m_txDuration != Time::Min()); + mpdu->GetHeader().SetDuration( + GetMuRtsDurationId(mpdu->GetSize(), + protection->muRtsTxVector, + txParams.m_txDuration, + txParams.m_acknowledgment->acknowledgmentTime)); + + // Get the TXVECTOR used by one station to send the CTS response. This is used + // to compute the preamble duration, so it does not matter which station we choose + WifiTxVector ctsTxVector = + GetCtsTxVectorAfterMuRts(protection->muRts, protection->muRts.begin()->GetAid12()); + + // After transmitting an MU-RTS frame, the STA shall wait for a CTSTimeout interval of + // aSIFSTime + aSlotTime + aRxPHYStartDelay (Sec. 27.2.5.2 of 802.11ax D3.0). + // aRxPHYStartDelay equals the time to transmit the PHY header. + Time timeout = m_phy->CalculateTxDuration(mpdu->GetSize(), + protection->muRtsTxVector, + m_phy->GetPhyBand()) + + m_phy->GetSifs() + m_phy->GetSlot() + + m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector); + + NS_ASSERT(!m_txTimer.IsRunning()); + m_txTimer.Set(WifiTxTimer::WAIT_CTS_AFTER_MU_RTS, + timeout, + &HeFrameExchangeManager::CtsAfterMuRtsTimeout, + this, + mpdu, + protection->muRtsTxVector); + m_channelAccessManager->NotifyCtsTimeoutStartNow(timeout); + + ForwardMpduDown(mpdu, protection->muRtsTxVector); +} + +void +HeFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxVector& txVector) +{ + NS_LOG_FUNCTION(this << *muRts << txVector); + + NS_ASSERT(!m_psduMap.empty()); + // NOTE Implementation of QSRC[AC] and QLRC[AC] should be improved... + const auto& hdr = m_psduMap.cbegin()->second->GetHeader(0); + if (!hdr.GetAddr1().IsGroup()) + { + GetWifiRemoteStationManager()->ReportRtsFailed(hdr); + } + + if (!hdr.GetAddr1().IsGroup() && + !GetWifiRemoteStationManager()->NeedRetransmission(*m_psduMap.cbegin()->second->begin())) + { + NS_LOG_DEBUG("Missed CTS, discard MPDUs"); + GetWifiRemoteStationManager()->ReportFinalRtsFailed(hdr); + for (const auto& psdu : m_psduMap) + { + // Dequeue the MPDUs if they are stored in a queue + DequeuePsdu(psdu.second); + for (const auto& mpdu : *PeekPointer(psdu.second)) + { + NotifyPacketDiscarded(mpdu); + } + } + m_edca->ResetCw(m_linkId); + } + else + { + NS_LOG_DEBUG("Missed CTS, retransmit MPDUs"); + m_edca->UpdateFailedCw(m_linkId); + } + // Make the sequence numbers of the MPDUs available again if the MPDUs have never + // been transmitted, both in case the MPDUs have been discarded and in case the + // MPDUs have to be transmitted (because a new sequence number is assigned to + // MPDUs that have never been transmitted and are selected for transmission) + for (const auto& psdu : m_psduMap) + { + for (const auto& mpdu : *PeekPointer(psdu.second)) + { + ReleaseSequenceNumber(mpdu); + } + } + m_psduMap.clear(); + TransmissionFailed(); +} + Ptr HeFrameExchangeManager::GetPsduTo(Mac48Address to, const WifiPsduMap& psduMap) { @@ -516,15 +660,6 @@ HeFrameExchangeManager::SendPsduMap() acknowledgment->stationsReceivingMultiStaBa.clear(); acknowledgment->baType.m_bitmapLen.clear(); - // Add a SIFS and the TB PPDU duration to the acknowledgment time of the - // Trigger Frame, so that its Duration/ID is correctly computed - NS_ASSERT(m_muScheduler); - Time tbPpduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration( - m_muScheduler->GetUlMuInfo(m_linkId).trigger.GetUlLength(), - acknowledgment->tbPpduTxVector, - m_phy->GetPhyBand()); - acknowledgment->acknowledgmentTime += m_phy->GetSifs() + tbPpduDuration; - timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF; responseTxVector = &acknowledgment->tbPpduTxVector; m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger); @@ -551,16 +686,8 @@ HeFrameExchangeManager::SendPsduMap() m_staExpectTbPpduFrom.insert(staIt->second); } - // Add a SIFS and the TB PPDU duration to the acknowledgment time of the - // Trigger Frame, so that its Duration/ID is correctly computed - WifiNoAck* acknowledgment = static_cast(m_txParams.m_acknowledgment.get()); - txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12()); - acknowledgment->acknowledgmentTime += - m_phy->GetSifs() + HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.GetUlLength(), - txVector, - m_phy->GetPhyBand()); - timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF; + txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12()); responseTxVector = &txVector; m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger); } @@ -787,6 +914,38 @@ HeFrameExchangeManager::PrepareMuBar(const WifiTxVector& responseTxVector, return Create(bar, hdr); } +void +HeFrameExchangeManager::CalculateProtectionTime(WifiProtection* protection) const +{ + NS_LOG_FUNCTION(this << protection); + NS_ASSERT(protection != nullptr); + + if (protection->method == WifiProtection::MU_RTS_CTS) + { + WifiMuRtsCtsProtection* muRtsCtsProtection = + static_cast(protection); + + // Get the TXVECTOR used by one station to send the CTS response. This is used + // to compute the TX duration, so it does not matter which station we choose + WifiTxVector ctsTxVector = + GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts, + muRtsCtsProtection->muRts.begin()->GetAid12()); + + uint32_t muRtsSize = WifiMacHeader(WIFI_MAC_CTL_TRIGGER).GetSize() + + muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH; + muRtsCtsProtection->protectionTime = + m_phy->CalculateTxDuration(muRtsSize, + muRtsCtsProtection->muRtsTxVector, + m_phy->GetPhyBand()) + + m_phy->CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) + + 2 * m_phy->GetSifs(); + } + else + { + VhtFrameExchangeManager::CalculateProtectionTime(protection); + } +} + void HeFrameExchangeManager::CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const { @@ -950,6 +1109,50 @@ HeFrameExchangeManager::CalculateAcknowledgmentTime(WifiAcknowledgment* acknowle } } +WifiMode +HeFrameExchangeManager::GetCtsModeAfterMuRts() const +{ + // The CTS frame sent in response to an MU-RTS Trigger frame shall be carried in a non-HT or + // non-HT duplicate PPDU (see Clause 17) with a 6 Mb/s rate (Sec. 26.2.6.3 of 802.11ax-2021) + return m_phy->GetPhyBand() == WIFI_PHY_BAND_2_4GHZ ? ErpOfdmPhy::GetErpOfdmRate6Mbps() + : OfdmPhy::GetOfdmRate6Mbps(); +} + +WifiTxVector +HeFrameExchangeManager::GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader& trigger, + uint16_t staId) const +{ + NS_LOG_FUNCTION(this << trigger << staId); + + auto userInfoIt = trigger.FindUserInfoWithAid(staId); + NS_ASSERT_MSG(userInfoIt != trigger.end(), "User Info field for AID=" << staId << " not found"); + uint16_t bw = 0; + + if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65) + { + bw = 20; + } + else if (ru < 67) + { + bw = 40; + } + else if (ru == 67) + { + bw = 80; + } + else + { + NS_ASSERT(ru == 68); + bw = 160; + } + + auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts()); + // set the channel width of the CTS TXVECTOR according to the allocated RU + txVector.SetChannelWidth(bw); + + return txVector; +} + Time HeFrameExchangeManager::GetTxDuration(uint32_t ppduPayloadSize, Mac48Address receiver, @@ -1287,6 +1490,65 @@ HeFrameExchangeManager::SetTargetRssi(CtrlTriggerHeader& trigger) const } } +void +HeFrameExchangeManager::PostProcessFrame(Ptr psdu, const WifiTxVector& txVector) +{ + NS_LOG_FUNCTION(this << psdu << txVector); + + auto txVectorCopy = txVector; + + if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger()) + { + CtrlTriggerHeader trigger; + psdu->GetPayload(0)->PeekHeader(trigger); + if (trigger.IsMuRts()) + { + const WifiMacHeader& muRts = psdu->GetHeader(0); + // A station receiving an MU-RTS behaves just like as if it received an RTS. + // Determine whether the MU-RTS is addressed to this station or not and + // prepare an "equivalent" RTS frame so that we can reuse the UpdateNav() + // and SetTxopHolder() methods of the parent classes + WifiMacHeader rts; + rts.SetType(WIFI_MAC_CTL_RTS); + rts.SetDsNotFrom(); + rts.SetDsNotTo(); + rts.SetDuration(muRts.GetDuration()); + rts.SetAddr2(muRts.GetAddr2()); + if (m_staMac != nullptr && m_staMac->IsAssociated() && + muRts.GetAddr2() == m_bssid // sent by the AP this STA is associated with + && trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) != trigger.end()) + { + // the MU-RTS is addressed to this station + rts.SetAddr1(m_self); + } + else + { + rts.SetAddr1(muRts.GetAddr2()); // an address different from that of this station + } + psdu = Create(Create(), rts); + // The duration of the NAV reset timeout has to take into account that the CTS + // response is sent using the 6 Mbps data rate + txVectorCopy = + GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts()); + } + } + VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy); +} + +void +HeFrameExchangeManager::SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr, + const CtrlTriggerHeader& trigger, + double muRtsSnr) +{ + NS_LOG_FUNCTION(this << muRtsHdr << trigger << muRtsSnr); + + NS_ASSERT(m_staMac != nullptr && m_staMac->IsAssociated()); + WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId()); + ctsTxVector.SetTriggerResponding(true); + + DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr); +} + void HeFrameExchangeManager::SendMultiStaBlockAck(const WifiTxParameters& txParams, Time durationId) { @@ -1716,10 +1978,12 @@ HeFrameExchangeManager::UpdateNav(Ptr psdu, const WifiTxVector& // (IEEE 802.11-2016 sec. 10.3.2.4) if (psdu->GetHeader(0).IsRts()) { + WifiTxVector ctsTxVector = + GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode()); auto navResetDelay = 2 * m_phy->GetSifs() + - WifiPhy::CalculateTxDuration(GetCtsSize(), txVector, m_phy->GetPhyBand()) + - m_phy->CalculatePhyPreambleAndHeaderDuration(txVector) + 2 * m_phy->GetSlot(); + WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) + + m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot(); m_intraBssNavResetEvent = Simulator::Schedule(navResetDelay, &HeFrameExchangeManager::IntraBssNavResetTimeout, @@ -1813,9 +2077,20 @@ HeFrameExchangeManager::UlMuCsMediumIdle(const CtrlTriggerHeader& trigger) const "No User Info field for STA (" << m_self << ") AID=" << m_staMac->GetAssociationId()); - const auto indices = - m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(), - trigger.GetUlBandwidth()); + std::set indices; + + if (trigger.IsMuRts()) + { + auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId()); + auto bw = ctsTxVector.GetChannelWidth(); + indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw); + } + else + { + indices = + m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(), + trigger.GetUlBandwidth()); + } return !m_channelAccessManager->GetPer20MHzBusy(indices); } @@ -1927,7 +2202,7 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr mpdu, m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF && !inAmpdu) // if in A-MPDU, processing is done at the end of A-MPDU reception { - Mac48Address sender = hdr.GetAddr2(); + const auto& sender = hdr.GetAddr2(); if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end()) { @@ -1984,6 +2259,18 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr mpdu, m_channelAccessManager->NotifyCtsTimeoutResetNow(); Simulator::Schedule(m_phy->GetSifs(), &HeFrameExchangeManager::SendPsduMap, this); } + else if (hdr.IsCts() && !m_psduMap.empty() && m_txTimer.IsRunning() && + m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS) + { + NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU"); + NS_ASSERT(hdr.GetAddr1() == m_self); + + NS_LOG_DEBUG("Received a CTS frame in response to an MU-RTS"); + + m_txTimer.Cancel(); + m_channelAccessManager->NotifyCtsTimeoutResetNow(); + Simulator::Schedule(m_phy->GetSifs(), &HeFrameExchangeManager::SendPsduMap, this); + } else if (hdr.IsAck() && m_txTimer.IsRunning() && m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU) { @@ -2201,7 +2488,35 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr mpdu, uint16_t staId = m_staMac->GetAssociationId(); - if (trigger.IsMuBar()) + if (trigger.IsMuRts()) + { + Mac48Address sender = hdr.GetAddr2(); + NS_LOG_DEBUG("Received MU-RTS Trigger Frame from=" << sender); + GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector); + + // If a non-AP STA receives an MU-RTS Trigger frame, the non-AP STA shall commence + // the transmission of a CTS frame response at the SIFS time boundary after + // the end of a received PPDU when all the following conditions are met: + // - The MU-RTS Trigger frame has one of the User Info fields addressed to + // the non-AP STA (this is guaranteed if we get here) + // - The UL MU CS condition indicates that the medium is idle + // (Sec. 26.2.6.3 of 802.11ax-2021) + if (UlMuCsMediumIdle(trigger)) + { + NS_LOG_DEBUG("Schedule CTS"); + Simulator::Schedule(m_phy->GetSifs(), + &HeFrameExchangeManager::SendCtsAfterMuRts, + this, + hdr, + trigger, + rxSignalInfo.snr); + } + else + { + NS_LOG_DEBUG("Cannot schedule CTS"); + } + } + else if (trigger.IsMuBar()) { Mac48Address sender = hdr.GetAddr2(); NS_LOG_DEBUG("Received MU-BAR Trigger Frame from=" << sender); diff --git a/src/wifi/model/he/he-frame-exchange-manager.h b/src/wifi/model/he/he-frame-exchange-manager.h index 85c0d3cff..4625330de 100644 --- a/src/wifi/model/he/he-frame-exchange-manager.h +++ b/src/wifi/model/he/he-frame-exchange-manager.h @@ -66,6 +66,7 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager void SetWifiMac(const Ptr mac) override; void SetWifiPhy(const Ptr phy) override; void CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const override; + void CalculateProtectionTime(WifiProtection* protection) const override; void SetTxopHolder(Ptr psdu, const WifiTxVector& txVector) override; bool VirtualCsMediumIdle() const override; @@ -138,6 +139,7 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager const RxSignalInfo& rxSignalInfo, const WifiTxVector& txVector, const std::vector& perMpduStatus) override; + void PostProcessFrame(Ptr psdu, const WifiTxVector& txVector) override; Time GetTxDuration(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters& txParams) const override; @@ -159,6 +161,62 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager */ virtual void IntraBssNavResetTimeout(); + /** + * Compute how to set the Duration/ID field of an MU-RTS Trigger Frame to send to protect + * a frame transmitted with the given TX vector. + * + * \param muRtsSize the size of the MU-RTS Trigger Frame in bytes + * \param muRtsTxVector the TX vector used to send the MU-RTS Trigger Frame + * \param txDuration the TX duration of the data frame + * \param response the time taken by the response (acknowledgment) to the data frame + * \return the computed Duration/ID value for the MU-RTS Trigger Frame + */ + virtual Time GetMuRtsDurationId(uint32_t muRtsSize, + const WifiTxVector& muRtsTxVector, + Time txDuration, + Time response) const; + + /** + * Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU. + * + * \param txParams the TX parameters for the data frame + */ + void SendMuRts(const WifiTxParameters& txParams); + + /** + * Called when no CTS frame is received after an MU-RTS. + * + * \param muRts the MU-RTS that solicited CTS responses + * \param txVector the TXVECTOR used to transmit the MU-RTS frame + */ + virtual void CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxVector& txVector); + + /** + * Send CTS after receiving an MU-RTS. + * + * \param muRtsHdr the MAC header of the received MU-RTS + * \param trigger the MU-RTS Trigger Frame header + * \param muRtsSnr the SNR of the MU-RTS in linear scale + */ + void SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr, + const CtrlTriggerHeader& trigger, + double muRtsSnr); + + /** + * \return the mode used to transmit a CTS after an MU-RTS. + */ + WifiMode GetCtsModeAfterMuRts() const; + + /** + * Get the TXVECTOR that the station having the given station ID has to use to send a + * CTS frame after receiving an MU-RTS Trigger Frame from the AP it is associated with. + * + * \param trigger the MU-RTS Trigger Frame + * \param staId the station ID for MU + * \return the TXVECTOR to use to send a CTS frame + */ + WifiTxVector GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader& trigger, uint16_t staId) const; + /** * Send a map of PSDUs as a DL MU PPDU. * Note that both psduMap and txParams are moved to m_psduMap and