diff --git a/src/wifi/model/eht/default-emlsr-manager.cc b/src/wifi/model/eht/default-emlsr-manager.cc index 016ef7a05..7cd831c00 100644 --- a/src/wifi/model/eht/default-emlsr-manager.cc +++ b/src/wifi/model/eht/default-emlsr-manager.cc @@ -61,27 +61,24 @@ void DefaultEmlsrManager::DoNotifyMgtFrameReceived(Ptr mpdu, uint8_t linkId) { NS_LOG_FUNCTION(this << *mpdu << linkId); - - if (mpdu->GetHeader().IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout()) - { - m_assocLinkId = linkId; - } } uint8_t DefaultEmlsrManager::GetLinkToSendEmlNotification() { NS_LOG_FUNCTION(this); - NS_ASSERT_MSG(m_assocLinkId, "No recorded link on which Assoc Response was received"); - return *m_assocLinkId; + auto linkId = GetStaMac()->GetLinkForPhy(m_mainPhyId); + NS_ASSERT_MSG(linkId, "Link on which the main PHY is operating not found"); + return *linkId; } std::optional DefaultEmlsrManager::ResendNotification(Ptr mpdu) { NS_LOG_FUNCTION(this); - NS_ASSERT_MSG(m_assocLinkId, "No recorded link on which Assoc Response was received"); - return *m_assocLinkId; + auto linkId = GetStaMac()->GetLinkForPhy(m_mainPhyId); + NS_ASSERT_MSG(linkId, "Link on which the main PHY is operating not found"); + return *linkId; } void diff --git a/src/wifi/model/eht/default-emlsr-manager.h b/src/wifi/model/eht/default-emlsr-manager.h index b5cd515f6..216a38134 100644 --- a/src/wifi/model/eht/default-emlsr-manager.h +++ b/src/wifi/model/eht/default-emlsr-manager.h @@ -51,9 +51,6 @@ class DefaultEmlsrManager : public EmlsrManager private: void DoNotifyMgtFrameReceived(Ptr mpdu, uint8_t linkId) override; void NotifyEmlsrModeChanged() override; - - std::optional m_assocLinkId; /**< ID of the link on which Association Response - was received */ bool m_switchAuxPhy; /**< whether Aux PHY should switch channel to operate on the link on which the Main PHY was operating before moving to the link of the Aux PHY */ }; diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index c1740492c..bd85ef889 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -31,6 +31,7 @@ #include "wifi-net-device.h" #include "wifi-phy.h" +#include "ns3/attribute-container.h" #include "ns3/eht-configuration.h" #include "ns3/emlsr-manager.h" #include "ns3/he-configuration.h" @@ -162,6 +163,20 @@ void StaWifiMac::DoInitialize() { NS_LOG_FUNCTION(this); + // an EMLSR client must perform ML setup by using its main PHY + if (m_assocManager && m_emlsrManager) + { + auto mainPhyId = m_emlsrManager->GetMainPhyId(); + auto linkId = GetLinkForPhy(mainPhyId); + NS_ASSERT(linkId); + m_assocManager->SetAttribute( + "AllowedLinks", + AttributeContainerValue(std::list{*linkId})); + } + if (m_emlsrManager) + { + m_emlsrManager->Initialize(); + } StartScanning(); NS_ABORT_IF(!TraceConnectWithoutContext("AckedMpdu", MakeCallback(&StaWifiMac::TxOk, this))); WifiMac::DoInitialize(); diff --git a/src/wifi/test/wifi-emlsr-test.cc b/src/wifi/test/wifi-emlsr-test.cc index 058dd52bc..93a9004c8 100644 --- a/src/wifi/test/wifi-emlsr-test.cc +++ b/src/wifi/test/wifi-emlsr-test.cc @@ -196,6 +196,7 @@ class EmlsrOperationsTestBase : public TestCase uint8_t phyId; ///< ID of the transmitting PHY }; + uint8_t m_mainPhyId{0}; //!< ID of the main PHY std::set m_linksToEnableEmlsrOn; /**< IDs of the links on which EMLSR mode has to be enabled */ std::size_t m_nEmlsrStations{1}; ///< number of stations to create that activate EMLSR @@ -336,7 +337,9 @@ EmlsrOperationsTestBase::DoSetup() BooleanValue(false)); mac.SetEmlsrManager("ns3::DefaultEmlsrManager", "EmlsrLinkSet", - AttributeContainerValue(m_linksToEnableEmlsrOn)); + AttributeContainerValue(m_linksToEnableEmlsrOn), + "MainPhyId", + UintegerValue(m_mainPhyId)); NetDeviceContainer staDevices = wifi.Install(phyHelper, mac, wifiStaNodes); @@ -611,7 +614,6 @@ class EmlNotificationExchangeTest : public EmlsrOperationsTestBase void CheckEmlsrLinks(); private: - std::optional m_assocLinkId; //!< ID of the link used to establish association std::size_t m_checkEmlsrLinksCount; /**< counter for the number of times CheckEmlsrLinks is called (should be two: when the transition timeout expires and when the EML Notification @@ -671,7 +673,7 @@ EmlNotificationExchangeTest::Transmit(Ptr mac, switch (psdu->GetHeader(0).GetType()) { case WIFI_MAC_MGT_ASSOCIATION_REQUEST: - m_assocLinkId = linkId; + NS_TEST_EXPECT_MSG_EQ(+linkId, +m_mainPhyId, "AssocReq not sent by the main PHY"); CheckEmlCapabilitiesInAssocReq(*psdu->begin(), txVector, linkId); break; @@ -816,10 +818,7 @@ EmlNotificationExchangeTest::CheckEmlNotification(Ptr psdu, Simulator::Schedule(delay, &EmlNotificationExchangeTest::CheckEmlsrLinks, this); } - NS_TEST_ASSERT_MSG_EQ(m_assocLinkId.has_value(), - true, - "No link ID indicating the link on which association was performed"); - NS_TEST_EXPECT_MSG_EQ(+m_assocLinkId.value(), + NS_TEST_EXPECT_MSG_EQ(+m_mainPhyId, +linkId, "EML Notification received on unexpected link (frame sent by non-AP MLD: " << std::boolalpha << sentbyNonApMld << ")"); @@ -1053,14 +1052,11 @@ class EmlsrDlTxopTest : public EmlsrOperationsTestBase void EnableEmlsrMode(); std::set m_emlsrLinks; /**< IDs of the links on which EMLSR mode has to be enabled */ - std::vector> - m_assocLinkId; /**< ID of the link used to establish association (vector index is the node - ID) */ - Time m_emlsrEnabledTime; //!< when EMLSR mode has been enabled on all EMLSR clients - const Time m_fe2to3delay; /**< time interval between 2nd and 3rd frame exchange sequences - after the enablement of EMLSR mode */ - std::size_t m_countQoSframes; //!< counter for QoS frames (transition delay test) - std::size_t m_countBlockAck; //!< counter for BlockAck frames (transition delay test) + Time m_emlsrEnabledTime; //!< when EMLSR mode has been enabled on all EMLSR clients + const Time m_fe2to3delay; /**< time interval between 2nd and 3rd frame exchange sequences + after the enablement of EMLSR mode */ + std::size_t m_countQoSframes; //!< counter for QoS frames (transition delay test) + std::size_t m_countBlockAck; //!< counter for BlockAck frames (transition delay test) Ptr m_errorModel; ///< error rate model to corrupt BlockAck at AP MLD }; @@ -1073,7 +1069,6 @@ EmlsrDlTxopTest::EmlsrDlTxopTest(std::size_t nEmlsrStations, : EmlsrOperationsTestBase("Check EML DL TXOP transmissions (" + std::to_string(nEmlsrStations) + "," + std::to_string(nNonEmlsrStations) + ")"), m_emlsrLinks(linksToEnableEmlsrOn), - m_assocLinkId(1 + nEmlsrStations + nNonEmlsrStations, std::nullopt), m_emlsrEnabledTime(0), m_fe2to3delay(MilliSeconds(20)), m_countQoSframes(0), @@ -1082,6 +1077,7 @@ EmlsrDlTxopTest::EmlsrDlTxopTest(std::size_t nEmlsrStations, m_nEmlsrStations = nEmlsrStations; m_nNonEmlsrStations = nNonEmlsrStations; m_linksToEnableEmlsrOn = {}; // do not enable EMLSR right after association + m_mainPhyId = 1; m_paddingDelay = paddingDelay; m_transitionDelay = transitionDelay; m_transitionTimeout = transitionTimeout; @@ -1109,9 +1105,9 @@ EmlsrDlTxopTest::Transmit(Ptr mac, { case WIFI_MAC_MGT_ASSOCIATION_REQUEST: NS_ASSERT_MSG(nodeId > 0, "APs do not send AssocReq frames"); - m_assocLinkId.at(nodeId) = linkId; if (nodeId <= m_nEmlsrStations) { + NS_TEST_EXPECT_MSG_EQ(+linkId, +m_mainPhyId, "AssocReq not sent by the main PHY"); // this AssocReq is being sent by an EMLSR client. The other EMLSR links should be // in powersave mode after association; we let the non-EMLSR links transition to // active mode (by sending data null frames) after association @@ -1366,15 +1362,13 @@ EmlsrDlTxopTest::CheckResults() auto setupLinks = m_staMacs[i]->GetSetupLinkIds(); if (i < m_nEmlsrStations && std::none_of(setupLinks.begin(), setupLinks.end(), [&](auto&& linkId) { - return linkId != *m_assocLinkId[i + 1] && m_emlsrLinks.count(linkId) == 0; + return linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 0; })) { NS_TEST_EXPECT_MSG_EQ(linkIds.size(), 1, "Expected both A-MPDUs to be sent on the same link"); - NS_TEST_EXPECT_MSG_EQ(*linkIds.begin(), - *m_assocLinkId[i + 1], - "A-MPDUs sent on incorrect link"); + NS_TEST_EXPECT_MSG_EQ(*linkIds.begin(), +m_mainPhyId, "A-MPDUs sent on incorrect link"); NS_TEST_EXPECT_MSG_LT(firstAmpduTxEnd, secondAmpduTxStart, "A-MPDUs are not sent one after another"); @@ -1859,7 +1853,7 @@ EmlsrDlTxopTest::CheckResults() // EMLSR Manager sends EML Notification frames on the link used to establish association, // ICF is sent to protect the EML Notification frame if the link used to establish // association is an EMLSR link - if (m_emlsrLinks.count(*m_assocLinkId.at(i + 1)) == 1) + if (m_emlsrLinks.count(m_mainPhyId) == 1) { auto firstExchangeIt = frameExchanges.at(i).begin(); @@ -1906,18 +1900,18 @@ EmlsrDlTxopTest::CheckResults() "Expected one frame only in the second frame exchange sequence"); if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size() || - m_emlsrLinks.count(*m_assocLinkId.at(i + 1)) == 0) + m_emlsrLinks.count(m_mainPhyId) == 0) { // all links are EMLSR links or the non-EMLSR link is the link used for association: // the two QoS data frames are sent one after another on the link used for association NS_TEST_EXPECT_MSG_EQ( +firstExchangeIt->front()->linkId, - +(*m_assocLinkId.at(i + 1)), + +m_mainPhyId, "First frame exchange expected to occur on link used for association"); NS_TEST_EXPECT_MSG_EQ( +secondExchangeIt->front()->linkId, - +(*m_assocLinkId.at(i + 1)), + +m_mainPhyId, "Second frame exchange expected to occur on link used for association"); NS_TEST_EXPECT_MSG_LT(firstAmpduTxEnd, @@ -1957,8 +1951,8 @@ EmlsrDlTxopTest::CheckPmModeAfterAssociation(const Mac48Address& address) // transitioned to active mode instead for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++) { - bool psModeExpected = *staId < m_nEmlsrStations && linkId != m_assocLinkId.at(*staId + 1) && - m_emlsrLinks.count(linkId) == 1; + bool psModeExpected = + *staId < m_nEmlsrStations && linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 1; auto addr = m_staMacs.at(*staId)->GetAddress(); auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr); NS_TEST_EXPECT_MSG_EQ(psMode, @@ -2530,10 +2524,8 @@ WifiEmlsrTestSuite::WifiEmlsrTestSuite() AddTestCase(new EmlNotificationExchangeTest({1, 2}, MicroSeconds(2048)), TestCase::QUICK); AddTestCase(new EmlNotificationExchangeTest({0, 1, 2, 3}, MicroSeconds(0)), TestCase::QUICK); AddTestCase(new EmlNotificationExchangeTest({0, 1, 2, 3}, MicroSeconds(2048)), TestCase::QUICK); - for (const auto& emlsrLinks : {std::set{0, 1, 2}, - std::set{1, 2}, - std::set{0, 2}, - std::set{0, 1}}) + for (const auto& emlsrLinks : + {std::set{0, 1, 2}, std::set{1, 2}, std::set{0, 1}}) { AddTestCase(new EmlsrDlTxopTest(1, 0,