wifi: StaWifiMac makes use of the Association Manager

This commit is contained in:
Stefano Avallone
2022-06-12 23:37:16 +02:00
parent 384b506ed9
commit 1d8bc5ccb1
8 changed files with 177 additions and 137 deletions

View File

@@ -23,6 +23,7 @@
#include "ns3/frame-exchange-manager.h"
#include "ns3/wifi-protection-manager.h"
#include "ns3/wifi-ack-manager.h"
#include "ns3/wifi-assoc-manager.h"
#include "ns3/multi-user-scheduler.h"
#include "ns3/boolean.h"
@@ -33,6 +34,7 @@ WifiMacHelper::WifiMacHelper ()
//By default, we create an AdHoc MAC layer (without QoS).
SetType ("ns3::AdhocWifiMac");
m_assocManager.SetTypeId ("ns3::WifiDefaultAssocManager");
m_protectionManager.SetTypeId ("ns3::WifiDefaultProtectionManager");
m_ackManager.SetTypeId ("ns3::WifiDefaultAckManager");
}
@@ -98,6 +100,13 @@ WifiMacHelper::Create (Ptr<WifiNetDevice> device, WifiStandard standard) const
apMac->AggregateObject (muScheduler);
}
// create and install the Association Manager if this is a STA
if (auto staMac = DynamicCast<StaWifiMac> (mac); staMac != nullptr)
{
Ptr<WifiAssocManager> assocManager = m_assocManager.Create<WifiAssocManager> ();
staMac->SetAssocManager (assocManager);
}
return mac;
}

View File

