11#include "ns3/adhoc-wifi-mac.h"
12#include "ns3/ap-wifi-mac.h"
13#include "ns3/assert.h"
14#include "ns3/boolean.h"
15#include "ns3/emlsr-manager.h"
16#include "ns3/ht-configuration.h"
17#include "ns3/ht-frame-exchange-manager.h"
19#include "ns3/mgt-action-headers.h"
20#include "ns3/mgt-headers.h"
21#include "ns3/net-device-container.h"
22#include "ns3/packet.h"
23#include "ns3/simulator.h"
24#include "ns3/sta-wifi-mac.h"
25#include "ns3/wifi-net-device.h"
26#include "ns3/wifi-remote-station-manager.h"
27#include "ns3/wifi-utils.h"
40 for (
auto i = clientDevs.
Begin(); i != clientDevs.
End(); ++i)
66 NS_ABORT_MSG_IF(!apMac || !clientMac,
"Invalid static capabilities exchange case");
79 clientMac->SetAttribute(
"EnableScanning",
BooleanValue(
false));
82 const auto nClientLinks = clientMac->GetNLinks();
83 const auto isMldAssoc = nClientLinks > 1;
84 const auto apMldAddr = apMac->GetAddress();
85 const auto clientMldAddr = clientMac->GetAddress();
88 clientMac->SwapLinks(linkIdMap);
89 const auto clientLinkIds = clientMac->GetLinkIds();
90 const auto assocLinkId = *clientLinkIds.cbegin();
91 std::optional<MultiLinkElement> apMle;
96 std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
97 for (
const auto clientLinkId : clientLinkIds)
101 const auto apLinkId = clientLinkId;
102 auto& clientLink = clientMac->GetLink(clientLinkId);
105 auto apLinkAddr = apMac->GetFrameExchangeManager(apLinkId)->GetAddress();
106 clientMac->SetBssid(apLinkAddr, clientLinkId);
107 clientLink.bssid = apLinkAddr;
112 NS_ASSERT_MSG(apMle.has_value(),
"Expected Multi-link Element");
115 mleCommonInfo = std::make_shared<CommonInfoBasicMle>(apMle->GetCommonInfoBasic());
117 auto clientManager = clientMac->GetWifiRemoteStationManager(clientLinkId);
118 clientManager->AddStationMleCommonInfo(apLinkAddr, mleCommonInfo);
122 auto assocReq =
GetAssocReq(clientMac, assocLinkId, isMldAssoc);
123 auto clientLinkAddr = clientMac->GetFrameExchangeManager(assocLinkId)->GetAddress();
125 assocReqHdr.
SetAddr2(clientLinkAddr);
126 auto assocSuccess = apMac->ReceiveAssocRequest(assocReq, clientLinkAddr, assocLinkId);
127 apMac->ParseReportedStaInfo(assocReq, clientLinkAddr, assocLinkId);
129 "Static Association failed AP: " << apMldAddr <<
", STA: " << clientMldAddr);
133 auto assocResp =
GetAssocResp(clientLinkAddr, apMac, assocLinkId, isMldAssoc);
135 auto linkIdStaAddrMap = apMac->GetLinkIdStaAddrMap(assocResp, clientLinkAddr, assocLinkId);
136 apMac->SetAid(assocResp, linkIdStaAddrMap);
138 packet->AddHeader(assocResp);
140 clientMac->ReceiveAssocResp(mpdu, assocLinkId);
143 for (
auto clientLinkId : clientLinkIds)
145 const auto apLinkId = clientLinkId;
146 clientLinkAddr = clientMac->GetFrameExchangeManager(clientLinkId)->GetAddress();
147 apMac->GetWifiRemoteStationManager(apLinkId)->RecordGotAssocTxOk(clientLinkAddr);
148 const auto aid = apMac->GetAssociationId(clientLinkAddr, apLinkId);
149 if (
const auto gcrMgr = apMac->GetGcrManager())
151 const auto extendedCapabilities =
152 apMac->GetWifiRemoteStationManager(apLinkId)->GetStationExtendedCapabilities(
154 gcrMgr->NotifyStaAssociated(clientLinkAddr,
155 extendedCapabilities &&
156 (extendedCapabilities->m_robustAvStreaming > 0));
158 apMac->m_assocLogger(aid, clientLinkAddr);
161 NS_LOG_DEBUG(
"Assoc success AP addr=" << apMldAddr <<
", STA addr=" << clientMldAddr);
171std::map<linkId_t, linkId_t>
181std::map<linkId_t, linkId_t>
185 const auto nApLinks = apMac->GetNLinks();
186 const auto nClientLinks = clientMac->GetNLinks();
189 nApLinks >= nClientLinks,
190 "Expected AP MLD to have at least the same number of links than non-AP MLD, nApLinks="
191 << nApLinks <<
", nClientLinks=" << nClientLinks);
193 std::map<linkId_t, linkId_t> linkIdMap{};
194 auto apCandidateLinks = apMac->GetLinkIds();
196 for (
const auto clientLinkId : clientMac->GetLinkIds())
198 for (
const auto apLinkId : apCandidateLinks)
200 const auto apPhy = apMac->GetWifiPhy(apLinkId);
201 const auto clientPhy = clientMac->GetWifiPhy(clientLinkId);
202 if (!apPhy || !clientPhy)
206 NS_LOG_DEBUG(
"AP channel: " << apPhy->GetOperatingChannel());
207 NS_LOG_DEBUG(
"Client channel: " << clientPhy->GetOperatingChannel());
208 const auto isMatch = (apPhy->GetOperatingChannel().GetPrimaryChannel(
MHz_u{20}) ==
209 clientPhy->GetOperatingChannel().GetPrimaryChannel(
MHz_u{20}));
210 NS_LOG_DEBUG(
"Client Link ID = " << +clientLinkId <<
", AP Link ID Candidate="
211 << +apLinkId <<
", isMatch=" << isMatch);
214 linkIdMap[clientLinkId] = apLinkId;
220 "No matching AP found for STA PHY setting link ID=" << +clientLinkId);
221 apCandidateLinks.erase(linkIdMap.at(clientLinkId));
234 auto apLinkAddr = apMac->GetFrameExchangeManager(apLinkId)->GetAddress();
246 auto assocResp = apMac->GetAssocResp(clientLinkAddr, apLinkId);
260 auto frame = clientMac->GetAssociationRequest(
false, linkId);
261 auto assocReq = std::get<MgtAssocRequestHeader>(frame);
267 auto mle = clientMac->GetBasicMultiLinkElement(
false, linkId);
269 auto& link = clientMac->GetLink(linkId);
270 auto bssid = *link.bssid;
271 auto remoteManager = clientMac->GetWifiRemoteStationManager(linkId);
272 const auto& mldCap = remoteManager->GetStationMldCapabilities(bssid);
273 NS_ASSERT_MSG(mldCap,
"Expected MLD Capabilities info for AP MLD");
274 auto apNegSupport = mldCap->get().tidToLinkMappingSupport;
275 if (apNegSupport > 0)
287 const std::set<tid_t>& tids,
288 std::optional<Mac48Address> gcrGroupAddr)
292 for (
auto i = clientDevs.
Begin(); i != clientDevs.
End(); ++i)
296 if (!clientDev->GetHtConfiguration())
301 for (
const auto tid : tids)
313 std::optional<Mac48Address> gcrGroupAddr)
328 std::optional<Mac48Address> gcrGroupAddr)
333 const auto originatorMac = originatorDev->GetMac();
334 const auto originatorLinkId = *(originatorMac->GetLinkIds().begin());
336 originatorMac->GetFrameExchangeManager(originatorLinkId));
337 NS_ASSERT_MSG(originatorFem,
"Block ACK setup requires HT support");
338 const auto originatorBaManager = originatorMac->GetQosTxop(tid)->GetBaManager();
341 const auto recipientMac = recipientDev->GetMac();
342 const auto recipientLinkId = *(recipientMac->GetLinkIds().begin());
343 const auto recipientFem =
345 NS_ASSERT_MSG(recipientFem,
"Block ACK setup requires HT support");
346 const auto recipientBaManager = recipientMac->GetQosTxop(tid)->GetBaManager();
352 if (originatorMac->GetBaAgreementEstablishedAsOriginator(recipientAddr, tid, gcrGroupAddr))
378 auto agrBufferSize = std::min(reqHdr.
GetBufferSize(), recipientMac->GetMpduBufferSize());
386 originatorBaManager->CreateOriginatorAgreement(reqHdr, recipientAddr);
387 recipientBaManager->CreateRecipientAgreement(respHdr,
390 recipientMac->m_rxMiddle);
391 auto recipientAgr [[maybe_unused]] =
392 recipientBaManager->GetAgreementAsRecipient(originatorAddr,
396 "No agreement as recipient found for originator " << originatorAddr <<
", TID "
398 originatorBaManager->UpdateOriginatorAgreement(respHdr,
401 auto originatorAgr [[maybe_unused]] =
402 originatorBaManager->GetAgreementAsOriginator(recipientAddr,
406 "No agreement as originator found for recipient " << recipientAddr <<
", TID "
417 return origAdhoc->GetAddress();
425 NS_ASSERT_MSG(origSta,
"Expected originator StaWifiMac type");
426 return origSta->GetLocalAddress(recAdhoc->GetAddress());
430 auto isOriginatorClient{
true};
435 isOriginatorClient =
false;
437 NS_ASSERT_MSG(staMac,
"Expected one of the MACs to be StaWifiMac type");
439 const auto setupLinks = staMac->GetSetupLinkIds();
440 const auto nSetupLinks = setupLinks.size();
441 if (nSetupLinks != 1)
443 return originatorMac->GetAddress();
449 const auto linkId = *(setupLinks.cbegin());
450 if (isOriginatorClient)
452 const auto fem = originatorMac->GetFrameExchangeManager(linkId);
453 return fem->GetAddress();
457 const auto fem = recipientMac->GetFrameExchangeManager(linkId);
458 return fem->GetBssid();
484 NS_ASSERT_MSG(clientMac->IsAssociated(),
"Expected Association complete");
485 auto setupLinks = clientMac->GetSetupLinkIds();
487 if (
const auto isMldAssoc = (setupLinks.size() > 1); !isMldAssoc)
489 NS_LOG_DEBUG(
"Multi-link setup not performed, skipping EMLSR static setup");
492 if (!clientDev->IsEmlsrActivated())
494 NS_LOG_DEBUG(
"Non-AP MLD does not support EMLSR, not performing EMLSR static setup");
498 auto emlsrManager = clientMac->GetEmlsrManager();
500 emlsrManager->ComputeOperatingChannels();
501 auto emlOmnReq = emlsrManager->GetEmlOmn();
502 auto emlsrLinkId = emlsrManager->GetLinkToSendEmlOmn();
503 emlsrManager->ChangeEmlsrMode();
504 auto clientLinkAddr = clientMac->GetFrameExchangeManager(emlsrLinkId)->GetAddress();
507 apMac->ReceiveEmlOmn(emlOmnReq, clientLinkAddr, emlsrLinkId);
508 apMac->EmlOmnExchangeCompleted(emlOmnReq, clientLinkAddr, emlsrLinkId);
520 if ((!apMac->GetEhtSupported()) || (apMac->GetNLinks() == 1))
522 NS_LOG_DEBUG(
"AP does not support MLD, not performing EMLSR static setup");
526 if (!apDev->IsEmlsrActivated())
528 NS_LOG_DEBUG(
"AP MLD does not support EMLSR, not performing EMLSR static setup");
532 for (
auto i = clientDevs.
Begin(); i != clientDevs.
End(); ++i)
AttributeValue implementation for Boolean.
holds a vector of ns3::NetDevice pointers
Iterator Begin() const
Get an iterator which refers to the first NetDevice in the container.
Iterator End() const
Get an iterator which indicates past-the-last NetDevice in the container.
Smart pointer class similar to boost::intrusive_ptr.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Status code for association response.
void SetSuccess()
Set success bit to 0 (success).
TID-to-Link Mapping Information Element.
static Mac48Address GetBaRecipientAddr(Ptr< WifiMac > originatorMac, Ptr< WifiMac > recipientMac)
Get Block ACK recipient address based on devices MAC config.
static Mac48Address GetBaOriginatorAddr(Ptr< WifiMac > originatorMac, Ptr< WifiMac > recipientMac)
Get Block ACK originator address based on devices MAC config.
static void SetStaticBlockAckPostInit(Ptr< WifiNetDevice > originatorDev, Ptr< WifiNetDevice > recipientDev, tid_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
Perform ADDBA Request-Response exchange sequence between input devices for given TID post initializat...
static void SetStaticAssociation(Ptr< WifiNetDevice > bssDev, const NetDeviceContainer &clientDevs)
Bypass static capabilities exchange for input devices.
static std::map< linkId_t, linkId_t > GetLinkIdMap(Ptr< WifiNetDevice > apDev, Ptr< WifiNetDevice > clientDev)
Construct non-AP MLD link ID to AP MLD link ID mapping based on PHY channel settings.
static MgtAssocRequestHeader GetAssocReq(Ptr< StaWifiMac > staMac, linkId_t staLinkId, bool isMldAssoc)
Get Association Request for input STA link address.
static void SetStaticAssocPostInit(Ptr< WifiNetDevice > bssDev, Ptr< WifiNetDevice > clientDev)
Perform static Association Request/Response exchange for input devices post initialization at runtime...
static MgtAssocResponseHeader GetAssocResp(Mac48Address staLinkAddr, Ptr< ApWifiMac > apMac, linkId_t apLinkId, bool isMldAssoc)
Get Association Response for input STA link address from AP MAC including Multi-link Element if MLD A...
static void SetStaticEmlsrPostInit(Ptr< WifiNetDevice > apDev, Ptr< WifiNetDevice > clientDev)
Perform EML Operating Mode Notification exchange sequence between AP MLD and non-AP MLD to enable EML...
static void SetStaticBlockAck(Ptr< WifiNetDevice > apDev, const NetDeviceContainer &clientDevs, const std::set< tid_t > &tids, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
Bypass ADDBA Request-Response exchange sequence between AP and STAs for given TIDs.
static WifiMacHeader GetAssocRespMacHdr(Mac48Address staLinkAddr, Ptr< ApWifiMac > apMac, linkId_t apLinkId)
Get Association Response MAC Header for input STA link address from AP MAC including Multi-link Eleme...
static void SetStaticEmlsr(Ptr< WifiNetDevice > apDev, const NetDeviceContainer &clientDevs)
Bypass EML Operating Mode Notification exchange sequence between AP MLD and input non-AP devices.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
WifiTidToLinkMappingNegSupport
TID-to-Link Mapping Negotiation Support.
double MHz_u
MHz weak type.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
uint8_t tid_t
IEEE 802.11-2020 9.2.4.5.2 TID subfield.
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
uint8_t linkId_t
IEEE 802.11be D7.0 Figure 9-207e—Link ID Info field format.