diff --git a/src/wifi/model/eht/advanced-emlsr-manager.cc b/src/wifi/model/eht/advanced-emlsr-manager.cc index 4fc550e74..65bf629b6 100644 --- a/src/wifi/model/eht/advanced-emlsr-manager.cc +++ b/src/wifi/model/eht/advanced-emlsr-manager.cc @@ -67,6 +67,32 @@ AdvancedEmlsrManager::~AdvancedEmlsrManager() NS_LOG_FUNCTION_NOARGS(); } +void +AdvancedEmlsrManager::DoDispose() +{ + NS_LOG_FUNCTION(this); + for (auto phy : GetStaMac()->GetDevice()->GetPhys()) + { + phy->TraceDisconnectWithoutContext( + "PhyRxMacHeaderEnd", + MakeCallback(&AdvancedEmlsrManager::ReceivedMacHdr, this).Bind(phy)); + } + DefaultEmlsrManager::DoDispose(); +} + +void +AdvancedEmlsrManager::DoSetWifiMac(Ptr mac) +{ + NS_LOG_FUNCTION(this << mac); + + for (auto phy : GetStaMac()->GetDevice()->GetPhys()) + { + phy->TraceConnectWithoutContext( + "PhyRxMacHeaderEnd", + MakeCallback(&AdvancedEmlsrManager::ReceivedMacHdr, this).Bind(phy)); + } +} + Time AdvancedEmlsrManager::GetDelayUntilAccessRequest(uint8_t linkId) { @@ -162,4 +188,36 @@ AdvancedEmlsrManager::GetDelayUntilAccessRequest(uint8_t linkId) return Time{0}; } +void +AdvancedEmlsrManager::ReceivedMacHdr(Ptr phy, + const WifiMacHeader& macHdr, + const WifiTxVector& txVector, + Time psduDuration) +{ + auto linkId = GetStaMac()->GetLinkForPhy(phy); + if (!linkId.has_value()) + { + return; + } + NS_LOG_FUNCTION(this << *linkId << macHdr << txVector << psduDuration.As(Time::MS)); + + auto& ongoingTxopEnd = GetEhtFem(*linkId)->GetOngoingTxopEndEvent(); + + if (m_useNotifiedMacHdr && ongoingTxopEnd.IsPending() && + macHdr.GetAddr1() != GetEhtFem(*linkId)->GetAddress() && !macHdr.GetAddr1().IsBroadcast() && + !(macHdr.IsCts() && macHdr.GetAddr1() == GetEhtFem(*linkId)->GetBssid() /* CTS-to-self */)) + { + // the EMLSR client is no longer involved in the TXOP and switching to listening mode + ongoingTxopEnd.Cancel(); + // this method is a callback connected to the PhyRxMacHeaderEnd trace source of WifiPhy + // and is called within a for loop that executes all the callbacks. The call to NotifyTxop + // below leads the main PHY to be connected back to the primary link, thus + // the ResetPhy() method of the FEM on the non-primary link is called, which disconnects + // another callback (FEM::ReceivedMacHdr) from the PhyRxMacHeaderEnd trace source of + // the main PHY, thus invalidating the list of callbacks on which the for loop iterates. + // Hence, schedule the call to NotifyTxopEnd to execute it outside such for loop. + Simulator::ScheduleNow(&AdvancedEmlsrManager::NotifyTxopEnd, this, *linkId, false, false); + } +} + } // namespace ns3 diff --git a/src/wifi/model/eht/advanced-emlsr-manager.h b/src/wifi/model/eht/advanced-emlsr-manager.h index 7c229519d..a0a2ba675 100644 --- a/src/wifi/model/eht/advanced-emlsr-manager.h +++ b/src/wifi/model/eht/advanced-emlsr-manager.h @@ -44,6 +44,24 @@ class AdvancedEmlsrManager : public DefaultEmlsrManager Time GetDelayUntilAccessRequest(uint8_t linkId) override; + protected: + void DoDispose() override; + void DoSetWifiMac(Ptr mac) override; + + /** + * Possibly take actions when notified of the MAC header of the MPDU being received by the + * given PHY. + * + * \param phy the given PHY + * \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(Ptr phy, + const WifiMacHeader& macHdr, + const WifiTxVector& txVector, + Time psduDuration); + private: bool m_useNotifiedMacHdr; //!< whether to use the information about the MAC header of //!< the MPDU being received (if notified by the PHY) diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.cc b/src/wifi/model/eht/eht-frame-exchange-manager.cc index fe6a19114..ef7c3af71 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -1163,6 +1163,12 @@ EhtFrameExchangeManager::CheckEmlsrClientStartingTxop(const WifiMacHeader& hdr, return true; } +EventId& +EhtFrameExchangeManager::GetOngoingTxopEndEvent() +{ + return m_ongoingTxopEnd; +} + void EhtFrameExchangeManager::PsduRxError(Ptr psdu) { diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.h b/src/wifi/model/eht/eht-frame-exchange-manager.h index 35f16424d..9c2473b39 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.h +++ b/src/wifi/model/eht/eht-frame-exchange-manager.h @@ -126,6 +126,12 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager */ void EmlsrSwitchToListening(const Mac48Address& address, const Time& delay); + /** + * \return a reference to the event indicating the possible end of the current TXOP (of + * which this device is not the holder) + */ + EventId& GetOngoingTxopEndEvent(); + protected: void DoDispose() override; void RxStartIndication(WifiTxVector txVector, Time psduDuration) override; diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index b9e4c8c1e..37931d8e5 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -177,6 +177,13 @@ EmlsrManager::SetWifiMac(Ptr mac) m_staMac->TraceConnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this)); m_staMac->TraceConnectWithoutContext("DroppedMpdu", MakeCallback(&EmlsrManager::TxDropped, this)); + DoSetWifiMac(mac); +} + +void +EmlsrManager::DoSetWifiMac(Ptr mac) +{ + NS_LOG_FUNCTION(this << mac); } void diff --git a/src/wifi/model/eht/emlsr-manager.h b/src/wifi/model/eht/emlsr-manager.h index c7a595db0..78dedf419 100644 --- a/src/wifi/model/eht/emlsr-manager.h +++ b/src/wifi/model/eht/emlsr-manager.h @@ -280,6 +280,13 @@ class EmlsrManager : public Object protected: void DoDispose() override; + /** + * Allow subclasses to take actions when the MAC is set. + * + * \param mac the wifi MAC + */ + virtual void DoSetWifiMac(Ptr mac); + /** * \return the MAC of the non-AP MLD managed by this EMLSR Manager. */