@@ -68,6 +68,16 @@ public:
template <typename... Args>
void SetType (std::string type, Args&&... args);
/**
* Helper function used to set the Association Manager.
*
* \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
* \param type the type of Association Manager
* \param args A sequence of name-value pairs of the attributes to set.
*/
template <typename... Args>
void SetAssocManager (std::string type, Args&&... args);
/**
* Helper function used to set the Protection Manager.
*
@@ -111,6 +121,7 @@ public:
protected:
ObjectFactory m_mac; ///< MAC object factory
ObjectFactory m_assocManager; ///< Association Manager
ObjectFactory m_protectionManager; ///< Factory to create a protection manager
ObjectFactory m_ackManager; ///< Factory to create an acknowledgment manager
ObjectFactory m_muScheduler; ///< Multi-user Scheduler object factory
@@ -133,6 +144,14 @@ WifiMacHelper::SetType (std::string type, Args&&... args)
m_mac.Set (args...);
}
template <typename... Args>
void
WifiMacHelper::SetAssocManager (std::string type, Args&&... args)
{
m_assocManager.SetTypeId (type);
m_assocManager.Set (args...);
}
template <typename... Args>
void
WifiMacHelper::SetProtectionManager (std::string type, Args&&... args)

View File

@@ -32,6 +32,7 @@
#include "wifi-phy.h"
#include "mgt-headers.h"
#include "snr-tag.h"
#include "wifi-assoc-manager.h"
#include "wifi-net-device.h"
#include "ns3/ht-configuration.h"
#include "ns3/he-configuration.h"
@@ -99,8 +100,6 @@ StaWifiMac::GetTypeId (void)
StaWifiMac::StaWifiMac ()
: m_state (UNASSOCIATED),
m_aid (0),
m_waitBeaconEvent (),
m_probeRequestEvent (),
m_assocRequestEvent (),
m_beaconWatchdogEnd (Seconds (0))
{
@@ -118,6 +117,18 @@ StaWifiMac::DoInitialize (void)
StartScanning ();
}
void
StaWifiMac::DoDispose (void)
{
NS_LOG_FUNCTION (this);
if (m_assocManager)
{
m_assocManager->Dispose ();
}
m_assocManager = nullptr;
WifiMac::DoDispose ();
}
StaWifiMac::~StaWifiMac ()
{
NS_LOG_FUNCTION (this);
@@ -131,6 +142,14 @@ StaWifiMac::AssignStreams (int64_t stream)
return 1;
}
void
StaWifiMac::SetAssocManager (Ptr<WifiAssocManager> assocManager)
{
NS_LOG_FUNCTION (this << assocManager);
m_assocManager = assocManager;
m_assocManager->SetStaWifiMac (this);
}
uint16_t
StaWifiMac::GetAssociationId (void) const
{
@@ -167,6 +186,15 @@ StaWifiMac::SetWifiPhys (const std::vector<Ptr<WifiPhy>>& phys)
}
}
WifiScanParams::Channel
StaWifiMac::GetCurrentChannel (uint8_t linkId) const
{
auto phy = GetWifiPhy (linkId);
uint16_t width = phy->GetOperatingChannel ().IsOfdm () ? 20 : phy->GetChannelWidth ();
uint8_t ch = phy->GetOperatingChannel ().GetPrimaryChannelNumber (width, phy->GetStandard ());
return {ch, phy->GetPhyBand ()};
}
void
StaWifiMac::SendProbeRequest (void)
{
@@ -354,68 +382,68 @@ void
StaWifiMac::StartScanning (void)
{
NS_LOG_FUNCTION (this);
m_candidateAps.clear ();
if (m_probeRequestEvent.IsRunning ())
SetState (SCANNING);
NS_ASSERT (m_assocManager);
WifiScanParams scanParams;
scanParams.ssid = GetSsid ();
for (uint8_t linkId = 0; linkId < GetNLinks (); linkId++)
{
m_probeRequestEvent.Cancel ();
WifiScanParams::ChannelList channel {(GetWifiPhy (linkId)->HasFixedPhyBand ())
? WifiScanParams::Channel {0, GetWifiPhy (linkId)->GetPhyBand ()}
: WifiScanParams::Channel {0, WIFI_PHY_BAND_UNSPECIFIED}};
scanParams.channelList.push_back (channel);
}
if (m_waitBeaconEvent.IsRunning ())
if (m_activeProbing)
{
m_waitBeaconEvent.Cancel ();
}
if (GetActiveProbing ())
{
SendProbeRequest ();
m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
&StaWifiMac::ScanningTimeout,
this);
scanParams.type = WifiScanParams::ACTIVE;
scanParams.probeDelay = MicroSeconds (m_probeDelay->GetValue ());
scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
}
else
{
m_waitBeaconEvent = Simulator::Schedule (m_waitBeaconTimeout,
&StaWifiMac::ScanningTimeout,
this);
scanParams.type = WifiScanParams::PASSIVE;
scanParams.maxChannelTime = m_waitBeaconTimeout;
}
SetState (SCANNING);
m_assocManager->StartScanning (std::move (scanParams));
}
void
StaWifiMac::ScanningTimeout (void)
StaWifiMac::ScanningTimeout (const std::optional<ApInfo>& bestAp)
{
NS_LOG_FUNCTION (this);
if (!m_candidateAps.empty ())
{
ApInfo bestAp = m_candidateAps.front();
m_candidateAps.erase(m_candidateAps.begin ());
NS_LOG_DEBUG ("Attempting to associate with BSSID " << bestAp.m_bssid);
UpdateApInfo (bestAp.m_frame, bestAp.m_apAddr, bestAp.m_bssid, bestAp.m_linkId);
// lambda to get beacon interval from Beacon or Probe Response
auto getBeaconInterval =
[](auto&& frame)
{
using T = std::decay_t<decltype (frame)>;
if constexpr (std::is_same_v<T, MgtBeaconHeader>
|| std::is_same_v<T, MgtProbeResponseHeader>)
{
return MicroSeconds (frame.GetBeaconIntervalUs ());
}
else
{
NS_ABORT_MSG ("Unexpected frame type");
return Seconds (0);
}
};
Time beaconInterval = std::visit (getBeaconInterval, bestAp.m_frame);
Time delay = beaconInterval * m_maxMissedBeacons;
RestartBeaconWatchdog (delay);
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest (false);
}
else
if (!bestAp.has_value ())
{
NS_LOG_DEBUG ("Exhausted list of candidate AP; restart scanning");
StartScanning ();
return;
}
NS_LOG_DEBUG ("Attempting to associate with BSSID " << bestAp->m_bssid);
UpdateApInfo (bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
// lambda to get beacon interval from Beacon or Probe Response
auto getBeaconInterval =
[](auto&& frame)
{
using T = std::decay_t<decltype (frame)>;
if constexpr (std::is_same_v<T, MgtBeaconHeader> || std::is_same_v<T, MgtProbeResponseHeader>)
{
return MicroSeconds (frame.GetBeaconIntervalUs ());
}
else
{
NS_ABORT_MSG ("Unexpected frame type");
return Seconds (0);
}
};
Time beaconInterval = std::visit (getBeaconInterval, bestAp->m_frame);
Time delay = beaconInterval * m_maxMissedBeacons;
RestartBeaconWatchdog (delay);
SetState (WAIT_ASSOC_RESP);
SendAssociationRequest (false);
}
void
@@ -645,10 +673,9 @@ StaWifiMac::Receive (Ptr<WifiMacQueueItem> mpdu, uint8_t linkId)
}
else
{
// we retain this Beacon as candidate AP if the SSID matches ours and the
// supported rates fit the configured BSS membership selector
goodBeacon = ((GetSsid ().IsBroadcast () || beacon.GetSsid ().IsEqual (GetSsid ()))
&& CheckSupportedRates (beacon, linkId));
// we retain this Beacon as candidate AP if the supported rates fit the
// configured BSS membership selector
goodBeacon = CheckSupportedRates (beacon, linkId);
}
if (!goodBeacon)
@@ -663,9 +690,9 @@ StaWifiMac::Receive (Ptr<WifiMacQueueItem> mpdu, uint8_t linkId)
RestartBeaconWatchdog (delay);
UpdateApInfo (beacon, hdr->GetAddr2 (), hdr->GetAddr3 (), linkId);
}
else if (m_state == SCANNING)
else
{
NS_LOG_DEBUG ("Beacon received while scanning from " << hdr->GetAddr2 ());
NS_LOG_DEBUG ("Beacon received from " << hdr->GetAddr2 ());
SnrTag snrTag;
bool removed = copy->RemovePacketTag (snrTag);
NS_ASSERT (removed);
@@ -673,36 +700,34 @@ StaWifiMac::Receive (Ptr<WifiMacQueueItem> mpdu, uint8_t linkId)
apInfo.m_apAddr = hdr->GetAddr2 ();
apInfo.m_bssid = hdr->GetAddr3 ();
apInfo.m_snr = snrTag.Get ();
apInfo.m_frame = beacon;
apInfo.m_frame = std::move (beacon);
apInfo.m_linkId = linkId;
UpdateCandidateApList (apInfo);
apInfo.m_channel = {GetCurrentChannel (linkId)};
m_assocManager->NotifyApInfo (std::move (apInfo));
}
return;
}
else if (hdr->IsProbeResp ())
{
if (m_state == SCANNING)
NS_LOG_DEBUG ("Probe response received from " << hdr->GetAddr2 ());
MgtProbeResponseHeader probeResp;
Ptr<Packet> copy = packet->Copy ();
copy->RemoveHeader (probeResp);
if (!CheckSupportedRates (probeResp, linkId))
{
NS_LOG_DEBUG ("Probe response received while scanning from " << hdr->GetAddr2 ());
MgtProbeResponseHeader probeResp;
Ptr<Packet> copy = packet->Copy ();
copy->RemoveHeader (probeResp);
if ((!GetSsid ().IsBroadcast () && !probeResp.GetSsid ().IsEqual (GetSsid ()))
|| !CheckSupportedRates (probeResp, linkId))
{
return;
}
SnrTag snrTag;
bool removed = copy->RemovePacketTag (snrTag);
NS_ASSERT (removed);
ApInfo apInfo;
apInfo.m_apAddr = hdr->GetAddr2 ();
apInfo.m_bssid = hdr->GetAddr3 ();
apInfo.m_snr = snrTag.Get ();
apInfo.m_frame = probeResp;
apInfo.m_linkId = linkId;
UpdateCandidateApList (apInfo);
return;
}
SnrTag snrTag;
bool removed = copy->RemovePacketTag (snrTag);
NS_ASSERT (removed);
ApInfo apInfo;
apInfo.m_apAddr = hdr->GetAddr2 ();
apInfo.m_bssid = hdr->GetAddr3 ();
apInfo.m_snr = snrTag.Get ();
apInfo.m_frame = std::move (probeResp);
apInfo.m_linkId = linkId;
apInfo.m_channel = {GetCurrentChannel (linkId)};
m_assocManager->NotifyApInfo (std::move (apInfo));
return;
}
else if (hdr->IsAssocResp () || hdr->IsReassocResp ())
@@ -736,14 +761,8 @@ StaWifiMac::Receive (Ptr<WifiMacQueueItem> mpdu, uint8_t linkId)
else
{
NS_LOG_DEBUG ("association refused");
if (m_candidateAps.empty ())
{
SetState (REFUSED);
}
else
{
ScanningTimeout ();
}
SetState (REFUSED);
StartScanning ();
}
}
return;
@@ -782,32 +801,6 @@ StaWifiMac::CheckSupportedRates (std::variant<MgtBeaconHeader, MgtProbeResponseH
return std::visit (check, frame);
}
void
StaWifiMac::UpdateCandidateApList (ApInfo newApInfo)
{
NS_LOG_FUNCTION (this << newApInfo.m_bssid << newApInfo.m_apAddr << newApInfo.m_snr << newApInfo.m_frame.index () +newApInfo.m_linkId);
// Remove duplicate ApInfo entry
for (std::vector<ApInfo>::iterator i = m_candidateAps.begin(); i != m_candidateAps.end(); ++i)
{
if (newApInfo.m_bssid == (*i).m_bssid)
{
m_candidateAps.erase(i);
break;
}
}
// Insert before the entry with lower SNR
for (std::vector<ApInfo>::iterator i = m_candidateAps.begin(); i != m_candidateAps.end(); ++i)
{
if (newApInfo.m_snr > (*i).m_snr)
{
m_candidateAps.insert (i, newApInfo);
return;
}
}
// If new ApInfo is the lowest, insert at back
m_candidateAps.push_back(newApInfo);
}
void
StaWifiMac::UpdateApInfo (const MgtFrameType& frame, const Mac48Address& apAddr,
const Mac48Address& bssid, uint8_t linkId)

View File

@@ -36,6 +36,7 @@ namespace ns3 {
class SupportedRates;
class CapabilityInformation;
class RandomVariableStream;
class WifiAssocManager;
/**
@@ -168,6 +169,13 @@ public:
*/
void SetWifiPhys (const std::vector<Ptr<WifiPhy>>& phys) override;
/**
* Set the Association Manager.
*
* \param assocManager the Association Manager
*/
void SetAssocManager (Ptr<WifiAssocManager> assocManager);
/**
* Forward a probe request packet to the DCF. The standard is not clear on the correct
* queue for management frames if QoS is supported. We always use the DCF.
@@ -178,8 +186,10 @@ public:
* This method is called after wait beacon timeout or wait probe request timeout has
* occurred. This will trigger association process from beacons or probe responses
* gathered while scanning.
*
* \param bestAp the info about the best AP to associate with, if one was found
*/
void ScanningTimeout (void);
void ScanningTimeout (const std::optional<ApInfo>& bestAp);
/**
* Return whether we are associated with an AP.
@@ -260,14 +270,6 @@ private:
void UpdateApInfo (const MgtFrameType& frame, const Mac48Address& apAddr,
const Mac48Address& bssid, uint8_t linkId);
/**
* Update list of candidate AP to associate. The list should contain ApInfo sorted from
* best to worst SNR, with no duplicate.
*
* \param newApInfo the new ApInfo to be inserted
*/
void UpdateCandidateApList (ApInfo newApInfo);
/**
* Forward an association or reassociation request packet to the DCF.
* The standard is not clear on the correct queue for management frames if QoS is supported.
@@ -357,15 +359,24 @@ private:
*/
void PhyCapabilitiesChanged (void);
/**
* Get the current primary20 channel used on the given link as a
* (channel number, PHY band) pair.
*
* \param linkId the ID of the given link
* \return a (channel number, PHY band) pair
*/
WifiScanParams::Channel GetCurrentChannel (uint8_t linkId) const;
void DoInitialize (void) override;
void DoDispose (void) override;
MacState m_state; ///< MAC state
uint16_t m_aid; ///< Association AID
Ptr<WifiAssocManager> m_assocManager; ///< Association Manager
Time m_waitBeaconTimeout; ///< wait beacon timeout
Time m_probeRequestTimeout; ///< probe request timeout
Time m_assocRequestTimeout; ///< association request timeout
EventId m_waitBeaconEvent; ///< wait beacon event
EventId m_probeRequestEvent; ///< probe request event
EventId m_assocRequestEvent; ///< association request event
EventId m_beaconWatchdog; ///< beacon watchdog
Time m_beaconWatchdogEnd; ///< beacon watchdog end
@@ -373,11 +384,6 @@ private:
bool m_activeProbing; ///< active probing
Ptr<RandomVariableStream> m_probeDelay; ///< RandomVariable used to randomize the time
///< of the first Probe Response on each channel
std::vector<ApInfo> m_candidateAps; ///< list of candidate APs to associate to
// Note: std::multiset<ApInfo> might be a candidate container to implement
// this sorted list, but we are using a std::vector because we want to sort
// based on SNR but find duplicates based on BSSID, and in practice this
// candidate vector should not be too large.
TracedCallback<Mac48Address> m_assocLogger; ///< association logger
TracedCallback<Mac48Address> m_deAssocLogger; ///< disassociation logger

