wifi: Add support for limited channel width capabilities of EMLSR aux PHYs
This commit is contained in:
committed by
Stefano Avallone
parent
cdabc52473
commit
ad271fddbd
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user