diff --git a/src/wifi/model/eht/default-emlsr-manager.cc b/src/wifi/model/eht/default-emlsr-manager.cc index 7cd831c00..bf27501d8 100644 --- a/src/wifi/model/eht/default-emlsr-manager.cc +++ b/src/wifi/model/eht/default-emlsr-manager.cc @@ -20,8 +20,10 @@ #include "default-emlsr-manager.h" #include "ns3/boolean.h" +#include "ns3/channel-access-manager.h" #include "ns3/log.h" #include "ns3/wifi-mpdu.h" +#include "ns3/wifi-phy.h" namespace ns3 { @@ -87,4 +89,31 @@ DefaultEmlsrManager::NotifyEmlsrModeChanged() NS_LOG_FUNCTION(this); } +void +DefaultEmlsrManager::NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId) +{ + NS_LOG_FUNCTION(this << currLinkId << nextLinkId); + + if (!m_switchAuxPhy) + { + return; // nothing to do + } + + // switch channel on Aux PHY so that it operates on the link on which the main PHY was operating + auto mainPhy = GetStaMac()->GetWifiPhy(currLinkId); + auto auxPhy = GetStaMac()->GetWifiPhy(nextLinkId); + + auto currMainPhyChannel = mainPhy->GetOperatingChannel(); + + NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << currMainPhyChannel + << " to operate on link " << +currLinkId); + + GetStaMac() + ->GetChannelAccessManager(nextLinkId) + ->NotifySwitchingEmlsrLink(auxPhy, currMainPhyChannel, currLinkId); + + void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel; + Simulator::ScheduleNow(fp, auxPhy, currMainPhyChannel); +} + } // namespace ns3 diff --git a/src/wifi/model/eht/default-emlsr-manager.h b/src/wifi/model/eht/default-emlsr-manager.h index 216a38134..5ec1028b2 100644 --- a/src/wifi/model/eht/default-emlsr-manager.h +++ b/src/wifi/model/eht/default-emlsr-manager.h @@ -51,6 +51,8 @@ class DefaultEmlsrManager : public EmlsrManager private: void DoNotifyMgtFrameReceived(Ptr mpdu, uint8_t linkId) override; void NotifyEmlsrModeChanged() override; + void NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId) override; + 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/eht/eht-frame-exchange-manager.cc b/src/wifi/model/eht/eht-frame-exchange-manager.cc index aebd5fc46..c86fe3c00 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -23,6 +23,7 @@ #include "ns3/abort.h" #include "ns3/ap-wifi-mac.h" +#include "ns3/emlsr-manager.h" #include "ns3/log.h" #include "ns3/sta-wifi-mac.h" #include "ns3/wifi-mac-queue.h" @@ -461,4 +462,46 @@ EhtFrameExchangeManager::NotifyChannelReleased(Ptr txop) HeFrameExchangeManager::NotifyChannelReleased(txop); } +void +EhtFrameExchangeManager::ReceiveMpdu(Ptr mpdu, + RxSignalInfo rxSignalInfo, + const WifiTxVector& txVector, + bool inAmpdu) +{ + // The received MPDU is either broadcast or addressed to this station + NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self); + + const auto& hdr = mpdu->GetHeader(); + + if (hdr.IsTrigger()) + { + if (!m_staMac) + { + return; // Trigger Frames are only processed by STAs + } + + CtrlTriggerHeader trigger; + mpdu->GetPacket()->PeekHeader(trigger); + + if (hdr.GetAddr1() != m_self && + (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() || + hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with + || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end())) + { + return; // not addressed to us + } + + if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId)) + { + // this is an initial Control frame + NS_ASSERT(m_staMac->GetEmlsrManager()); + Simulator::ScheduleNow(&EmlsrManager::NotifyIcfReceived, + m_staMac->GetEmlsrManager(), + m_linkId); + } + } + + HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu); +} + } // 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 1fad02f00..6f345a740 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.h +++ b/src/wifi/model/eht/eht-frame-exchange-manager.h @@ -92,6 +92,10 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override; void SendMuRts(const WifiTxParameters& txParams) override; void NotifyChannelReleased(Ptr txop) override; + void ReceiveMpdu(Ptr mpdu, + RxSignalInfo rxSignalInfo, + const WifiTxVector& txVector, + bool inAmpdu) override; /** * This method is intended to be called when an AP MLD detects that an EMLSR client previously diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index f6874fd69..1f5464dad 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -27,6 +27,7 @@ #include "ns3/attribute-container.h" #include "ns3/log.h" #include "ns3/wifi-mpdu.h" +#include "ns3/wifi-net-device.h" namespace ns3 { @@ -232,6 +233,58 @@ EmlsrManager::NotifyMgtFrameReceived(Ptr mpdu, uint8_t linkId) } } +void +EmlsrManager::NotifyIcfReceived(uint8_t linkId) +{ + NS_LOG_FUNCTION(this << linkId); + + auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId); + auto auxPhy = m_staMac->GetWifiPhy(linkId); + + if (m_staMac->GetWifiPhy(linkId) == mainPhy) + { + // nothing to do, we received an ICF from the main PHY + return; + } + + SwitchMainPhy(linkId); + + // aux PHY received the ICF but main PHY will send the response + auto uid = auxPhy->GetPreviouslyRxPpduUid(); + mainPhy->SetPreviouslyRxPpduUid(uid); +} + +void +EmlsrManager::SwitchMainPhy(uint8_t linkId) +{ + NS_LOG_FUNCTION(this << linkId); + + auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId); + auto auxPhy = m_staMac->GetWifiPhy(linkId); + + NS_ASSERT_MSG(mainPhy != auxPhy, "Main PHY is already operating on link " << +linkId); + + // find the link on which the main PHY is operating + auto currMainPhyLinkId = m_staMac->GetLinkForPhy(mainPhy); + NS_ASSERT_MSG(currMainPhyLinkId, "Current link ID for main PHY not found"); + + auto currMainPhyChannel = mainPhy->GetOperatingChannel(); + auto newMainPhyChannel = auxPhy->GetOperatingChannel(); + + NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel + << " to operate on link " << +linkId); + + // notify the channel access manager of the upcoming channel switch(es) + m_staMac->GetChannelAccessManager(*currMainPhyLinkId) + ->NotifySwitchingEmlsrLink(mainPhy, newMainPhyChannel, linkId); + + // request the main PHY to switch channel + void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel; + Simulator::ScheduleNow(fp, mainPhy, newMainPhyChannel); + + NotifyMainPhySwitch(*currMainPhyLinkId, linkId); +} + void EmlsrManager::SendEmlOperatingModeNotification() { diff --git a/src/wifi/model/eht/emlsr-manager.h b/src/wifi/model/eht/emlsr-manager.h index 6a04bb817..9ecf1f159 100644 --- a/src/wifi/model/eht/emlsr-manager.h +++ b/src/wifi/model/eht/emlsr-manager.h @@ -20,6 +20,7 @@ #ifndef EMLSR_MANAGER_H #define EMLSR_MANAGER_H +#include "ns3/ctrl-headers.h" #include "ns3/mac48-address.h" #include "ns3/mgt-headers.h" #include "ns3/object.h" @@ -119,6 +120,13 @@ class EmlsrManager : public Object */ void NotifyMgtFrameReceived(Ptr mpdu, uint8_t linkId); + /** + * Notify the reception of an initial Control frame on the given link. + * + * \param linkId the ID of the link on which the initial Control frame was received + */ + void NotifyIcfReceived(uint8_t linkId); + protected: void DoDispose() override; @@ -187,11 +195,26 @@ class EmlsrManager : public Object */ void ChangeEmlsrMode(); + /** + * Switch channel on the Main PHY so that it operates on the given link. + * + * \param linkId the ID of the link on which the main PHY has to operate + */ + void SwitchMainPhy(uint8_t linkId); + /** * Notify subclass that EMLSR mode changed. */ virtual void NotifyEmlsrModeChanged() = 0; + /** + * Notify subclass that the main PHY is switching channel to operate on another link. + * + * \param currLinkId the ID of the link on which the main PHY is operating + * \param nextLinkId the ID of the link on which the main PHY will be operating + */ + virtual void NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId) = 0; + Ptr m_staMac; //!< the MAC of the managed non-AP MLD std::optional