wifi: EMLSR Manager takes action when notified of received ICF

This commit is contained in:
Stefano Avallone
2023-04-05 17:58:45 +02:00
committed by Stefano Avallone
parent 4cb770cbda
commit cdabc52473
7 changed files with 197 additions and 30 deletions

View File

@@ -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

View File

@@ -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 */
};

View File

@@ -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

View File

@@ -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

View File

@@ -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()
{

View File

@@ -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 */

View File

@@ -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);