From 4c0c96eaa7b1359b5a423758efeb7e666db68c66 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Thu, 18 Jan 2024 00:14:28 +0100 Subject: [PATCH] wifi: Do not double CW if CTS missing after ICF because of EMLSR clients starting UL TXOPs --- src/wifi/model/eht/ap-emlsr-manager.h | 7 +++ .../model/eht/default-ap-emlsr-manager.cc | 6 +++ src/wifi/model/eht/default-ap-emlsr-manager.h | 1 + .../model/eht/eht-frame-exchange-manager.cc | 54 +++++++++++++++---- .../model/he/he-frame-exchange-manager.cc | 14 ++++- src/wifi/model/he/he-frame-exchange-manager.h | 11 ++++ 6 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/wifi/model/eht/ap-emlsr-manager.h b/src/wifi/model/eht/ap-emlsr-manager.h index 6af3376af..57bb119fe 100644 --- a/src/wifi/model/eht/ap-emlsr-manager.h +++ b/src/wifi/model/eht/ap-emlsr-manager.h @@ -85,6 +85,13 @@ class ApEmlsrManager : public Object const WifiTxVector& txVector, WifiPhyBand band) = 0; + /** + * \return whether the AP MLD shall double the CW upon CTS timeout after an MU-RTS in case + * all the clients solicited by the MU-RTS are EMLSR clients that have sent (or + * are sending) a frame to the AP + */ + virtual bool UpdateCwAfterFailedIcf() = 0; + protected: void DoDispose() override; diff --git a/src/wifi/model/eht/default-ap-emlsr-manager.cc b/src/wifi/model/eht/default-ap-emlsr-manager.cc index 52f193c57..4f0b1ec51 100644 --- a/src/wifi/model/eht/default-ap-emlsr-manager.cc +++ b/src/wifi/model/eht/default-ap-emlsr-manager.cc @@ -60,4 +60,10 @@ DefaultApEmlsrManager::GetDelayOnTxPsduNotForEmlsr(Ptr psdu, return WifiPhy::CalculateTxDuration(psdu, txVector, band); } +bool +DefaultApEmlsrManager::UpdateCwAfterFailedIcf() +{ + return true; +} + } // namespace ns3 diff --git a/src/wifi/model/eht/default-ap-emlsr-manager.h b/src/wifi/model/eht/default-ap-emlsr-manager.h index 1cf0bff60..2964d809e 100644 --- a/src/wifi/model/eht/default-ap-emlsr-manager.h +++ b/src/wifi/model/eht/default-ap-emlsr-manager.h @@ -45,6 +45,7 @@ class DefaultApEmlsrManager : public ApEmlsrManager Time GetDelayOnTxPsduNotForEmlsr(Ptr psdu, const WifiTxVector& txVector, WifiPhyBand band) override; + bool UpdateCwAfterFailedIcf() override; }; } // 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 077f9b8c5..33886c5ad 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -33,6 +33,8 @@ #include "ns3/wifi-net-device.h" #include "ns3/wifi-spectrum-phy-interface.h" +#include + #undef NS_LOG_APPEND_CONTEXT #define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT @@ -803,6 +805,10 @@ EhtFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxV { NS_LOG_FUNCTION(this << *muRts << txVector); + // check if all the clients solicited by the MU-RTS are EMLSR clients that have sent (or + // are sending) a frame to the AP + auto crossLinkCollision = true; + // we blocked transmissions on the other EMLSR links for the EMLSR clients we sent the ICF to. // Given that no client responded, we can unblock transmissions for a client if there is no // ongoing UL TXOP held by that client @@ -810,33 +816,61 @@ EhtFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxV { if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address)) { + crossLinkCollision = false; continue; } auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address); NS_ASSERT(mldAddress); - if (m_ongoingTxopEnd.IsPending() && m_txopHolder && - m_mac->GetMldAddress(*m_txopHolder) == mldAddress) - { - continue; - } - - std::set linkIds; + std::set linkIds; // all EMLSR links of EMLSR client for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++) { - if (linkId != m_linkId && - m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress)) + if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress)) { linkIds.insert(linkId); } } + + if (std::any_of(linkIds.cbegin(), + linkIds.cend(), + /* lambda returning true if an UL TXOP is ongoing on the given link ID */ + [=, this](uint8_t id) { + auto ehtFem = StaticCast( + m_mac->GetFrameExchangeManager(id)); + return ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder && + m_mac->GetMldAddress(ehtFem->m_txopHolder.value()) == mldAddress; + })) + { + // an UL TXOP is ongoing on one EMLSR link, do not unblock links + continue; + } + + // no UL TXOP is ongoing on any EMLSR link; if the EMLSR client is not transmitting a + // frame to the AP on any EMLSR link, then the lack of response to the MU-RTS was not + // caused by a simultaneous UL transmission + if (std::none_of(linkIds.cbegin(), + linkIds.cend(), + /* lambda returning true if an MPDU from the EMLSR client is being received + on the given link ID */ + [=, this](uint8_t id) { + auto macHdr = m_mac->GetFrameExchangeManager(id)->GetReceivedMacHdr(); + return macHdr.has_value() && + m_mac->GetMldAddress(macHdr->get().GetAddr2()) == mldAddress; + })) + { + crossLinkCollision = false; + } + + linkIds.erase(m_linkId); m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK, *mldAddress, linkIds); } - HeFrameExchangeManager::CtsAfterMuRtsTimeout(muRts, txVector); + auto updateFailedCw = + crossLinkCollision ? m_apMac->GetApEmlsrManager()->UpdateCwAfterFailedIcf() : true; + DoCtsAfterMuRtsTimeout(muRts, txVector, updateFailedCw); } void diff --git a/src/wifi/model/he/he-frame-exchange-manager.cc b/src/wifi/model/he/he-frame-exchange-manager.cc index 9c102e2b8..418c8b78e 100644 --- a/src/wifi/model/he/he-frame-exchange-manager.cc +++ b/src/wifi/model/he/he-frame-exchange-manager.cc @@ -399,6 +399,15 @@ void HeFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxVector& txVector) { NS_LOG_FUNCTION(this << *muRts << txVector); + DoCtsAfterMuRtsTimeout(muRts, txVector, true); +} + +void +HeFrameExchangeManager::DoCtsAfterMuRtsTimeout(Ptr muRts, + const WifiTxVector& txVector, + bool updateFailedCw) +{ + NS_LOG_FUNCTION(this << *muRts << txVector << updateFailedCw); if (m_psduMap.empty()) { @@ -446,7 +455,10 @@ HeFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxVe else { NS_LOG_DEBUG("Missed CTS, retransmit MPDUs"); - m_edca->UpdateFailedCw(m_linkId); + if (updateFailedCw) + { + 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 diff --git a/src/wifi/model/he/he-frame-exchange-manager.h b/src/wifi/model/he/he-frame-exchange-manager.h index 11274edf7..8215f570d 100644 --- a/src/wifi/model/he/he-frame-exchange-manager.h +++ b/src/wifi/model/he/he-frame-exchange-manager.h @@ -213,6 +213,17 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager */ virtual void CtsAfterMuRtsTimeout(Ptr muRts, const WifiTxVector& txVector); + /** + * 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 + * \param updateFailedCw whether to update CW in case of retransmission after TX failure + */ + void DoCtsAfterMuRtsTimeout(Ptr muRts, + const WifiTxVector& txVector, + bool updateFailedCw); + /** * Send CTS after receiving an MU-RTS. *