diff --git a/src/wifi/model/eht/advanced-ap-emlsr-manager.cc b/src/wifi/model/eht/advanced-ap-emlsr-manager.cc index 1376d5738..c0de5184b 100644 --- a/src/wifi/model/eht/advanced-ap-emlsr-manager.cc +++ b/src/wifi/model/eht/advanced-ap-emlsr-manager.cc @@ -19,7 +19,12 @@ #include "advanced-ap-emlsr-manager.h" +#include "eht-frame-exchange-manager.h" + +#include "ns3/ap-wifi-mac.h" +#include "ns3/boolean.h" #include "ns3/log.h" +#include "ns3/wifi-phy.h" namespace ns3 { @@ -31,10 +36,26 @@ NS_OBJECT_ENSURE_REGISTERED(AdvancedApEmlsrManager); TypeId AdvancedApEmlsrManager::GetTypeId() { - static TypeId tid = TypeId("ns3::AdvancedApEmlsrManager") - .SetParent() - .SetGroupName("Wifi") - .AddConstructor(); + static TypeId tid = + TypeId("ns3::AdvancedApEmlsrManager") + .SetParent() + .SetGroupName("Wifi") + .AddConstructor() + .AddAttribute("UseNotifiedMacHdr", + "Whether to use the information about the MAC header of the MPDU " + "being received, if notified by the PHY.", + BooleanValue(true), + MakeBooleanAccessor(&AdvancedApEmlsrManager::m_useNotifiedMacHdr), + MakeBooleanChecker()) + .AddAttribute( + "WaitTransDelayOnPsduRxError", + "If true, the AP MLD waits for a response timeout after a PSDU reception " + "error before starting the transition delay for the EMLSR client that " + "sent the failed PSDU. Otherwise, the AP MLD does not start the " + "transition delay timer for the EMLSR client that sent the failed PSDU.", + BooleanValue(true), + MakeBooleanAccessor(&AdvancedApEmlsrManager::m_waitTransDelayOnPsduRxError), + MakeBooleanChecker()); return tid; } @@ -48,4 +69,101 @@ AdvancedApEmlsrManager::~AdvancedApEmlsrManager() NS_LOG_FUNCTION_NOARGS(); } +void +AdvancedApEmlsrManager::DoDispose() +{ + NS_LOG_FUNCTION(this); + for (uint8_t linkId = 0; linkId < GetApMac()->GetNLinks(); linkId++) + { + auto phy = GetApMac()->GetWifiPhy(linkId); + phy->TraceDisconnectWithoutContext( + "PhyRxMacHeaderEnd", + MakeCallback(&AdvancedApEmlsrManager::ReceivedMacHdr, this).Bind(linkId)); + } + DefaultApEmlsrManager::DoDispose(); +} + +void +AdvancedApEmlsrManager::DoSetWifiMac(Ptr mac) +{ + NS_LOG_FUNCTION(this << mac); + + for (uint8_t linkId = 0; linkId < GetApMac()->GetNLinks(); linkId++) + { + auto phy = GetApMac()->GetWifiPhy(linkId); + phy->TraceConnectWithoutContext( + "PhyRxMacHeaderEnd", + MakeCallback(&AdvancedApEmlsrManager::ReceivedMacHdr, this).Bind(linkId)); + } +} + +void +AdvancedApEmlsrManager::ReceivedMacHdr(uint8_t linkId, + const WifiMacHeader& macHdr, + const WifiTxVector& txVector, + Time psduDuration) +{ + NS_LOG_FUNCTION(this << linkId << macHdr << txVector << psduDuration.As(Time::MS)); + + if (m_useNotifiedMacHdr && GetEhtFem(linkId)->CheckEmlsrClientStartingTxop(macHdr, txVector)) + { + // the AP MLD is receiving an MPDU from an EMLSR client that is starting an UL TXOP. + // CheckEmlsrClientStartingTxop has blocked transmissions to the EMLSR client on other + // links. If the reception of the PSDU fails, however, the AP MLD does not respond and + // the EMLSR client will switch to listening mode after the ack timeout. + m_blockedLinksOnMacHdrRx.insert(linkId); + } +} + +void +AdvancedApEmlsrManager::NotifyPsduRxOk(uint8_t linkId, Ptr psdu) +{ + NS_LOG_FUNCTION(this << linkId << *psdu); + m_blockedLinksOnMacHdrRx.erase(linkId); +} + +void +AdvancedApEmlsrManager::NotifyPsduRxError(uint8_t linkId, Ptr psdu) +{ + NS_LOG_FUNCTION(this << linkId << *psdu); + + if (auto it = m_blockedLinksOnMacHdrRx.find(linkId); it == m_blockedLinksOnMacHdrRx.cend()) + { + return; + } + else + { + m_blockedLinksOnMacHdrRx.erase(it); + } + + if (m_waitTransDelayOnPsduRxError) + { + auto phy = GetApMac()->GetWifiPhy(linkId); + auto delay = phy->GetSifs() + phy->GetSlot() + EMLSR_RX_PHY_START_DELAY; + GetEhtFem(linkId)->EmlsrSwitchToListening(psdu->GetAddr2(), delay); + return; + } + + // all other EMLSR links were blocked when receiving MAC header; unblock them now + auto mldAddress = + GetApMac()->GetWifiRemoteStationManager(linkId)->GetMldAddress(psdu->GetAddr2()); + if (!mldAddress.has_value()) + { + NS_LOG_DEBUG(psdu->GetAddr2() << " is not an EMLSR client"); + return; + } + + std::set linkIds; + for (uint8_t id = 0; id < GetApMac()->GetNLinks(); id++) + { + if (GetApMac()->GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*mldAddress)) + { + linkIds.insert(id); + } + } + GetApMac()->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK, + *mldAddress, + linkIds); +} + } // namespace ns3 diff --git a/src/wifi/model/eht/advanced-ap-emlsr-manager.h b/src/wifi/model/eht/advanced-ap-emlsr-manager.h index af6ff1efb..422ce611d 100644 --- a/src/wifi/model/eht/advanced-ap-emlsr-manager.h +++ b/src/wifi/model/eht/advanced-ap-emlsr-manager.h @@ -22,9 +22,18 @@ #include "default-ap-emlsr-manager.h" +#include "ns3/nstime.h" + +#include + namespace ns3 { +class ApWifiMac; +class WifiMacHeader; +class WifiPsdu; +class WifiTxVector; + /** * \ingroup wifi * @@ -41,6 +50,35 @@ class AdvancedApEmlsrManager : public DefaultApEmlsrManager AdvancedApEmlsrManager(); ~AdvancedApEmlsrManager() override; + + void NotifyPsduRxOk(uint8_t linkId, Ptr psdu) override; + void NotifyPsduRxError(uint8_t linkId, Ptr psdu) override; + + protected: + void DoDispose() override; + void DoSetWifiMac(Ptr mac) override; + + /** + * Store information about the MAC header of the MPDU being received on the given link. + * + * \param linkId the ID of the given link + * \param macHdr the MAC header of the MPDU being received + * \param txVector the TXVECTOR used to transmit the PSDU + * \param psduDuration the remaining duration of the PSDU + */ + void ReceivedMacHdr(uint8_t linkId, + const WifiMacHeader& macHdr, + const WifiTxVector& txVector, + Time psduDuration); + + private: + std::set + m_blockedLinksOnMacHdrRx; //!< links that have been blocked upon receiving a MAC header + bool m_useNotifiedMacHdr; //!< whether to use the information about the MAC header of + //!< the MPDU being received (if notified by the PHY) + bool m_waitTransDelayOnPsduRxError; //!< Whether the AP MLD waits for a response timeout after a + //!< PSDU reception error before starting the transition + //!< delay }; } // namespace ns3 diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.cc b/src/wifi/model/eht/eht-frame-exchange-manager.cc index 9786bef01..fe6a19114 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -39,9 +39,7 @@ namespace ns3 { -/// aRxPHYStartDelay value to use when waiting for a new frame in the context of EMLSR operations -/// (Sec. 35.3.17 of 802.11be D3.1) -static constexpr uint8_t RX_PHY_START_DELAY_USEC = 20; +const Time EMLSR_RX_PHY_START_DELAY = MicroSeconds(20); /** * Additional time (exceeding 20 us) to wait for a PHY-RXSTART.indication when the PHY is @@ -1364,8 +1362,7 @@ EhtFrameExchangeManager::UpdateTxopEndOnTxStart(Time txDuration, Time durationId // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS // after the end of this PPDU, hence we need to postpone the TXOP end in order to // get the PHY-RXSTART.indication - delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() + - MicroSeconds(RX_PHY_START_DELAY_USEC); + delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() + EMLSR_RX_PHY_START_DELAY; } NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S)); @@ -1418,7 +1415,7 @@ EhtFrameExchangeManager::UpdateTxopEndOnRxEnd(Time durationId) // we may send a response after a SIFS or we may receive another frame after a SIFS. // Postpone the TXOP end by considering the latter (which takes longer) - auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC); + auto delay = m_phy->GetSifs() + m_phy->GetSlot() + EMLSR_RX_PHY_START_DELAY; NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S)); m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this, m_txopHolder); diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.h b/src/wifi/model/eht/eht-frame-exchange-manager.h index f59b39d78..35f16424d 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.h +++ b/src/wifi/model/eht/eht-frame-exchange-manager.h @@ -28,6 +28,10 @@ namespace ns3 { +/// aRxPHYStartDelay value to use when waiting for a new frame in the context of EMLSR operations +/// (Sec. 35.3.17 of 802.11be D3.1) +extern const Time EMLSR_RX_PHY_START_DELAY; + class MgtEmlOmn; /**