From 384b506ed91e47124ac319c94ea065bb265660ca Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Sun, 12 Jun 2022 15:51:12 +0200 Subject: [PATCH] wifi: Add Association Manager base class and default subclass --- src/wifi/CMakeLists.txt | 4 + src/wifi/helper/wifi-helper.cc | 2 + src/wifi/model/wifi-assoc-manager.cc | 240 +++++++++++++++++++ src/wifi/model/wifi-assoc-manager.h | 185 ++++++++++++++ src/wifi/model/wifi-default-assoc-manager.cc | 114 +++++++++ src/wifi/model/wifi-default-assoc-manager.h | 63 +++++ 6 files changed, 608 insertions(+) create mode 100644 src/wifi/model/wifi-assoc-manager.cc create mode 100644 src/wifi/model/wifi-assoc-manager.h create mode 100644 src/wifi/model/wifi-default-assoc-manager.cc create mode 100644 src/wifi/model/wifi-default-assoc-manager.h diff --git a/src/wifi/CMakeLists.txt b/src/wifi/CMakeLists.txt index 5bba59df4..9f55feaa7 100644 --- a/src/wifi/CMakeLists.txt +++ b/src/wifi/CMakeLists.txt @@ -111,7 +111,9 @@ set(source_files model/vht/vht-ppdu.cc model/wifi-ack-manager.cc model/wifi-acknowledgment.cc + model/wifi-assoc-manager.cc model/wifi-default-ack-manager.cc + model/wifi-default-assoc-manager.cc model/wifi-default-protection-manager.cc model/wifi-information-element-vector.cc model/wifi-information-element.cc @@ -252,7 +254,9 @@ set(header_files model/vht/vht-ppdu.h model/wifi-ack-manager.h model/wifi-acknowledgment.h + model/wifi-assoc-manager.h model/wifi-default-ack-manager.h + model/wifi-default-assoc-manager.h model/wifi-default-protection-manager.h model/wifi-information-element-vector.h model/wifi-information-element.h diff --git a/src/wifi/helper/wifi-helper.cc b/src/wifi/helper/wifi-helper.cc index 5f168670e..348d3bdea 100644 --- a/src/wifi/helper/wifi-helper.cc +++ b/src/wifi/helper/wifi-helper.cc @@ -921,7 +921,9 @@ WifiHelper::EnableLogComponents (void) LogComponentEnable ("VhtPhy", LOG_LEVEL_ALL); LogComponentEnable ("VhtPpdu", LOG_LEVEL_ALL); LogComponentEnable ("WifiAckManager", LOG_LEVEL_ALL); + LogComponentEnable ("WifiAssocManager", LOG_LEVEL_ALL); LogComponentEnable ("WifiDefaultAckManager", LOG_LEVEL_ALL); + LogComponentEnable ("WifiDefaultAssocManager", LOG_LEVEL_ALL); LogComponentEnable ("WifiDefaultProtectionManager", LOG_LEVEL_ALL); LogComponentEnable ("WifiMac", LOG_LEVEL_ALL); LogComponentEnable ("WifiMacQueue", LOG_LEVEL_ALL); diff --git a/src/wifi/model/wifi-assoc-manager.cc b/src/wifi/model/wifi-assoc-manager.cc new file mode 100644 index 000000000..ea404728e --- /dev/null +++ b/src/wifi/model/wifi-assoc-manager.cc @@ -0,0 +1,240 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#include +#include "ns3/log.h" +#include "sta-wifi-mac.h" +#include "wifi-assoc-manager.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("WifiAssocManager"); + +NS_OBJECT_ENSURE_REGISTERED (WifiAssocManager); + +WifiAssocManager::ApInfoCompare::ApInfoCompare (const WifiAssocManager& manager) + : m_manager (manager) +{ +} + +bool +WifiAssocManager::ApInfoCompare::operator() (const StaWifiMac::ApInfo& lhs, + const StaWifiMac::ApInfo& rhs) const +{ + NS_ASSERT_MSG (lhs.m_bssid != rhs.m_bssid, + "Comparing two ApInfo objects with the same BSSID: " << lhs.m_bssid); + + bool lhsBefore = m_manager.Compare (lhs, rhs); + if (lhsBefore) + { + return true; + } + + // the Compare method implemented by subclass may be such that the two ApInfo objects + // compare equal; in such a case, use the BSSID as tie breaker + bool rhsBefore = m_manager.Compare (rhs, lhs); + if (rhsBefore) + { + return false; + } + + WifiAddressHash hash; + return hash (lhs.m_bssid) > hash (rhs.m_bssid); +} + +TypeId +WifiAssocManager::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WifiAssocManager") + .SetParent () + .SetGroupName ("Wifi") + ; + return tid; +} + +WifiAssocManager::WifiAssocManager () + : m_scanParams (), // zero-initialization + m_apList (ApInfoCompare (*this)) +{ +} + +WifiAssocManager::~WifiAssocManager () +{ + NS_LOG_FUNCTION (this); +} + +void +WifiAssocManager::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + m_mac = nullptr; +} + +void +WifiAssocManager::SetStaWifiMac (Ptr mac) +{ + NS_LOG_FUNCTION (this << mac); + m_mac = mac; +} + +const WifiAssocManager::SortedList& +WifiAssocManager::GetSortedList (void) const +{ + return m_apList; +} + +const WifiScanParams& +WifiAssocManager::GetScanParams (void) const +{ + return m_scanParams; +} + +bool +WifiAssocManager::MatchScanParams (const StaWifiMac::ApInfo& apInfo) const +{ + NS_LOG_FUNCTION (this); + + if (!m_scanParams.ssid.IsBroadcast ()) + { + // we need to check if AP's advertised SSID matches the requested SSID + Ssid apSsid; + if (auto beacon = std::get_if (&apInfo.m_frame); beacon) + { + apSsid = beacon->GetSsid (); + } + else + { + auto probeResp = std::get_if (&apInfo.m_frame); + NS_ASSERT (probeResp); + apSsid = probeResp->GetSsid (); + } + if (!apSsid.IsEqual (m_scanParams.ssid)) + { + NS_LOG_DEBUG ("AP " << apInfo.m_bssid << " does not advertise our SSID " + << apSsid << " " << m_scanParams.ssid); + return false; + } + } + + // we need to check if the AP is operating on a requested channel + auto channelMatch = + [&apInfo](auto&& channel) + { + if (channel.number != 0 && channel.number != apInfo.m_channel.number) + { + return false; + } + if (channel.band != WIFI_PHY_BAND_UNSPECIFIED && channel.band != apInfo.m_channel.band) + { + return false; + } + return true; + }; + + NS_ASSERT (apInfo.m_linkId < m_scanParams.channelList.size ()); + if (std::find_if (m_scanParams.channelList[apInfo.m_linkId].cbegin (), + m_scanParams.channelList[apInfo.m_linkId].cend (), + channelMatch) + == m_scanParams.channelList[apInfo.m_linkId].cend ()) + { + NS_LOG_DEBUG ("AP " << apInfo.m_bssid << " is not operating on a requested channel"); + return false; + } + + return true; +} + +void +WifiAssocManager::StartScanning (WifiScanParams&& scanParams) +{ + NS_LOG_FUNCTION (this); + m_scanParams = std::move (scanParams); + + // remove stored AP information not matching the scanning parameters + for (auto ap = m_apList.begin (); ap != m_apList.end (); ) + { + if (!MatchScanParams (*ap)) + { + // remove AP info from list + m_apListIt.erase (ap->m_bssid); + ap = m_apList.erase (ap); + } + else + { + ++ap; + } + } + + DoStartScanning (); +} + +void +WifiAssocManager::NotifyApInfo (const StaWifiMac::ApInfo&& apInfo) +{ + NS_LOG_FUNCTION (this << apInfo.m_apAddr << apInfo.m_bssid << +apInfo.m_linkId); + + if (!CanBeInserted (apInfo) || !MatchScanParams (apInfo)) + { + return; + } + + // check if an ApInfo object with the same BSSID is already present in the + // sorted list of ApInfo objects. This is done by trying to insert the BSSID + // in the hash table (insertion fails if the BSSID is already present) + auto [hashIt, hashInserted] = m_apListIt.insert ({apInfo.m_bssid, {}}); + if (!hashInserted) + { + // an element with the searched BSSID is already present in the hash table. + // Remove the corresponding ApInfo object from the sorted list. + m_apList.erase (hashIt->second); + } + // insert the ApInfo object + auto [listIt, listInserted] = m_apList.insert (std::move (apInfo)); + // update the hash table entry + NS_ASSERT_MSG (listInserted, + "An entry (" << listIt->m_apAddr << ", " << listIt->m_bssid << ", " + << +listIt->m_linkId << ") prevented insertion of given ApInfo object"); + hashIt->second = listIt; +} + +void +WifiAssocManager::ScanningTimeout (void) +{ + NS_LOG_FUNCTION (this); + + StaWifiMac::ApInfo bestAp; + + do + { + if (m_apList.empty ()) + { + m_mac->ScanningTimeout (/*std::nullopt*/); + return; + } + + bestAp = std::move (m_apList.extract (m_apList.begin ()).value ()); + m_apListIt.erase (bestAp.m_bssid); + } while (!CanBeReturned (bestAp)); + + m_mac->ScanningTimeout (/*std::move (bestAp)*/); +} + +} //namespace ns3 diff --git a/src/wifi/model/wifi-assoc-manager.h b/src/wifi/model/wifi-assoc-manager.h new file mode 100644 index 000000000..40a219988 --- /dev/null +++ b/src/wifi/model/wifi-assoc-manager.h @@ -0,0 +1,185 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#ifndef WIFI_ASSOC_MANAGER_H +#define WIFI_ASSOC_MANAGER_H + +#include "qos-utils.h" +#include "sta-wifi-mac.h" +#include +#include + +namespace ns3 { + +/** + * \ingroup wifi + * + * Abstract base class for the Association Manager, which manages + * scanning and association for single link devices and ML discovery + * and setup for multi-link devices. + */ +class WifiAssocManager : public Object +{ + /** + * Struct providing a function call operator to compare two ApInfo objects. + * This struct is used as the Compare template type parameter of the set of + * ApInfo objects maintained by the Association Manager. + */ + struct ApInfoCompare + { + /** + * Constructor. + * + * \param manager a pointer to the Association Manager + */ + ApInfoCompare (const WifiAssocManager& manager); + /** + * Function call operator. Calls the Compare method of the Association Manager. + * + * \param lhs left hand side ApInfo object + * \param rhs right hand side ApInfo object + * \return true if the left hand side ApInfo object should be placed before the + * right hand side ApInfo object in the sorted list maintained by the + * Association Manager, false otherwise + */ + bool operator()(const StaWifiMac::ApInfo& lhs, const StaWifiMac::ApInfo& rhs) const; + + private: + const WifiAssocManager& m_manager; ///< Association Manager + }; + +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + virtual ~WifiAssocManager (); + + /** + * Set the pointer to the STA wifi MAC. + * + * \param mac the pointer to the STA wifi MAC + */ + void SetStaWifiMac (Ptr mac); + + /** + * Request the Association Manager to start a scanning procedure according to + * the given scanning parameters. At subclass' discretion, stored information + * about APs matching the given scanning parameters may be used and scanning + * not performed. + * + * \param scanParams the scanning parameters + */ + void StartScanning (WifiScanParams&& scanParams); + + /** + * STA wifi MAC received a Beacon frame or Probe Response frame while scanning + * and notifies us the AP information contained in the received frame. + * + * Note that the given ApInfo object is moved to the sorted list of ApInfo objects. + * + * \param apInfo the AP information contained in the received frame + */ + virtual void NotifyApInfo (const StaWifiMac::ApInfo&& apInfo); + + /** + * Compare two ApInfo objects for the purpose of keeping a sorted list of + * ApInfo objects. + * + * \param lhs left hand side ApInfo object + * \param rhs right hand side ApInfo object + * \return true if the left hand side ApInfo object should be placed before the + * right hand side ApInfo object in the sorted list of ApInfo objects, + * false otherwise + */ + virtual bool Compare (const StaWifiMac::ApInfo& lhs, const StaWifiMac::ApInfo& rhs) const = 0; + +protected: + /** + * Constructor (protected as this is an abstract base class) + */ + WifiAssocManager (); + void DoDispose (void) override; + + /// typedef for the sorted list of ApInfo objects + using SortedList = std::set; + + /** + * \return a const reference to the sorted list of ApInfo objects. + */ + const SortedList& GetSortedList (void) const; + + /** + * \return the scanning parameters. + */ + const WifiScanParams& GetScanParams (void) const; + + /** + * Check whether the given AP information match the current scanning parameters. + * + * \param apInfo the given AP information + * \return whether the given AP information match the current scanning parameters + */ + bool MatchScanParams (const StaWifiMac::ApInfo& apInfo) const; + + /** + * Allow subclasses to choose whether the given ApInfo shall be considered + * and hence inserted in the sorted list of ApInfo objects. + * + * \param apInfo the apInfo object to insert + * \return true if the apInfo object can be inserted, false otherwise + */ + virtual bool CanBeInserted (const StaWifiMac::ApInfo& apInfo) const = 0; + /** + * Allow subclasses to choose whether the given ApInfo shall be returned or + * discarded when the STA wifi MAC requests information on the best AP. + * + * \param apInfo the apInfo object to return + * \return true if the apInfo object can be returned, false otherwise + */ + virtual bool CanBeReturned (const StaWifiMac::ApInfo& apInfo) const = 0; + + /** + * Extract the best AP to associate with from the sorted list and return + * it, if any, to the STA wifi MAC along with the notification that scanning + * is completed. + */ + void ScanningTimeout (void); + + Ptr m_mac; ///< pointer to the STA wifi MAC + +private: + /** + * Start a scanning procedure. This method needs to schedule a call to + * ScanningTimeout when the scanning procedure is completed. + */ + virtual void DoStartScanning (void) = 0; + + WifiScanParams m_scanParams; ///< scanning parameters + SortedList m_apList; ///< sorted list of candidate APs + /// hash table to help locate ApInfo objects in the sorted list based on the BSSID + std::unordered_map m_apListIt; +}; + +} //namespace ns3 + +#endif /* WIFI_ASSOC_MANAGER_H */ diff --git a/src/wifi/model/wifi-default-assoc-manager.cc b/src/wifi/model/wifi-default-assoc-manager.cc new file mode 100644 index 000000000..011330a4e --- /dev/null +++ b/src/wifi/model/wifi-default-assoc-manager.cc @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#include "ns3/log.h" +#include "ns3/simulator.h" +#include "sta-wifi-mac.h" +#include "wifi-default-assoc-manager.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("WifiDefaultAssocManager"); + +NS_OBJECT_ENSURE_REGISTERED (WifiDefaultAssocManager); + +TypeId +WifiDefaultAssocManager::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WifiDefaultAssocManager") + .SetParent () + .AddConstructor () + .SetGroupName ("Wifi") + ; + return tid; +} + +WifiDefaultAssocManager::WifiDefaultAssocManager () +{ + NS_LOG_FUNCTION (this); +} + +WifiDefaultAssocManager::~WifiDefaultAssocManager () +{ + NS_LOG_FUNCTION (this); +} + +void +WifiDefaultAssocManager::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + m_probeRequestEvent.Cancel (); + m_waitBeaconEvent.Cancel (); + WifiAssocManager::DoDispose(); +} + +bool +WifiDefaultAssocManager::Compare (const StaWifiMac::ApInfo& lhs, + const StaWifiMac::ApInfo& rhs) const +{ + return lhs.m_snr > rhs.m_snr; +} + +void +WifiDefaultAssocManager::DoStartScanning (void) +{ + NS_LOG_FUNCTION (this); + + // if there are entries in the sorted list of AP information, reuse them and + // do not perform scanning + if (!GetSortedList ().empty ()) + { + Simulator::ScheduleNow (&WifiDefaultAssocManager::ScanningTimeout, this); + return; + } + + m_probeRequestEvent.Cancel (); + m_waitBeaconEvent.Cancel (); + + if (GetScanParams ().type == WifiScanParams::ACTIVE) + { + Simulator::Schedule (GetScanParams ().probeDelay, &StaWifiMac::SendProbeRequest, m_mac); + m_probeRequestEvent = Simulator::Schedule (GetScanParams ().probeDelay + + GetScanParams().maxChannelTime, + &WifiDefaultAssocManager::ScanningTimeout, + this); + } + else + { + m_waitBeaconEvent = Simulator::Schedule (GetScanParams ().maxChannelTime, + &WifiDefaultAssocManager::ScanningTimeout, + this); + } +} + +bool +WifiDefaultAssocManager::CanBeInserted (const StaWifiMac::ApInfo& apInfo) const +{ + return (m_waitBeaconEvent.IsRunning () || m_probeRequestEvent.IsRunning ()); +} + +bool +WifiDefaultAssocManager::CanBeReturned (const StaWifiMac::ApInfo& apInfo) const +{ + return true; +} + +} //namespace ns3 diff --git a/src/wifi/model/wifi-default-assoc-manager.h b/src/wifi/model/wifi-default-assoc-manager.h new file mode 100644 index 000000000..1965d3c06 --- /dev/null +++ b/src/wifi/model/wifi-default-assoc-manager.h @@ -0,0 +1,63 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#ifndef WIFI_DEFAULT_ASSOC_MANAGER_H +#define WIFI_DEFAULT_ASSOC_MANAGER_H + +#include "wifi-assoc-manager.h" + + +namespace ns3 { + +class StaWifiMac; + +/** + * \ingroup wifi + * + * Default wifi Association Manager. + */ +class WifiDefaultAssocManager : public WifiAssocManager +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + WifiDefaultAssocManager (); + virtual ~WifiDefaultAssocManager (); + + bool Compare (const StaWifiMac::ApInfo& lhs, const StaWifiMac::ApInfo& rhs) const override; + +protected: + void DoDispose (void) override; + bool CanBeInserted (const StaWifiMac::ApInfo& apInfo) const override; + bool CanBeReturned (const StaWifiMac::ApInfo& apInfo) const override; + +private: + void DoStartScanning (void) override; + + EventId m_waitBeaconEvent; ///< wait beacon event + EventId m_probeRequestEvent; ///< probe request event +}; + +} //namespace ns3 + +#endif /* WIFI_DEFAULT_ASSOC_MANAGER_H */