wifi: Add support for limited channel width capabilities of EMLSR aux PHYs

This commit is contained in:
Stefano Avallone
2023-05-03 17:13:54 +02:00
committed by Stefano Avallone
parent cdabc52473
commit ad271fddbd
3 changed files with 149 additions and 14 deletions

View File

@@ -100,20 +100,19 @@ DefaultEmlsrManager::NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId)
}
// 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();
auto newAuxPhyChannel = GetChannelForAuxPhy(currLinkId);
NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << currMainPhyChannel
NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << newAuxPhyChannel
<< " to operate on link " << +currLinkId);
GetStaMac()
->GetChannelAccessManager(nextLinkId)
->NotifySwitchingEmlsrLink(auxPhy, currMainPhyChannel, currLinkId);
->NotifySwitchingEmlsrLink(auxPhy, newAuxPhyChannel, currLinkId);
void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel;
Simulator::ScheduleNow(fp, auxPhy, currMainPhyChannel);
Simulator::ScheduleNow(fp, auxPhy, newAuxPhyChannel);
}
} // namespace ns3

View File

@@ -207,12 +207,17 @@ EmlsrManager::NotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
DoNotifyMgtFrameReceived(mpdu, linkId);
if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout() &&
m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
{
// we just completed ML setup with an AP MLD that supports EMLSR and a non-empty
// set of EMLSR links have been configured, hence enable EMLSR mode on those links
SendEmlOperatingModeNotification();
// we just completed ML setup with an AP MLD that supports EMLSR
ComputeOperatingChannels();
if (m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
{
// a non-empty set of EMLSR links have been configured, hence enable EMLSR mode
// on those links
SendEmlOperatingModeNotification();
}
}
if (hdr.IsAction() && hdr.GetAddr2() == m_staMac->GetBssid(linkId))
@@ -260,16 +265,15 @@ 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);
NS_ASSERT_MSG(mainPhy != m_staMac->GetWifiPhy(linkId),
"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();
auto newMainPhyChannel = GetChannelForMainPhy(linkId);
NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel
<< " to operate on link " << +linkId);
@@ -431,7 +435,105 @@ EmlsrManager::ChangeEmlsrMode()
// Make other non-AP STAs operating on the corresponding EMLSR links transition to
// active mode or passive mode (depending on whether EMLSR mode has been enabled or disabled)
m_staMac->NotifyEmlsrModeChanged(m_emlsrLinks);
// Enforce the limit on the max channel width supported by aux PHYs
ApplyMaxChannelWidthOnAuxPhys();
NotifyEmlsrModeChanged();
}
void
EmlsrManager::ApplyMaxChannelWidthOnAuxPhys()
{
NS_LOG_FUNCTION(this);
auto currMainPhyLinkId = m_staMac->GetLinkForPhy(m_mainPhyId);
NS_ASSERT(currMainPhyLinkId);
for (const auto linkId : m_staMac->GetLinkIds())
{
auto auxPhy = m_staMac->GetWifiPhy(linkId);
auto channel = GetChannelForAuxPhy(linkId);
if (linkId == currMainPhyLinkId || !m_staMac->IsEmlsrLink(linkId) ||
auxPhy->GetOperatingChannel() == channel)
{
continue;
}
NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << channel
<< " to operate on link " << +linkId);
// We cannot simply set the new channel, because otherwise the MAC will disable
// the setup link. We need to inform the MAC (via the Channel Access Manager) that
// this channel switch must not have such a consequence. We already have a method
// for doing so, i.e., inform the MAC that the PHY is switching channel to operate
// on the "same" link.
m_staMac->GetChannelAccessManager(linkId)->NotifySwitchingEmlsrLink(auxPhy,
channel,
linkId);
void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel;
Simulator::ScheduleNow(fp, auxPhy, channel);
}
}
void
EmlsrManager::ComputeOperatingChannels()
{
NS_LOG_FUNCTION(this);
m_mainPhyChannels.clear();
m_auxPhyChannels.clear();
auto linkIds = m_staMac->GetSetupLinkIds();
for (auto linkId : linkIds)
{
const auto& channel = m_staMac->GetWifiPhy(linkId)->GetOperatingChannel();
m_mainPhyChannels.emplace(linkId, channel);
auto mainPhyChWidth = channel.GetWidth();
if (m_auxPhyMaxWidth >= mainPhyChWidth)
{
// same channel can be used by aux PHYs
m_auxPhyChannels.emplace(linkId, channel);
continue;
}
// aux PHYs will operate on a primary subchannel
auto freq = channel.GetPrimaryChannelCenterFrequency(m_auxPhyMaxWidth);
auto chIt = WifiPhyOperatingChannel::FindFirst(0,
freq,
m_auxPhyMaxWidth,
WIFI_STANDARD_UNSPECIFIED,
channel.GetPhyBand());
NS_ASSERT_MSG(chIt != WifiPhyOperatingChannel::m_frequencyChannels.end(),
"Primary" << m_auxPhyMaxWidth << " channel not found");
m_auxPhyChannels.emplace(linkId, chIt);
// find the P20 index for the channel used by the aux PHYs
auto p20Index = channel.GetPrimaryChannelIndex(20);
while (mainPhyChWidth > m_auxPhyMaxWidth)
{
mainPhyChWidth /= 2;
p20Index /= 2;
}
m_auxPhyChannels[linkId].SetPrimary20Index(p20Index);
}
}
const WifiPhyOperatingChannel&
EmlsrManager::GetChannelForMainPhy(uint8_t linkId) const
{
auto it = m_mainPhyChannels.find(linkId);
NS_ASSERT_MSG(it != m_mainPhyChannels.end(),
"Channel for main PHY on link ID " << +linkId << " not found");
return it->second;
}
const WifiPhyOperatingChannel&
EmlsrManager::GetChannelForAuxPhy(uint8_t linkId) const
{
auto it = m_auxPhyChannels.find(linkId);
NS_ASSERT_MSG(it != m_auxPhyChannels.end(),
"Channel for aux PHY on link ID " << +linkId << " not found");
return it->second;
}
} // namespace ns3

