From 12b376443784c6dc367adaec1e26b62077b91ba8 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Wed, 10 May 2023 18:00:03 +0200 Subject: [PATCH] wifi: (Un)block other EMLSR links when a DL TXOP starts/ends --- .../model/eht/eht-frame-exchange-manager.cc | 131 +++++++++++++++++- .../model/eht/eht-frame-exchange-manager.h | 27 ++++ src/wifi/model/eht/emlsr-manager.cc | 32 +++++ src/wifi/model/eht/emlsr-manager.h | 7 + 4 files changed, 193 insertions(+), 4 deletions(-) diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.cc b/src/wifi/model/eht/eht-frame-exchange-manager.cc index c9fa553ee..ab1b5fc18 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -67,6 +67,7 @@ EhtFrameExchangeManager::DoDispose() { NS_LOG_FUNCTION(this); m_responseFromEmlsrClients.Cancel(); + m_ongoingTxopEnd.Cancel(); HeFrameExchangeManager::DoDispose(); } @@ -85,6 +86,7 @@ EhtFrameExchangeManager::RxStartIndication(WifiTxVector txVector, Time psduDurat &EhtFrameExchangeManager::HandleMissingResponses, this); } + UpdateTxopEndOnRxStartIndication(psduDuration); } void @@ -159,14 +161,15 @@ EhtFrameExchangeManager::ForwardPsduDown(Ptr psdu, WifiTxVector& txVector.SetSigBMode(sigBMode); } + auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand()); + if (!m_apMac) { HeFrameExchangeManager::ForwardPsduDown(psdu, txVector); + UpdateTxopEndOnTxStart(txDuration); return; } - auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand()); - // check if the EMLSR clients shall switch back to listening operation at the end of this PPDU for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();) { @@ -202,14 +205,15 @@ EhtFrameExchangeManager::ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVect { NS_LOG_FUNCTION(this << psduMap << txVector); + auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand()); + if (!m_apMac) { HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector); + UpdateTxopEndOnTxStart(txDuration); return; } - auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand()); - // check if the EMLSR clients shall switch back to listening operation at the end of this PPDU for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();) { @@ -507,6 +511,34 @@ EhtFrameExchangeManager::NotifyChannelReleased(Ptr txop) HeFrameExchangeManager::NotifyChannelReleased(txop); } +void +EhtFrameExchangeManager::PostProcessFrame(Ptr psdu, const WifiTxVector& txVector) +{ + NS_LOG_FUNCTION(this << psdu << txVector); + + HeFrameExchangeManager::PostProcessFrame(psdu, txVector); + + if (!m_ongoingTxopEnd.IsRunning()) + { + // nothing to do + return; + } + + if (m_staMac) + { + if (GetEmlsrSwitchToListening(psdu, m_staMac->GetAssociationId(), m_self)) + { + // we are no longer involved in the TXOP and switching to listening mode + m_ongoingTxopEnd.Cancel(); + m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId); + } + else + { + UpdateTxopEndOnRxEnd(); + } + } +} + void EhtFrameExchangeManager::ReceiveMpdu(Ptr mpdu, RxSignalInfo rxSignalInfo, @@ -543,6 +575,12 @@ EhtFrameExchangeManager::ReceiveMpdu(Ptr mpdu, Simulator::ScheduleNow(&EmlsrManager::NotifyIcfReceived, m_staMac->GetEmlsrManager(), m_linkId); + // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a + // SIFS (we are expected to reply by sending a CTS frame) + NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S)); + m_ongoingTxopEnd = Simulator::Schedule(m_phy->GetSifs() + NanoSeconds(1), + &EhtFrameExchangeManager::TxopEnd, + this); } } @@ -568,4 +606,89 @@ EhtFrameExchangeManager::HandleMissingResponses() } } +void +EhtFrameExchangeManager::TxopEnd() +{ + NS_LOG_FUNCTION(this); + + if (m_staMac && m_staMac->IsEmlsrLink(m_linkId)) + { + m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId); + } +} + +void +EhtFrameExchangeManager::UpdateTxopEndOnTxStart(Time txDuration) +{ + NS_LOG_FUNCTION(this << txDuration.As(Time::MS)); + + if (!m_ongoingTxopEnd.IsRunning()) + { + // nothing to do + return; + } + + m_ongoingTxopEnd.Cancel(); + Time delay; + + if (m_txTimer.IsRunning()) + { + // the TX timer is running, hence we are expecting a response. Postpone the TXOP end + // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for + // the response) + delay = m_txTimer.GetDelayLeft(); + } + else + { + // the TX Timer is not running, hence no response is expected (e.g., we are + // 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); + } + + NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S)); + m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this); +} + +void +EhtFrameExchangeManager::UpdateTxopEndOnRxStartIndication(Time psduDuration) +{ + NS_LOG_FUNCTION(this << psduDuration.As(Time::MS)); + + if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive()) + { + // nothing to do + return; + } + + // postpone the TXOP end until after the reception of the PSDU is completed + m_ongoingTxopEnd.Cancel(); + + NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S)); + m_ongoingTxopEnd = + Simulator::Schedule(psduDuration + NanoSeconds(1), &EhtFrameExchangeManager::TxopEnd, this); +} + +void +EhtFrameExchangeManager::UpdateTxopEndOnRxEnd() +{ + NS_LOG_FUNCTION(this); + + if (!m_ongoingTxopEnd.IsRunning()) + { + // nothing to do + return; + } + + m_ongoingTxopEnd.Cancel(); + + // 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); + NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S)); + m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this); +} + } // namespace ns3 diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.h b/src/wifi/model/eht/eht-frame-exchange-manager.h index 4096bfe62..d6453746a 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.h +++ b/src/wifi/model/eht/eht-frame-exchange-manager.h @@ -93,6 +93,7 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override; void SendMuRts(const WifiTxParameters& txParams) override; void NotifyChannelReleased(Ptr txop) override; + void PostProcessFrame(Ptr psdu, const WifiTxVector& txVector) override; void ReceiveMpdu(Ptr mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector& txVector, @@ -116,8 +117,34 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager */ void HandleMissingResponses(); + /** + * Update the TXOP end timer when starting a frame transmission. + * + * \param txDuration the TX duration of the frame being transmitted + */ + void UpdateTxopEndOnTxStart(Time txDuration); + + /** + * Update the TXOP end timer when receiving a PHY-RXSTART.indication. + * + * \param psduDuration the TX duration of the PSDU being received + */ + void UpdateTxopEndOnRxStartIndication(Time psduDuration); + + /** + * Update the TXOP end timer when a frame reception ends. + */ + void UpdateTxopEndOnRxEnd(); + + /** + * Take actions when a TXOP (of which we are not the holder) ends. + */ + void TxopEnd(); + EventId m_responseFromEmlsrClients; ///< timer used by an AP MLD when expecting a response from ///< an EMLSR client + EventId m_ongoingTxopEnd; //!< event indicating the possible end of the current TXOP (of which + //!< we are not the holder) }; } // namespace ns3 diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index b43e69f99..6342a4abb 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -243,6 +243,17 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId) { NS_LOG_FUNCTION(this << linkId); + NS_ASSERT(m_staMac->IsEmlsrLink(linkId)); + + // block transmissions on all other EMLSR links + for (auto id : m_staMac->GetLinkIds()) + { + if (id != linkId && m_staMac->IsEmlsrLink(id)) + { + m_staMac->BlockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK); + } + } + auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId); auto auxPhy = m_staMac->GetWifiPhy(linkId); @@ -259,6 +270,27 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId) mainPhy->SetPreviouslyRxPpduUid(uid); } +void +EmlsrManager::NotifyTxopEnd(uint8_t linkId) +{ + NS_LOG_FUNCTION(this << linkId); + + if (!m_staMac->IsEmlsrLink(linkId)) + { + NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId); + return; + } + + // unblock transmissions on other EMLSR links + for (auto id : m_staMac->GetLinkIds()) + { + if (id != linkId && m_staMac->IsEmlsrLink(id)) + { + m_staMac->UnblockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK); + } + } +} + void EmlsrManager::SwitchMainPhy(uint8_t linkId) { diff --git a/src/wifi/model/eht/emlsr-manager.h b/src/wifi/model/eht/emlsr-manager.h index fb04f153a..38c462385 100644 --- a/src/wifi/model/eht/emlsr-manager.h +++ b/src/wifi/model/eht/emlsr-manager.h @@ -129,6 +129,13 @@ class EmlsrManager : public Object */ void NotifyIcfReceived(uint8_t linkId); + /** + * Notify the end of a TXOP on the given link. + * + * \param linkId the ID of the given link + */ + void NotifyTxopEnd(uint8_t linkId); + protected: void DoDispose() override;