diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.cc b/src/wifi/model/eht/eht-frame-exchange-manager.cc index 9d5e3565b..5df05f7ff 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -154,6 +154,24 @@ EhtFrameExchangeManager::StartTransmission(Ptr edca, uint16_t allowedWidth NS_ASSERT_MSG(mask && !mask->test(static_cast( WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)), "StartTransmission called while EMLSR link is being used"); + + auto emlsrManager = m_staMac->GetEmlsrManager(); + + if (auto elapsed = emlsrManager->GetElapsedMediumSyncDelayTimer(m_linkId); + elapsed && emlsrManager->MediumSyncDelayNTxopsExceeded(m_linkId)) + { + edca->NotifyChannelReleased(m_linkId); + NS_LOG_DEBUG("No new TXOP attempts allowed while MediumSyncDelay is running"); + // request channel access if needed when the MediumSyncDelay timer expires + Simulator::Schedule(emlsrManager->GetMediumSyncDuration() - *elapsed, [=]() { + if (edca->GetAccessStatus(m_linkId) == Txop::NOT_REQUESTED && + edca->HasFramesToTransmit(m_linkId)) + { + m_staMac->GetChannelAccessManager(m_linkId)->RequestAccess(edca); + } + }); + return false; + } } auto started = HeFrameExchangeManager::StartTransmission(edca, allowedWidth); @@ -489,11 +507,35 @@ EhtFrameExchangeManager::GetEmlsrSwitchToListening(Ptr psdu, return true; } +void +EhtFrameExchangeManager::TransmissionSucceeded() +{ + NS_LOG_FUNCTION(this); + + if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) && + m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId)) + { + NS_LOG_DEBUG("Reset the counter of TXOP attempts allowed while " + "MediumSyncDelay is running"); + m_staMac->GetEmlsrManager()->ResetMediumSyncDelayNTxops(m_linkId); + } + + HeFrameExchangeManager::TransmissionSucceeded(); +} + void EhtFrameExchangeManager::TransmissionFailed() { NS_LOG_FUNCTION(this); + if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) && + m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId)) + { + NS_LOG_DEBUG("Decrement the remaining number of TXOP attempts allowed while " + "MediumSyncDelay is running"); + m_staMac->GetEmlsrManager()->DecrementMediumSyncDelayNTxops(m_linkId); + } + for (const auto& address : m_txTimer.GetStasExpectedToRespond()) { if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address)) @@ -509,7 +551,7 @@ EhtFrameExchangeManager::TransmissionFailed() // protected stations, hence next transmission to this client in this TXOP will be // protected by ICF NS_LOG_DEBUG("EMLSR client " << address << " did not respond, continue TXOP"); - TransmissionSucceeded(); + HeFrameExchangeManager::TransmissionSucceeded(); return; } } diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.h b/src/wifi/model/eht/eht-frame-exchange-manager.h index 20c3581b8..5a0caf1dd 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 ForwardPsduDown(Ptr psdu, WifiTxVector& txVector) override; void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override; void SendMuRts(const WifiTxParameters& txParams) override; + void TransmissionSucceeded() override; void TransmissionFailed() override; void NotifyChannelReleased(Ptr txop) override; void PreProcessFrame(Ptr psdu, const WifiTxVector& txVector) override; diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index a052faefd..2001f0058 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -621,6 +621,44 @@ EmlsrManager::MediumSyncDelayTimerExpired(uint8_t linkId) m_prevCcaEdThreshold.erase(threshIt); } +void +EmlsrManager::DecrementMediumSyncDelayNTxops(uint8_t linkId) +{ + NS_LOG_FUNCTION(this << linkId); + + const auto timerIt = m_mediumSyncDelayStatus.find(linkId); + + NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning()); + NS_ASSERT(timerIt->second.msdNTxopsLeft != 0); + + if (timerIt->second.msdNTxopsLeft) + { + --timerIt->second.msdNTxopsLeft.value(); + } +} + +void +EmlsrManager::ResetMediumSyncDelayNTxops(uint8_t linkId) +{ + NS_LOG_FUNCTION(this << linkId); + + auto timerIt = m_mediumSyncDelayStatus.find(linkId); + + NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning()); + timerIt->second.msdNTxopsLeft.reset(); +} + +bool +EmlsrManager::MediumSyncDelayNTxopsExceeded(uint8_t linkId) +{ + NS_LOG_FUNCTION(this << linkId); + + auto timerIt = m_mediumSyncDelayStatus.find(linkId); + + NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning()); + return timerIt->second.msdNTxopsLeft == 0; +} + MgtEmlOmn EmlsrManager::GetEmlOmn() { diff --git a/src/wifi/model/eht/emlsr-manager.h b/src/wifi/model/eht/emlsr-manager.h index fd5143e94..c1d0baafd 100644 --- a/src/wifi/model/eht/emlsr-manager.h +++ b/src/wifi/model/eht/emlsr-manager.h @@ -195,6 +195,35 @@ class EmlsrManager : public Object */ void CancelMediumSyncDelayTimer(uint8_t linkId); + /** + * Decrement the counter indicating the number of TXOP attempts left while the MediumSyncDelay + * timer is running. This function must not be called when the MediumSyncDelay timer is not + * running on the given link. + * + * \param linkId the ID of the link on which a new TXOP attempt may be carried out + */ + void DecrementMediumSyncDelayNTxops(uint8_t linkId); + + /** + * Reset the counter indicating the number of TXOP attempts left while the MediumSyncDelay + * timer is running, so as to remove the limit on the number of attempts that can be made + * while the MediumSyncDelay timer is running. This function is normally called when a TXOP + * attempt is successful. This function must not be called when the MediumSyncDelay timer is + * not running on the given link. + * + * \param linkId the ID of the link for which the counter of the TXOP attempts is reset + */ + void ResetMediumSyncDelayNTxops(uint8_t linkId); + + /** + * Return whether no more TXOP attempt is allowed on the given link. This function must not + * be called when the MediumSyncDelay timer is not running on the given link. + * + * \param linkId the ID of the link on which a new TXOP attempt may be carried out + * \return whether no more TXOP attempt on the given link is allowed + */ + bool MediumSyncDelayNTxopsExceeded(uint8_t linkId); + protected: void DoDispose() override;