wifi: Default association manager waits for channel switch notifications

This commit is contained in:
Stefano Avallone
2022-07-19 18:10:06 +02:00
committed by Stefano Avallone
parent 8d96d482b6
commit eca850fcef
4 changed files with 137 additions and 15 deletions

View File

@@ -1278,6 +1278,9 @@ StaWifiMac::NotifyChannelSwitching (uint8_t linkId)
{
Disassociated (linkId);
}
// notify association manager
m_assocManager->NotifyChannelSwitched (linkId);
}
std::ostream & operator << (std::ostream &os, const StaWifiMac::ApInfo& apInfo)

View File

@@ -111,6 +111,13 @@ public:
*/
virtual void NotifyApInfo (const StaWifiMac::ApInfo&& apInfo);
/**
* Notify that the given link has completed channel switching.
*
* \param linkId the ID of the given link
*/
virtual void NotifyChannelSwitched (uint8_t linkId) = 0;
/**
* Compare two ApInfo objects for the purpose of keeping a sorted list of
* ApInfo objects.

View File

@@ -24,6 +24,7 @@
#include "sta-wifi-mac.h"
#include "wifi-default-assoc-manager.h"
#include "wifi-phy.h"
#include <algorithm>
namespace ns3 {
@@ -38,6 +39,13 @@ WifiDefaultAssocManager::GetTypeId (void)
.SetParent<WifiAssocManager> ()
.AddConstructor<WifiDefaultAssocManager> ()
.SetGroupName ("Wifi")
.AddAttribute ("ChannelSwitchTimeout",
"After requesting a channel switch on a link to setup that link, "
"wait at most this amount of time. If a channel switch is not "
"notified within this amount of time, we give up setting up that link.",
TimeValue (MilliSeconds (5)),
MakeTimeAccessor (&WifiDefaultAssocManager::m_channelSwitchTimeout),
MakeTimeChecker (Seconds (0)))
;
return tid;
}
@@ -153,6 +161,7 @@ WifiDefaultAssocManager::EndScanning (void)
// iterate over all the local links and find if we can setup a link for each of them
for (const auto& linkId : localLinkIds)
{
auto phy = m_mac->GetWifiPhy (linkId);
auto apIt = apList.begin ();
while (apIt != apList.end ())
@@ -162,13 +171,30 @@ WifiDefaultAssocManager::EndScanning (void)
// we cannot setup a link with this affiliated AP if this PHY object is
// constrained to operate in the current PHY band and this affiliated AP
// is operating in a different PHY band than this PHY object
if (m_mac->GetWifiPhy (linkId)->HasFixedPhyBand ()
&& m_mac->GetWifiPhy (linkId)->GetPhyBand () != apChannel.GetPhyBand ())
if (phy->HasFixedPhyBand () && phy->GetPhyBand () != apChannel.GetPhyBand ())
{
apIt++;
continue;
}
bool needChannelSwitch = false;
if (const auto& channel = phy->GetOperatingChannel ();
channel.GetNumber () != apChannel.GetNumber ()
|| channel.GetWidth () != apChannel.GetWidth ()
|| channel.GetPhyBand () != apChannel.GetPhyBand ())
{
needChannelSwitch = true;
}
if (needChannelSwitch && phy->IsStateSwitching ())
{
// skip this affiliated AP, which is operating on a different channel
// than ours, because we are already switching channel and cannot
// schedule another channel switch to match the affiliated AP channel
apIt++;
continue;
}
// if we get here, it means we can setup a link with this affiliated AP
// set the BSSID for this link
Mac48Address bssid = rnr->get ().GetBssid (apIt->m_nbrApInfoId, apIt->m_tbttInfoFieldId);
@@ -179,15 +205,33 @@ WifiDefaultAssocManager::EndScanning (void)
m_mac->GetWifiRemoteStationManager (linkId)->SetMldAddress (bssid, mle->get ().GetMldMacAddress ());
setupLinks.push_back ({linkId, rnr->get ().GetLinkId (apIt->m_nbrApInfoId, apIt->m_tbttInfoFieldId)});
// switch this link to using the channel used by a reported AP
// TODO check if the STA only supports a narrower channel width
NS_LOG_DEBUG ("Switch link " << +linkId << " to using channel " << +apChannel.GetNumber ()
<< " in band " << apChannel.GetPhyBand () << " frequency "
<< apChannel.GetFrequency () << "MHz width " << apChannel.GetWidth () << "MHz");
WifiPhy::ChannelTuple chTuple {apChannel.GetNumber (), apChannel.GetWidth (),
apChannel.GetPhyBand (),
apChannel.GetPrimaryChannelIndex (20)};
m_mac->GetWifiPhy (linkId)->SetOperatingChannel (chTuple);
if (needChannelSwitch)
{
if (phy->IsStateSleep ())
{
// switching channel while a PHY is in sleep state fails
phy->ResumeFromSleep ();
}
// switch this link to using the channel used by a reported AP
// TODO check if the STA only supports a narrower channel width
NS_LOG_DEBUG ("Switch link " << +linkId
<< " to using channel " << +apChannel.GetNumber ()
<< " in band " << apChannel.GetPhyBand ()
<< " frequency " << apChannel.GetFrequency ()
<< "MHz width " << apChannel.GetWidth () << "MHz");
WifiPhy::ChannelTuple chTuple {apChannel.GetNumber (), apChannel.GetWidth (),
apChannel.GetPhyBand (),
apChannel.GetPrimaryChannelIndex (20)};
phy->SetOperatingChannel (chTuple);
// actual channel switching may be delayed, thus setup a channel switch timer
m_channelSwitchInfo.resize (m_mac->GetNLinks ());
m_channelSwitchInfo[linkId].timer.Cancel ();
m_channelSwitchInfo[linkId].timer = Simulator::Schedule (m_channelSwitchTimeout,
&WifiDefaultAssocManager::ChannelSwitchTimeout,
this, linkId);
m_channelSwitchInfo[linkId].apLinkAddress = bssid;
m_channelSwitchInfo[linkId].apMldAddress = mle->get ().GetMldMacAddress ();
}
// remove the affiliated AP with which we are going to setup a link and move
// to the next local linkId
@@ -196,8 +240,56 @@ WifiDefaultAssocManager::EndScanning (void)
}
}
// we are done
ScanningTimeout ();
if (std::none_of (m_channelSwitchInfo.begin (), m_channelSwitchInfo.end (),
[](auto &&info){ return info.timer.IsRunning (); }))
{
// we are done
ScanningTimeout ();
}
}
void
WifiDefaultAssocManager::NotifyChannelSwitched (uint8_t linkId)
{
NS_LOG_FUNCTION (this << +linkId);
if (m_channelSwitchInfo.size () > linkId && m_channelSwitchInfo[linkId].timer.IsRunning ())
{
// we were waiting for this notification
m_channelSwitchInfo[linkId].timer.Cancel ();
// the remote station manager has been reset after switching, hence store
// information about AP link address and AP MLD address
m_mac->GetWifiRemoteStationManager (linkId)->SetMldAddress (m_channelSwitchInfo[linkId].apLinkAddress,
m_channelSwitchInfo[linkId].apMldAddress);
if (std::none_of (m_channelSwitchInfo.begin (), m_channelSwitchInfo.end (),
[](auto &&info){ return info.timer.IsRunning (); }))
{
// we are done
ScanningTimeout ();
}
}
}
void
WifiDefaultAssocManager::ChannelSwitchTimeout (uint8_t linkId)
{
NS_LOG_FUNCTION (this << +linkId);
// we give up setting up this link
auto& bestAp = *GetSortedList ().begin ();
auto& setupLinks = GetSetupLinks (bestAp);
auto it = std::find_if (setupLinks.begin (), setupLinks.end (),
[&linkId](auto&& linkIds){ return linkIds.first == linkId; });
NS_ASSERT (it != setupLinks.end ());
setupLinks.erase (it);
if (std::none_of (m_channelSwitchInfo.begin (), m_channelSwitchInfo.end (),
[](auto &&info){ return info.timer.IsRunning (); }))
{
// we are done
ScanningTimeout ();
}
}
bool

View File

@@ -44,6 +44,7 @@ public:
WifiDefaultAssocManager ();
virtual ~WifiDefaultAssocManager ();
void NotifyChannelSwitched (uint8_t linkId) override;
bool Compare (const StaWifiMac::ApInfo& lhs, const StaWifiMac::ApInfo& rhs) const override;
protected:
@@ -60,8 +61,27 @@ protected:
private:
void DoStartScanning (void) override;
EventId m_waitBeaconEvent; ///< wait beacon event
EventId m_probeRequestEvent; ///< probe request event
/**
* Take action upon the expiration of the timer set when requesting channel
* switch on the given link.
*
* \param linkId the ID of the given link
*/
void ChannelSwitchTimeout (uint8_t linkId);
EventId m_waitBeaconEvent; ///< wait beacon event
EventId m_probeRequestEvent; ///< probe request event
Time m_channelSwitchTimeout; ///< maximum delay for channel switching
/** Channel switch info */
struct ChannelSwitchInfo
{
EventId timer; ///< timer
Mac48Address apLinkAddress; ///< AP link address
Mac48Address apMldAddress; ///< AP MLD address
};
std::vector<ChannelSwitchInfo> m_channelSwitchInfo; ///< per-link channel switch info
};
} //namespace ns3