diff --git a/src/wifi/helper/wifi-helper.cc b/src/wifi/helper/wifi-helper.cc index deda2067a..dd0208564 100644 --- a/src/wifi/helper/wifi-helper.cc +++ b/src/wifi/helper/wifi-helper.cc @@ -1298,6 +1298,7 @@ WifiHelper::EnableLogComponents(LogLevel logLevel) LogComponentEnable("WifiSpectrumPhyInterface", logLevel); LogComponentEnable("WifiSpectrumSignalParameters", logLevel); LogComponentEnable("WifiSpectrumValueHelper", logLevel); + LogComponentEnable("WifiStaticSetupHelper", logLevel); LogComponentEnable("WifiTxCurrentModel", logLevel); LogComponentEnable("WifiTxParameters", logLevel); LogComponentEnable("WifiTxTimer", logLevel); diff --git a/src/wifi/helper/wifi-static-setup-helper.cc b/src/wifi/helper/wifi-static-setup-helper.cc index d18391f74..54bd4ccdf 100644 --- a/src/wifi/helper/wifi-static-setup-helper.cc +++ b/src/wifi/helper/wifi-static-setup-helper.cc @@ -8,11 +8,14 @@ #include "wifi-static-setup-helper.h" +#include "ns3/adhoc-wifi-mac.h" #include "ns3/ap-wifi-mac.h" #include "ns3/assert.h" #include "ns3/boolean.h" -#include "ns3/frame-exchange-manager.h" +#include "ns3/ht-configuration.h" +#include "ns3/ht-frame-exchange-manager.h" #include "ns3/log.h" +#include "ns3/mgt-action-headers.h" #include "ns3/mgt-headers.h" #include "ns3/net-device-container.h" #include "ns3/packet.h" @@ -277,4 +280,188 @@ WifiStaticSetupHelper::GetAssocReq(Ptr clientMac, linkId_t linkId, b return assocReq; } +void +WifiStaticSetupHelper::SetStaticBlockAck(Ptr apDev, + const NetDeviceContainer& clientDevs, + const std::set& tids, + std::optional gcrGroupAddr) +{ + NS_LOG_FUNCTION_NOARGS(); + + for (auto i = clientDevs.Begin(); i != clientDevs.End(); ++i) + { + auto clientDev = DynamicCast(*i); + NS_ASSERT_MSG(clientDev, "WifiNetDevice expected"); + if (!clientDev->GetHtConfiguration()) + { + // Block Ack requires HT support + continue; + } + for (const auto tid : tids) + { + SetStaticBlockAck(apDev, clientDev, tid, gcrGroupAddr); // Downlink setup + SetStaticBlockAck(clientDev, apDev, tid, gcrGroupAddr); // Uplink setup + } + } +} + +void +WifiStaticSetupHelper::SetStaticBlockAck(Ptr originatorDev, + Ptr recipientDev, + tid_t tid, + std::optional gcrGroupAddr) +{ + NS_LOG_FUNCTION_NOARGS(); + + Simulator::ScheduleNow(&WifiStaticSetupHelper::SetStaticBlockAckPostInit, + originatorDev, + recipientDev, + tid, + gcrGroupAddr); +} + +void +WifiStaticSetupHelper::SetStaticBlockAckPostInit(Ptr originatorDev, + Ptr recipientDev, + tid_t tid, + std::optional gcrGroupAddr) +{ + NS_LOG_FUNCTION_NOARGS(); + + // Originator Device + const auto originatorMac = originatorDev->GetMac(); + const auto originatorLinkId = *(originatorMac->GetLinkIds().begin()); + const auto originatorFem = DynamicCast( + originatorMac->GetFrameExchangeManager(originatorLinkId)); + NS_ASSERT_MSG(originatorFem, "Block ACK setup requires HT support"); + const auto originatorBaManager = originatorMac->GetQosTxop(tid)->GetBaManager(); + + // Recipient Device + const auto recipientMac = recipientDev->GetMac(); + const auto recipientLinkId = *(recipientMac->GetLinkIds().begin()); + const auto recipientFem = + DynamicCast(recipientMac->GetFrameExchangeManager(recipientLinkId)); + NS_ASSERT_MSG(recipientFem, "Block ACK setup requires HT support"); + const auto recipientBaManager = recipientMac->GetQosTxop(tid)->GetBaManager(); + + const auto originatorAddr = GetBaOriginatorAddr(originatorMac, recipientMac); + const auto recipientAddr = GetBaRecipientAddr(originatorMac, recipientMac); + + // Early return if BA Agreement already exists + if (originatorMac->GetBaAgreementEstablishedAsOriginator(recipientAddr, tid, gcrGroupAddr)) + { + return; + } + + // ADDBA Request + MgtAddBaRequestHeader reqHdr; + reqHdr.SetAmsduSupport(true); + reqHdr.SetImmediateBlockAck(); + reqHdr.SetTid(tid); + reqHdr.SetBufferSize(originatorMac->GetMpduBufferSize()); + reqHdr.SetTimeout(0); + reqHdr.SetStartingSequence(0); + if (gcrGroupAddr) + { + reqHdr.SetGcrGroupAddress(gcrGroupAddr.value()); + } + + // ADDBA Response + MgtAddBaResponseHeader respHdr; + StatusCode code; + code.SetSuccess(); + respHdr.SetStatusCode(code); + respHdr.SetAmsduSupport(true); + respHdr.SetImmediateBlockAck(); + respHdr.SetTid(tid); + auto agrBufferSize = std::min(reqHdr.GetBufferSize(), recipientMac->GetMpduBufferSize()); + respHdr.SetBufferSize(agrBufferSize); + respHdr.SetTimeout(0); + if (auto gcrGroupAddr = reqHdr.GetGcrGroupAddress()) + { + respHdr.SetGcrGroupAddress(gcrGroupAddr.value()); + } + + originatorBaManager->CreateOriginatorAgreement(reqHdr, recipientAddr); + recipientBaManager->CreateRecipientAgreement(respHdr, + originatorAddr, + reqHdr.GetStartingSequence(), + recipientMac->m_rxMiddle); + auto recipientAgr [[maybe_unused]] = + recipientBaManager->GetAgreementAsRecipient(originatorAddr, + tid, + reqHdr.GetGcrGroupAddress()); + NS_ASSERT_MSG(recipientAgr.has_value(), + "No agreement as recipient found for originator " << originatorAddr << ", TID " + << +tid); + originatorBaManager->UpdateOriginatorAgreement(respHdr, + recipientAddr, + reqHdr.GetStartingSequence()); + auto originatorAgr [[maybe_unused]] = + originatorBaManager->GetAgreementAsOriginator(recipientAddr, + tid, + reqHdr.GetGcrGroupAddress()); + NS_ASSERT_MSG(originatorAgr.has_value(), + "No agreement as originator found for recipient " << recipientAddr << ", TID " + << +tid); +} + +Mac48Address +WifiStaticSetupHelper::GetBaOriginatorAddr(Ptr originatorMac, Ptr recipientMac) +{ + // Originator is AdhocWifiMac type + // FIXME Restricted to single link operation, as AdHocWifiMac does not support multi-link yet + if (const auto origAdhoc = DynamicCast(originatorMac)) + { + return origAdhoc->GetAddress(); + } + + // Recipient is AdhocWifiMac type + // Return MAC address of link communicating with recipient + if (const auto recAdhoc = DynamicCast(recipientMac)) + { + const auto origSta = DynamicCast(originatorMac); + NS_ASSERT_MSG(origSta, "Expected originator StaWifiMac type"); + return origSta->GetLocalAddress(recAdhoc->GetAddress()); + } + + // Infra WLAN case + auto isOriginatorClient{true}; + auto staMac = DynamicCast(originatorMac); + if (!staMac) + { + staMac = DynamicCast(recipientMac); + isOriginatorClient = false; + } + NS_ASSERT_MSG(staMac, "Expected one of the MACs to be StaWifiMac type"); + + const auto setupLinks = staMac->GetSetupLinkIds(); + const auto nSetupLinks = setupLinks.size(); + if (nSetupLinks != 1) + { // Handle cases other than single link association + return originatorMac->GetAddress(); + } + + // Handle case where one device is MLD and other is single link device + // Link MAC address to be used for Block ACK agreement + // Required for one device to be StaWifiMac type + const auto linkId = *(setupLinks.cbegin()); + if (isOriginatorClient) + { + const auto fem = originatorMac->GetFrameExchangeManager(linkId); + return fem->GetAddress(); + } + else + { + const auto fem = recipientMac->GetFrameExchangeManager(linkId); + return fem->GetBssid(); + } +} + +Mac48Address +WifiStaticSetupHelper::GetBaRecipientAddr(Ptr originatorMac, Ptr recipientMac) +{ + return GetBaOriginatorAddr(recipientMac, originatorMac); +} + } // namespace ns3 diff --git a/src/wifi/helper/wifi-static-setup-helper.h b/src/wifi/helper/wifi-static-setup-helper.h index 2edd987a9..df592fdd5 100644 --- a/src/wifi/helper/wifi-static-setup-helper.h +++ b/src/wifi/helper/wifi-static-setup-helper.h @@ -12,6 +12,9 @@ #include "ns3/mac48-address.h" #include "ns3/wifi-utils.h" +#include +#include + namespace ns3 { @@ -28,6 +31,7 @@ class WifiMacHeader; * air: * * - association/ML setup (note that scanning is disabled for this purpose) + * - block ack agreement(s) */ class WifiStaticSetupHelper { @@ -104,6 +108,50 @@ class WifiStaticSetupHelper static WifiMacHeader GetAssocRespMacHdr(Mac48Address staLinkAddr, Ptr apMac, linkId_t apLinkId); + + /// Bypass ADDBA Request-Response exchange sequence between AP and STAs for given TIDs. + /// Static setup will be performed in both uplink and downlink. + /// @param apDev AP device + /// @param clientDevs STA devices + /// @param tids the set of TIDs corresponding to Block ACK agreements + /// @param gcrGroupAddr MAC address of the GCR group (GCR Group Address) + static void SetStaticBlockAck(Ptr apDev, + const NetDeviceContainer& clientDevs, + const std::set& tids, + std::optional gcrGroupAddr = std::nullopt); + + /// Bypass ADDBA Request-Response exchange sequence between input devices for given TID. + /// @param originatorDev originator device of Block ACK agreement + /// @param recipientDev recipient device of Block ACK agreement + /// @param tid TID corresponding to Block ACK agreement + /// @param gcrGroupAddr MAC address of the GCR group (GCR Group Address) + static void SetStaticBlockAck(Ptr originatorDev, + Ptr recipientDev, + tid_t tid, + std::optional gcrGroupAddr = std::nullopt); + + /// Perform ADDBA Request-Response exchange sequence between input devices for given TID + /// post initialization at runtime begin + /// @param originatorDev originator device of Block ACK agreement + /// @param recipientDev recipient device of Block ACK agreement + /// @param tid TID corresponding to Block ACK agreement + /// @param gcrGroupAddr MAC address of the GCR group (GCR Group Address) + static void SetStaticBlockAckPostInit(Ptr originatorDev, + Ptr recipientDev, + tid_t tid, + std::optional gcrGroupAddr = std::nullopt); + + /// Get Block ACK originator address based on devices MAC config + /// @param originatorMac originator MAC + /// @param recipientMac recipient MAC + /// @return the Block Ack originator address + static Mac48Address GetBaOriginatorAddr(Ptr originatorMac, Ptr recipientMac); + + /// Get Block ACK recipient address based on devices MAC config + /// @param originatorMac originator MAC + /// @param recipientMac recipient MAC + /// @return the Block Ack recipient address + static Mac48Address GetBaRecipientAddr(Ptr originatorMac, Ptr recipientMac); }; } // namespace ns3