From da9a8a92e63bdc4abcb509f7edb41690ccea3f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deronne?= Date: Sat, 10 Jun 2023 15:47:41 +0200 Subject: [PATCH] wifi: Add initial manager classes for GCR Only GCR-UR is supported at this stage by these managers --- src/wifi/CMakeLists.txt | 4 + src/wifi/helper/wifi-helper.cc | 2 + src/wifi/model/gcr-manager.cc | 197 +++++++++++++++++++++ src/wifi/model/gcr-manager.h | 144 +++++++++++++++ src/wifi/model/wifi-default-gcr-manager.cc | 57 ++++++ src/wifi/model/wifi-default-gcr-manager.h | 45 +++++ 6 files changed, 449 insertions(+) create mode 100644 src/wifi/model/gcr-manager.cc create mode 100644 src/wifi/model/gcr-manager.h create mode 100644 src/wifi/model/wifi-default-gcr-manager.cc create mode 100644 src/wifi/model/wifi-default-gcr-manager.h diff --git a/src/wifi/CMakeLists.txt b/src/wifi/CMakeLists.txt index 727661848..52e92894a 100644 --- a/src/wifi/CMakeLists.txt +++ b/src/wifi/CMakeLists.txt @@ -50,6 +50,7 @@ set(source_files model/frame-capture-model.cc model/frame-exchange-manager.cc model/gcr-group-address.cc + model/gcr-manager.cc model/he/constant-obss-pd-algorithm.cc model/he/he-6ghz-band-capabilities.cc model/he/he-capabilities.cc @@ -135,6 +136,7 @@ set(source_files model/wifi-bandwidth-filter.cc model/wifi-default-ack-manager.cc model/wifi-default-assoc-manager.cc + model/wifi-default-gcr-manager.cc model/wifi-default-protection-manager.cc model/wifi-information-element.cc model/wifi-mac-header.cc @@ -216,6 +218,7 @@ set(header_files model/frame-capture-model.h model/frame-exchange-manager.h model/gcr-group-address.h + model/gcr-manager.h model/he/constant-obss-pd-algorithm.h model/he/he-6ghz-band-capabilities.h model/he/he-capabilities.h @@ -301,6 +304,7 @@ set(header_files model/wifi-bandwidth-filter.h model/wifi-default-ack-manager.h model/wifi-default-assoc-manager.h + model/wifi-default-gcr-manager.h model/wifi-default-protection-manager.h model/wifi-information-element.h model/wifi-mac-header.h diff --git a/src/wifi/helper/wifi-helper.cc b/src/wifi/helper/wifi-helper.cc index 4bfad7696..aa51ed4cf 100644 --- a/src/wifi/helper/wifi-helper.cc +++ b/src/wifi/helper/wifi-helper.cc @@ -1197,6 +1197,7 @@ WifiHelper::EnableLogComponents(LogLevel logLevel) LogComponentEnable("ErpOfdmPhy", logLevel); LogComponentEnable("ErpOfdmPpdu", logLevel); LogComponentEnable("FrameExchangeManager", logLevel); + LogComponentEnable("GcrManager", logLevel); LogComponentEnable("HeConfiguration", logLevel); LogComponentEnable("HeFrameExchangeManager", logLevel); LogComponentEnable("HePhy", logLevel); @@ -1244,6 +1245,7 @@ WifiHelper::EnableLogComponents(LogLevel logLevel) LogComponentEnable("WifiAssocManager", logLevel); LogComponentEnable("WifiDefaultAckManager", logLevel); LogComponentEnable("WifiDefaultAssocManager", logLevel); + LogComponentEnable("WifiDefaultGcrManager", logLevel); LogComponentEnable("WifiDefaultProtectionManager", logLevel); LogComponentEnable("WifiMac", logLevel); LogComponentEnable("WifiMacQueue", logLevel); diff --git a/src/wifi/model/gcr-manager.cc b/src/wifi/model/gcr-manager.cc new file mode 100644 index 000000000..da10cee31 --- /dev/null +++ b/src/wifi/model/gcr-manager.cc @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2023 DERONNE SOFTWARE ENGINEERING + * + * SPDX-License-Identifier: GPL-2.0-only + * + * Author: Sébastien Deronne + */ + +#include "gcr-manager.h" + +#include "ap-wifi-mac.h" +#include "wifi-mpdu.h" + +#include "ns3/enum.h" +#include "ns3/log.h" +#include "ns3/uinteger.h" + +#include + +namespace ns3 +{ + +NS_LOG_COMPONENT_DEFINE("GcrManager"); + +NS_OBJECT_ENSURE_REGISTERED(GcrManager); + +TypeId +GcrManager::GetTypeId() +{ + static TypeId tid = + TypeId("ns3::GcrManager") + .SetParent() + .SetGroupName("Wifi") + .AddAttribute("RetransmissionPolicy", + "The retransmission policy to use for group addresses.", + TypeId::ATTR_GET | + TypeId::ATTR_CONSTRUCT, // prevent setting after construction + EnumValue(GroupAddressRetransmissionPolicy::NO_ACK_NO_RETRY), + MakeEnumAccessor( + &GcrManager::m_retransmissionPolicy), + MakeEnumChecker(GroupAddressRetransmissionPolicy::NO_ACK_NO_RETRY, + "NO_RETRY", + GroupAddressRetransmissionPolicy::GCR_UNSOLICITED_RETRY, + "GCR_UR")) + .AddAttribute("UnsolicitedRetryLimit", + "The maximum number of transmission attempts of a frame delivered using " + "the GCR unsolicited retry retransmission policy.", + UintegerValue(7), + MakeUintegerAccessor(&GcrManager::m_gcrUnsolicitedRetryLimit), + MakeUintegerChecker()); + return tid; +} + +GcrManager::GcrManager() + : m_unsolicitedRetryCounter{0} +{ + NS_LOG_FUNCTION(this); +} + +GcrManager::~GcrManager() +{ + NS_LOG_FUNCTION(this); +} + +void +GcrManager::DoDispose() +{ + NS_LOG_FUNCTION(this); + m_apMac = nullptr; + Object::DoDispose(); +} + +void +GcrManager::SetWifiMac(Ptr mac) +{ + NS_LOG_FUNCTION(this << mac); + NS_ASSERT(mac); + m_apMac = mac; + + NS_ABORT_MSG_IF(m_apMac->GetTypeOfStation() != AP || !m_apMac->GetQosSupported(), + "GcrManager can only be installed on QoS APs"); +} + +GroupAddressRetransmissionPolicy +GcrManager::GetRetransmissionPolicy() const +{ + return m_retransmissionPolicy; +} + +GroupAddressRetransmissionPolicy +GcrManager::GetRetransmissionPolicyFor(const WifiMacHeader& header) const +{ + NS_ASSERT_MSG(header.IsQosData() && IsGroupcast(header.GetAddr1()), + "GCR service is only for QoS groupcast data frames"); + + // 11.21.16.3.4 GCR operation: + // A STA providing GCR service may switch between the DMS, + // GCR block ack, or GCR unsolicited retry retransmission policies + + // This is a retry, use configured retransmission policy + if (header.IsRetry()) + { + return m_retransmissionPolicy; + } + + // This is not a retry but all STAs are GCR-capable, use configured retransmission policy + if (m_nonGcrStas.empty()) + { + return m_retransmissionPolicy; + } + + // not a retry and GCR-incapable STA(s) present, transmit using No-Ack/No-Retry + return GroupAddressRetransmissionPolicy::NO_ACK_NO_RETRY; +} + +bool +GcrManager::KeepGroupcastQueued(Ptr mpdu) +{ + NS_LOG_FUNCTION(this << *mpdu); + NS_ASSERT_MSG(mpdu->GetHeader().IsQosData() && IsGroupcast(mpdu->GetHeader().GetAddr1()), + "GCR service is only for QoS groupcast data frames"); + NS_ASSERT_MSG(m_retransmissionPolicy != GroupAddressRetransmissionPolicy::NO_ACK_NO_RETRY, + "GCR service is not enabled"); + NS_ASSERT_MSG(!m_staMembers.empty(), "GCR service should not be used"); + if (!m_mpdu || !mpdu->GetHeader().IsRetry()) + { + m_unsolicitedRetryCounter = 0; + m_mpdu = mpdu; + NS_LOG_DEBUG("First groupcast transmission using No-Ack/No-Retry"); + } + else + { + m_unsolicitedRetryCounter++; + NS_LOG_DEBUG("GCR solicited retry counter increased to " << +m_unsolicitedRetryCounter); + } + if (m_unsolicitedRetryCounter == m_gcrUnsolicitedRetryLimit) + { + NS_LOG_DEBUG("Last groupcast transmission retry done"); + m_mpdu = nullptr; + m_unsolicitedRetryCounter = 0; + return false; + } + return true; +} + +void +GcrManager::NotifyStaAssociated(const Mac48Address& staAddress, bool gcrCapable) +{ + if (m_retransmissionPolicy == GroupAddressRetransmissionPolicy::NO_ACK_NO_RETRY) + { + // GCR is not used and we do not support run-time change of the retransmission policy + return; + } + NS_LOG_FUNCTION(this << staAddress << gcrCapable); + if (gcrCapable) + { + NS_ASSERT(m_staMembers.count(staAddress) == 0); + m_staMembers.insert(staAddress); + } + else + { + NS_ASSERT(m_nonGcrStas.count(staAddress) == 0); + m_nonGcrStas.insert(staAddress); + } +} + +void +GcrManager::NotifyStaDeassociated(const Mac48Address& staAddress) +{ + if (m_retransmissionPolicy == GroupAddressRetransmissionPolicy::NO_ACK_NO_RETRY) + { + // GCR is not used and we do not support run-time change of the retransmission policy + return; + } + NS_LOG_FUNCTION(this << staAddress); + m_nonGcrStas.erase(staAddress); + m_staMembers.erase(staAddress); +} + +const GcrManager::GcrMembers& +GcrManager::GetMemberStasForGroupAddress(const Mac48Address& /* groupAddress */) const +{ + // TODO: we currently assume all STAs belong to all group addresses + // as long as group membership action frame is not implemented + return m_staMembers; +} + +void +GcrManager::NotifyGroupMembershipChanged(const Mac48Address& staAddress, + const std::set& groupAddressList) +{ + NS_LOG_FUNCTION(this << staAddress << groupAddressList.size()); + // TODO: group membership is not implemented yet, current implementation assumes GCR STAs are + // members of all groups +} + +} // namespace ns3 diff --git a/src/wifi/model/gcr-manager.h b/src/wifi/model/gcr-manager.h new file mode 100644 index 000000000..5de72137e --- /dev/null +++ b/src/wifi/model/gcr-manager.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023 DERONNE SOFTWARE ENGINEERING + * + * SPDX-License-Identifier: GPL-2.0-only + * + * Author: Sébastien Deronne + */ + +#ifndef GCR_MANAGER_H +#define GCR_MANAGER_H + +#include "qos-utils.h" + +#include "ns3/mac48-address.h" +#include "ns3/object.h" + +#include +#include + +namespace ns3 +{ + +class ApWifiMac; +class WifiMpdu; + +/** + * @brief The possible values for group address retransmission policy + */ +enum class GroupAddressRetransmissionPolicy : uint8_t +{ + NO_ACK_NO_RETRY = 0, + GCR_UNSOLICITED_RETRY +}; + +/** + * @ingroup wifi + * + * GcrManager is a base class defining the API to handle 802.11aa GCR. + */ +class GcrManager : public Object +{ + public: + /** + * @brief Get the type ID. + * @return the object TypeId + */ + static TypeId GetTypeId(); + + GcrManager(); + ~GcrManager() override; + + /** + * Set the wifi MAC. Note that it must be the MAC of a QoS AP. + * + * @param mac the wifi MAC + */ + void SetWifiMac(Ptr mac); + + /** + * Get the configured retransmission policy. + * + * @return the configured retransmission policy + */ + GroupAddressRetransmissionPolicy GetRetransmissionPolicy() const; + + /** + * Get the retransmission policy to use to transmit a given group addressed packet. + * + * @param header the header of the groupcast frame + * @return the retransmission policy to use + */ + GroupAddressRetransmissionPolicy GetRetransmissionPolicyFor(const WifiMacHeader& header) const; + + /** + * This function indicates whether a groupcast MPDU should be kept for next retransmission. + * + * @param mpdu the groupcast MPDU + * @return whether a groupcast MPDU should be kept for next retransmission + */ + bool KeepGroupcastQueued(Ptr mpdu); + + /** + * This function notifies a STA is associated. + * + * @param staAddress the MAC address of the STA + * @param isGcrCapable whether GCR is supported by the STA + */ + void NotifyStaAssociated(const Mac48Address& staAddress, bool isGcrCapable); + + /** + * This function deletes a STA as a member of any group addresses. + * + * @param staAddress the MAC address of the STA + */ + void NotifyStaDeassociated(const Mac48Address& staAddress); + + /** + * This function adds a STA as a member of zero or more group addresses. + * + * @param staAddress the MAC address of the STA + * @param groupAddressList zero or more MAC addresses to indicate the set of group addressed MAC + * addresses for which the STA receives frames + */ + void NotifyGroupMembershipChanged(const Mac48Address& staAddress, + const std::set& groupAddressList); + + /// MAC addresses of member STAs of a GCR group + using GcrMembers = std::unordered_set; + + /** + * Get the list of MAC addresses of member STAs for a given group address. + * @param groupAddress the group address + * @return list of MAC addresses of member STAs for the group address + */ + const GcrMembers& GetMemberStasForGroupAddress(const Mac48Address& groupAddress) const; + + /** + * Get the MAC address of the individually addressed recipient to use for a groupcast frame for + * a given group address. + * @param groupAddress the group address + * @return the MAC address of the individually addressed recipient to use. + */ + virtual Mac48Address GetIndividuallyAddressedRecipient( + const Mac48Address& groupAddress) const = 0; + + protected: + void DoDispose() override; + + /// List of associated STAs that are not GCR capable + using NonGcrStas = GcrMembers; + + Ptr m_apMac; //!< the MAC of the AP + GroupAddressRetransmissionPolicy m_retransmissionPolicy; //!< retransmission policy + uint8_t m_gcrUnsolicitedRetryLimit; //!< GCR Unsolicited Retry Limit + uint8_t m_unsolicitedRetryCounter; //!< the unsolicited retry counter + Ptr m_mpdu; //!< current MPDU being retransmitted + NonGcrStas m_nonGcrStas; //!< the list of non-GCR capable STAs + GcrMembers m_staMembers; //!< the list of STA members (assume currently each member is part of + //!< all group) +}; + +} // namespace ns3 + +#endif /* GCR_MANAGER_H */ diff --git a/src/wifi/model/wifi-default-gcr-manager.cc b/src/wifi/model/wifi-default-gcr-manager.cc new file mode 100644 index 000000000..f02ae3816 --- /dev/null +++ b/src/wifi/model/wifi-default-gcr-manager.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 DERONNE SOFTWARE ENGINEERING + * + * SPDX-License-Identifier: GPL-2.0-only + * + * Author: Sébastien Deronne + */ + +#include "wifi-default-gcr-manager.h" + +#include "ap-wifi-mac.h" + +#include "ns3/log.h" + +namespace ns3 +{ + +NS_LOG_COMPONENT_DEFINE("WifiDefaultGcrManager"); + +NS_OBJECT_ENSURE_REGISTERED(WifiDefaultGcrManager); + +TypeId +WifiDefaultGcrManager::GetTypeId() +{ + static TypeId tid = TypeId("ns3::WifiDefaultGcrManager") + .SetParent() + .SetGroupName("Wifi") + .AddConstructor(); + return tid; +} + +WifiDefaultGcrManager::WifiDefaultGcrManager() +{ + NS_LOG_FUNCTION(this); +} + +WifiDefaultGcrManager::~WifiDefaultGcrManager() +{ + NS_LOG_FUNCTION_NOARGS(); +} + +Mac48Address +WifiDefaultGcrManager::GetIndividuallyAddressedRecipient( + const Mac48Address& /* groupAddress */) const +{ + /* + * 802.11-2020: 10.23.2.12.2 Unsolicited retry procedure: + * When using a protection mechanism that requires a response from another STA, + * the AP should select a STA that is a member of the GCR group. + * For now, we assume all associated GCR-capable STAs are part of the GCR group, + * hence we pick the first STA from the list held by the AP. + */ + NS_ASSERT(!m_staMembers.empty()); + return *m_staMembers.cbegin(); +} + +} // namespace ns3 diff --git a/src/wifi/model/wifi-default-gcr-manager.h b/src/wifi/model/wifi-default-gcr-manager.h new file mode 100644 index 000000000..b780f17fa --- /dev/null +++ b/src/wifi/model/wifi-default-gcr-manager.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 DERONNE SOFTWARE ENGINEERING + * + * SPDX-License-Identifier: GPL-2.0-only + * + * Author: Sébastien Deronne + */ + +#ifndef WIFI_DEFAULT_GCR_MANAGER_H +#define WIFI_DEFAULT_GCR_MANAGER_H + +#include "gcr-manager.h" + +namespace ns3 +{ + +/** + * @ingroup wifi + * + * WifiDefaultGcrManager is the default implementation for groupcast with retries GCR, as defined in + * 802.11aa. Since the standard does not describe how to map GCR-capable STAs to a given GCR group, + * the default implementation assumes all GCR-capable STAs are part of all GCR groups. Also, it is + * left left open to implementation which individual address to use to use while protecting a GCR + * transmission. The default implementation decides to pick the address of the first associated + * GCR-capable STA. + */ +class WifiDefaultGcrManager : public GcrManager +{ + public: + /** + * @brief Get the type ID. + * @return the object TypeId + */ + static TypeId GetTypeId(); + + WifiDefaultGcrManager(); + ~WifiDefaultGcrManager() override; + + Mac48Address GetIndividuallyAddressedRecipient( + const Mac48Address& groupcastAddress) const override; +}; + +} // namespace ns3 + +#endif /* WIFI_DEFAULT_GCR_MANAGER_H */