diff --git a/src/wifi/model/eht/default-emlsr-manager.cc b/src/wifi/model/eht/default-emlsr-manager.cc index bcbb5171a..90a952791 100644 --- a/src/wifi/model/eht/default-emlsr-manager.cc +++ b/src/wifi/model/eht/default-emlsr-manager.cc @@ -130,14 +130,34 @@ DefaultEmlsrManager::DoNotifyTxopEnd(uint8_t linkId) // switch main PHY to the previous link, if needed if (m_linkIdForMainPhyAfterTxop && linkId != m_linkIdForMainPhyAfterTxop) { - auto phy = m_auxPhyToReconnect; - SwitchMainPhy(*m_linkIdForMainPhyAfterTxop, false); - // Reconnect the aux PHY to its original link - Simulator::ScheduleNow([=, this]() { + auto auxPhy = m_auxPhyToReconnect; + + // lambda to switch the main PHY back to its previous link and reconnect the aux PHY to + // its original link + auto restorePhys = [=, this]() { + SwitchMainPhy(*m_linkIdForMainPhyAfterTxop, false); // the Aux PHY is not actually switching (hence no switching delay) - GetStaMac()->NotifySwitchingEmlsrLink(phy, linkId, Seconds(0)); - }); - SetCcaEdThresholdOnLinkSwitch(phy, linkId); + GetStaMac()->NotifySwitchingEmlsrLink(auxPhy, linkId, Seconds(0)); + SetCcaEdThresholdOnLinkSwitch(auxPhy, linkId); + m_linkIdForMainPhyAfterTxop.reset(); + }; + + auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId); + + // the main PHY may be switching at the end of a TXOP when, e.g., the main PHY starts + // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS + // is not received and the UL TXOP ends before the main PHY channel switch is completed. + // In such cases, wait until the main PHY channel switch is completed before requesting + // a new channel switch. + if (!mainPhy->IsStateSwitching()) + { + restorePhys(); + } + else + { + Simulator::Schedule(mainPhy->GetDelayUntilIdle(), restorePhys); + } + return; } m_linkIdForMainPhyAfterTxop.reset(); } diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index 0067f44aa..0229668d8 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -584,13 +584,12 @@ EmlsrManager::StartMediumSyncDelayTimer(uint8_t linkId) // reset the max number of TXOP attempts it->second.msdNTxopsLeft = m_msdMaxNTxops; - if (!it->second.timer.IsRunning()) + // there are cases in which no PHY is operating on a link; e.g., the main PHY starts + // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS + // is not received and the UL TXOP ends before the main PHY channel switch is + // completed. The MSD timer is started on the link left "uncovered" by the main PHY + if (auto phy = m_staMac->GetWifiPhy(id); phy && !it->second.timer.IsRunning()) { - // set the MSD OFDM ED threshold - auto phy = m_staMac->GetWifiPhy(id); - NS_ASSERT_MSG(phy, - "Expected a PHY to be operating on link " - << +id << " after terminating a TXOP"); NS_LOG_DEBUG("Setting CCA ED threshold on link " << +id << " to " << +m_msdOfdmEdThreshold << " PHY " << phy); m_prevCcaEdThreshold[phy] = phy->GetCcaEdThreshold();