wifi: EMLSR Manager takes action when notified of received ICF
This commit is contained in:
committed by
Stefano Avallone
parent
4cb770cbda
commit
cdabc52473
@@ -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
|
||||
|
||||
@@ -51,6 +51,8 @@ class DefaultEmlsrManager : public EmlsrManager
|
||||
private:
|
||||
void DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> 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 */
|
||||
};
|
||||
|
||||
@@ -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> txop)
|
||||
HeFrameExchangeManager::NotifyChannelReleased(txop);
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> 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
|
||||
|
||||
@@ -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> txop) override;
|
||||
void ReceiveMpdu(Ptr<const WifiMpdu> 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
|
||||
|
||||
@@ -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<const WifiMpdu> 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()
|
||||
{
|
||||
|
||||
@@ -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<const WifiMpdu> 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<StaWifiMac> m_staMac; //!< the MAC of the managed non-AP MLD
|
||||
std::optional<Time> m_emlsrTransitionTimeout; /**< Transition timeout advertised by APs with
|
||||
EMLSR activated */
|
||||
|
||||
@@ -290,6 +290,8 @@ EmlsrOperationsTestBase::Transmit(Ptr<WifiMac> mac,
|
||||
void
|
||||
EmlsrOperationsTestBase::DoSetup()
|
||||
{
|
||||
Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(Seconds(0)));
|
||||
|
||||
RngSeedManager::SetSeed(1);
|
||||
RngSeedManager::SetRun(2);
|
||||
int64_t streamNumber = 100;
|
||||
@@ -1037,11 +1039,11 @@ class EmlsrDlTxopTest : public EmlsrOperationsTestBase
|
||||
*
|
||||
* \param psduMap the PSDU carrying BlockAck frames
|
||||
* \param txVector the TXVECTOR used to send the PPDU
|
||||
* \param linkId the ID of the given link
|
||||
* \param phyId the ID of the PHY transmitting the PSDU(s)
|
||||
*/
|
||||
void CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
const WifiTxVector& txVector,
|
||||
uint8_t linkId);
|
||||
uint8_t phyId);
|
||||
|
||||
private:
|
||||
void StartTraffic() override;
|
||||
@@ -1147,7 +1149,7 @@ EmlsrDlTxopTest::Transmit(Ptr<WifiMac> mac,
|
||||
break;
|
||||
|
||||
case WIFI_MAC_CTL_BACKRESP:
|
||||
CheckBlockAck(psduMap, txVector, linkId);
|
||||
CheckBlockAck(psduMap, txVector, phyId);
|
||||
break;
|
||||
|
||||
default:;
|
||||
@@ -1226,7 +1228,7 @@ EmlsrDlTxopTest::StartTraffic()
|
||||
|
||||
Simulator::Schedule(m_fe2to3delay + MilliSeconds(5 * (m_nEmlsrStations + 1)), [=]() {
|
||||
m_apMac->GetDevice()->GetNode()->AddApplication(
|
||||
GetApplication(DOWNLINK, id, 8 / m_nEmlsrStations, 450));
|
||||
GetApplication(DOWNLINK, id, 8 / m_nEmlsrStations, 650));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1848,31 +1850,34 @@ EmlsrDlTxopTest::CheckResults()
|
||||
// (ICF protects the EML Notification response) and two frame exchanges with data frames
|
||||
for (std::size_t i = 0; i < m_nEmlsrStations; i++)
|
||||
{
|
||||
// if the EML Notification frame disabling EMLSR mode is sent on an EMLSR link, it
|
||||
// is protected by an ICF; otherwise, it is not protected. Given that the default
|
||||
// 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_mainPhyId) == 1)
|
||||
{
|
||||
auto firstExchangeIt = frameExchanges.at(i).begin();
|
||||
// the default EMLSR Manager requests to send EML Notification frames on the link where
|
||||
// the main PHY is operating, hence this link is an EMLSR link and the EML Notification
|
||||
// frame is protected by an ICF
|
||||
auto exchangeIt = frameExchanges.at(i).cbegin();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(IsTrigger(firstExchangeIt->front()->psduMap),
|
||||
true,
|
||||
"Expected an MU-RTS TF as ICF of first frame exchange sequence");
|
||||
NS_TEST_EXPECT_MSG_EQ(firstExchangeIt->size(),
|
||||
1,
|
||||
"Expected no data frame in the first frame exchange sequence");
|
||||
auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
|
||||
NS_TEST_ASSERT_MSG_EQ(linkIdOpt.has_value(),
|
||||
true,
|
||||
"Didn't find a link on which the main PHY is operating");
|
||||
|
||||
frameExchanges.at(i).pop_front();
|
||||
}
|
||||
NS_TEST_EXPECT_MSG_EQ(IsTrigger(exchangeIt->front()->psduMap),
|
||||
true,
|
||||
"Expected an MU-RTS TF as ICF of first frame exchange sequence");
|
||||
NS_TEST_EXPECT_MSG_EQ(+exchangeIt->front()->linkId,
|
||||
+linkIdOpt.value(),
|
||||
"ICF was not sent on the expected link");
|
||||
NS_TEST_EXPECT_MSG_EQ(exchangeIt->size(),
|
||||
1,
|
||||
"Expected no data frame in the first frame exchange sequence");
|
||||
|
||||
frameExchanges.at(i).pop_front();
|
||||
|
||||
NS_TEST_EXPECT_MSG_GT_OR_EQ(frameExchanges.at(i).size(),
|
||||
2,
|
||||
"Expected at least 2 frame exchange sequences "
|
||||
<< "involving EMLSR client " << i);
|
||||
|
||||
auto firstExchangeIt = frameExchanges.at(i).begin();
|
||||
auto firstExchangeIt = frameExchanges.at(i).cbegin();
|
||||
auto secondExchangeIt = std::next(firstExchangeIt);
|
||||
|
||||
const auto firstAmpduTxEnd =
|
||||
@@ -1899,20 +1904,19 @@ EmlsrDlTxopTest::CheckResults()
|
||||
1,
|
||||
"Expected one frame only in the second frame exchange sequence");
|
||||
|
||||
if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size() ||
|
||||
m_emlsrLinks.count(m_mainPhyId) == 0)
|
||||
if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
|
||||
{
|
||||
// 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
|
||||
// all links are EMLSR links: the two QoS data frames are sent one after another on
|
||||
// the link used for sending EML OMN
|
||||
NS_TEST_EXPECT_MSG_EQ(
|
||||
+firstExchangeIt->front()->linkId,
|
||||
+m_mainPhyId,
|
||||
"First frame exchange expected to occur on link used for association");
|
||||
+linkIdOpt.value(),
|
||||
"First frame exchange expected to occur on link used to send EML OMN");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(
|
||||
+secondExchangeIt->front()->linkId,
|
||||
+m_mainPhyId,
|
||||
"Second frame exchange expected to occur on link used for association");
|
||||
+linkIdOpt.value(),
|
||||
"Second frame exchange expected to occur on link used to send EML OMN");
|
||||
|
||||
NS_TEST_EXPECT_MSG_LT(firstAmpduTxEnd,
|
||||
secondAmpduTxStart,
|
||||
@@ -2331,7 +2335,7 @@ EmlsrDlTxopTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
|
||||
void
|
||||
EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
const WifiTxVector& txVector,
|
||||
uint8_t linkId)
|
||||
uint8_t phyId)
|
||||
{
|
||||
if (m_nEmlsrStations != 2 || m_apMac->GetNLinks() != m_emlsrLinks.size() ||
|
||||
m_emlsrEnabledTime.IsZero() || Simulator::Now() < m_emlsrEnabledTime + m_fe2to3delay)
|
||||
@@ -2353,6 +2357,15 @@ EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
"Unexpected TA for BlockAck: " << taddr);
|
||||
clientId = 1;
|
||||
}
|
||||
|
||||
// find the link on which the main PHY is operating
|
||||
auto currMainPhyLinkId = m_staMacs[clientId]->GetLinkForPhy(phyId);
|
||||
NS_TEST_ASSERT_MSG_EQ(
|
||||
currMainPhyLinkId.has_value(),
|
||||
true,
|
||||
"Didn't find the link on which the PHY sending the BlockAck is operating");
|
||||
auto linkId = *currMainPhyLinkId;
|
||||
|
||||
// we need the MLD address to check the status of the container queues
|
||||
auto addr = m_apMac->GetWifiRemoteStationManager(linkId)->GetMldAddress(taddr);
|
||||
NS_TEST_ASSERT_MSG_EQ(addr.has_value(), true, "MLD address not found for " << taddr);
|
||||
|
||||
Reference in New Issue
Block a user