View File

@@ -226,7 +226,7 @@ WifiAssocManager::ScanningTimeout (void)
{
if (m_apList.empty ())
{
m_mac->ScanningTimeout (/*std::nullopt*/);
m_mac->ScanningTimeout (std::nullopt);
return;
}
@@ -234,7 +234,7 @@ WifiAssocManager::ScanningTimeout (void)
m_apListIt.erase (bestAp.m_bssid);
} while (!CanBeReturned (bestAp));
m_mac->ScanningTimeout (/*std::move (bestAp)*/);
m_mac->ScanningTimeout (std::move (bestAp));
}
} //namespace ns3

View File

@@ -436,13 +436,18 @@ WifiPrimaryChannelsTest::DoSetup (void)
void
WifiPrimaryChannelsTest::DoRun (void)
{
// schedule association requests at different times
// schedule association requests at different times. One station's SSID is
// set to the correct value before initialization, so that such a station
// starts the scanning procedure by looking for the correct SSID
Ptr<WifiNetDevice> dev;
for (uint16_t i = 0; i < m_nStationsPerBss; i++)
// association can be done in parallel over the multiple BSSes
for (uint8_t bss = 0; bss < m_nBss; bss++)
{
// association can be done in parallel over the multiple BSSes
for (uint8_t bss = 0; bss < m_nBss; bss++)
dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (0));
dev->GetMac ()->SetSsid (Ssid ("wifi-ssid-" + std::to_string (bss)));
for (uint16_t i = 1; i < m_nStationsPerBss; i++)
{
dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i));
Simulator::Schedule (i * MicroSeconds (102400), &WifiMac::SetSsid,

View File

@@ -53,6 +53,7 @@
#include "ns3/frame-exchange-manager.h"
#include "ns3/wifi-default-protection-manager.h"
#include "ns3/wifi-default-ack-manager.h"
#include "ns3/wifi-default-assoc-manager.h"
using namespace ns3;
@@ -160,6 +161,10 @@ WifiTest::CreateOne (Vector pos, Ptr<YansWifiChannel> channel)
mac->SetAddress (Mac48Address::Allocate ());
dev->SetMac (mac);
mac->ConfigureStandard (WIFI_STANDARD_80211a);
if (mac->GetTypeOfStation () == STA)
{
StaticCast<StaWifiMac> (mac)->SetAssocManager (CreateObject<WifiDefaultAssocManager> ());
}
Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager ();
Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (mac);
@@ -1801,6 +1806,7 @@ Bug2831TestCase::DoRun (void)
staMac->SetDevice (staDev);
staMac->SetAddress (Mac48Address::Allocate ());
staMac->ConfigureStandard (WIFI_STANDARD_80211ax);
StaticCast<StaWifiMac> (staMac)->SetAssocManager (CreateObject<WifiDefaultAssocManager> ());
fem = staMac->GetFrameExchangeManager ();
protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (staMac);

View File

@@ -192,14 +192,16 @@ WifiTxopTest::DoRun (void)
m_apDevices = wifi.Install (phy, mac, wifiApNode);
// schedule association requests at different times
Time init = MilliSeconds (100);
Ptr<WifiNetDevice> dev;
// schedule association requests at different times. One station's SSID is
// set to the correct value before initialization, so that such a station
// starts the scanning procedure by looking for the correct SSID
Ptr<WifiNetDevice> dev = DynamicCast<WifiNetDevice> (m_staDevices.Get (0));
dev->GetMac ()->SetSsid (Ssid ("wifi-txop-ssid"));
for (uint16_t i = 0; i < m_nStations; i++)
for (uint16_t i = 1; i < m_nStations; i++)
{
dev = DynamicCast<WifiNetDevice> (m_staDevices.Get (i));
Simulator::Schedule (init + i * MicroSeconds (102400), &WifiMac::SetSsid,
Simulator::Schedule (i * MicroSeconds (102400), &WifiMac::SetSsid,
dev->GetMac (), Ssid ("wifi-txop-ssid"));
}