View File

@@ -25,7 +25,9 @@
#include "ns3/mgt-headers.h"
#include "ns3/object.h"
#include "ns3/sta-wifi-mac.h"
#include "ns3/wifi-phy-operating-channel.h"
#include <map>
#include <optional>
#include <set>
@@ -155,12 +157,34 @@ class EmlsrManager : public Object
*/
virtual std::optional<uint8_t> ResendNotification(Ptr<const WifiMpdu> mpdu) = 0;
/**
* \param linkId the ID of the given link
* \return the operating channel the main PHY must switch to in order to operate
* on the given link
*/
const WifiPhyOperatingChannel& GetChannelForMainPhy(uint8_t linkId) const;
/**
* \param linkId the ID of the given link
* \return the operating channel an aux PHY must switch to in order to operate
* on the given link
*/
const WifiPhyOperatingChannel& GetChannelForAuxPhy(uint8_t linkId) const;
Time m_emlsrPaddingDelay; //!< EMLSR Padding delay
Time m_emlsrTransitionDelay; //!< EMLSR Transition delay
uint8_t m_mainPhyId; //!< ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
uint16_t m_auxPhyMaxWidth; //!< max channel width (MHz) supported by aux PHYs
private:
/**
* Compute the operating channels that the main PHY and the aux PHY(s) must switch to in order
* to operate on each of the setup links. The operating channels may be different due to
* limited channel width capabilities of the aux PHY(s). This method shall be called upon
* completion of ML setup.
*/
void ComputeOperatingChannels();
/**
* Send an EML Operating Mode Notification frame.
*/
@@ -202,6 +226,12 @@ class EmlsrManager : public Object
*/
void SwitchMainPhy(uint8_t linkId);
/**
* Adjust the operating channel of all the aux PHYs to meet the constraint on the maximum
* channel width supported by aux PHYs.
*/
void ApplyMaxChannelWidthOnAuxPhys();
/**
* Notify subclass that EMLSR mode changed.
*/
@@ -227,6 +257,10 @@ class EmlsrManager : public Object
EventId m_transitionTimeoutEvent; /**< Timer started after the successful transmission of an
EML Operating Mode Notification frame */
bool m_resetCamState; //!< whether to reset the state of CAM when main PHY switches channel
std::map<uint8_t, WifiPhyOperatingChannel>
m_mainPhyChannels; //!< link ID-indexed map of operating channels for the main PHY
std::map<uint8_t, WifiPhyOperatingChannel>
m_auxPhyChannels; //!< link ID-indexed map of operating channels for the aux PHYs
};
} // namespace ns3