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/power-save-manager.h"
24#include "ns3/simulator.h"
25#include "ns3/sta-wifi-mac.h"
26#include "ns3/wifi-net-device.h"
27#include "ns3/wifi-remote-station-manager.h"
28#include "ns3/wifi-utils.h"
41 for (
auto i = clientDevs.
Begin(); i != clientDevs.
End(); ++i)
67 NS_ABORT_MSG_IF(!apMac || !clientMac,
"Invalid static capabilities exchange case");
80 clientMac->SetAttribute(
"EnableScanning",
BooleanValue(
false));
83 const auto nClientLinks = clientMac->GetNLinks();
84 const auto isMldAssoc = nClientLinks > 1;
85 const auto apMldAddr = apMac->GetAddress();
86 const auto clientMldAddr = clientMac->GetAddress();
89 clientMac->SwapLinks(linkIdMap);
90 const auto clientLinkIds = clientMac->GetLinkIds();
91 const auto assocLinkId = *clientLinkIds.cbegin();
92 std::optional<MultiLinkElement> apMle;
97 std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
98 for (
const auto clientLinkId : clientLinkIds)
102 const auto apLinkId = clientLinkId;
103 auto& clientLink = clientMac->GetLink(clientLinkId);
106 auto apLinkAddr = apMac->GetFrameExchangeManager(apLinkId)->GetAddress();
107 clientMac->SetBssid(apLinkAddr, clientLinkId);
108 clientLink.bssid = apLinkAddr;
113 NS_ASSERT_MSG(apMle.has_value(),
"Expected Multi-link Element");
116 mleCommonInfo = std::make_shared<CommonInfoBasicMle>(apMle->GetCommonInfoBasic());
118 auto clientManager = clientMac->GetWifiRemoteStationManager(clientLinkId);
119 clientManager->AddStationMleCommonInfo(apLinkAddr, mleCommonInfo);
123 auto assocReq =
GetAssocReq(clientMac, assocLinkId, isMldAssoc);
124 auto clientLinkAddr = clientMac->GetFrameExchangeManager(assocLinkId)->GetAddress();
126 assocReqHdr.
SetAddr2(clientLinkAddr);
127 auto assocSuccess = apMac->ReceiveAssocRequest(assocReq, clientLinkAddr, assocLinkId);
128 apMac->ParseReportedStaInfo(assocReq, clientLinkAddr, assocLinkId);
130 "Static Association failed AP: " << apMldAddr <<
", STA: " << clientMldAddr);
134 auto assocResp =
GetAssocResp(clientLinkAddr, apMac, assocLinkId, isMldAssoc);
136 auto linkIdStaAddrMap = apMac->GetLinkIdStaAddrMap(assocResp, clientLinkAddr, assocLinkId);
137 apMac->SetAid(assocResp, linkIdStaAddrMap);
139 packet->AddHeader(assocResp);
141 clientMac->ReceiveAssocResp(mpdu, assocLinkId);
144 for (
auto clientLinkId : clientLinkIds)
146 const auto apLinkId = clientLinkId;
147 clientLinkAddr = clientMac->GetFrameExchangeManager(clientLinkId)->GetAddress();
148 apMac->GetWifiRemoteStationManager(apLinkId)->RecordGotAssocTxOk(clientLinkAddr);
149 const auto aid = apMac->GetAssociationId(clientLinkAddr, apLinkId);
150 if (
const auto gcrMgr = apMac->GetGcrManager())
152 const auto extendedCapabilities =
153 apMac->GetWifiRemoteStationManager(apLinkId)->GetStationExtendedCapabilities(
155 gcrMgr->NotifyStaAssociated(clientLinkAddr,
156 extendedCapabilities &&
157 (extendedCapabilities->m_robustAvStreaming > 0));
159 apMac->m_assocLogger(aid, clientLinkAddr);
162 NS_LOG_DEBUG(
"Assoc success AP addr=" << apMldAddr <<
", STA addr=" << clientMldAddr);
180 if (clientMac->m_powerSaveManager)
182 for (
const auto apLinkId : apMac->GetLinkIds())
184 if (
const auto& beaconEvent = apMac->GetLink(apLinkId).beaconEvent;
185 beaconEvent.IsPending())
187 clientMac->m_powerSaveManager->NotifyBeaconIntervalAndTimestamp(
188 apMac->GetBeaconInterval(),
190 apMac->GetBeaconInterval(),
194 clientMac->m_powerSaveManager->NotifyAssocCompleted();
205std::map<linkId_t, linkId_t>
215std::map<linkId_t, linkId_t>
219 const auto nApLinks = apMac->GetNLinks();
220 const auto nClientLinks = clientMac->GetNLinks();
223 nApLinks >= nClientLinks,
224 "Expected AP MLD to have at least the same number of links than non-AP MLD, nApLinks="
225 << nApLinks <<
", nClientLinks=" << nClientLinks);
227 std::map<linkId_t, linkId_t> linkIdMap{};
228 auto apCandidateLinks = apMac->GetLinkIds();
230 for (
const auto clientLinkId : clientMac->GetLinkIds())
232 for (
const auto apLinkId : apCandidateLinks)
234 const auto apPhy = apMac->GetWifiPhy(apLinkId);
235 const auto clientPhy = clientMac->GetWifiPhy(clientLinkId);
236 if (!apPhy || !clientPhy)
240 NS_LOG_DEBUG(
"AP channel: " << apPhy->GetOperatingChannel());
241 NS_LOG_DEBUG(
"Client channel: " << clientPhy->GetOperatingChannel());
242 const auto isMatch = (apPhy->GetOperatingChannel().GetPrimaryChannel(
MHz_u{20}) ==
243 clientPhy->GetOperatingChannel().GetPrimaryChannel(
MHz_u{20}));
244 NS_LOG_DEBUG(
"Client Link ID = " << +clientLinkId <<
", AP Link ID Candidate="
245 << +apLinkId <<
", isMatch=" << isMatch);
248 linkIdMap[clientLinkId] = apLinkId;
254 "No matching AP found for STA PHY setting link ID=" << +clientLinkId);
255 apCandidateLinks.erase(linkIdMap.at(clientLinkId));
268 auto apLinkAddr = apMac->GetFrameExchangeManager(apLinkId)->GetAddress();
280 auto assocResp = apMac->GetAssocResp(clientLinkAddr, apLinkId);
294 auto frame = clientMac->GetAssociationRequest(
false, linkId);
295 auto assocReq = std::get<MgtAssocRequestHeader>(frame);
301 auto mle = clientMac->GetBasicMultiLinkElement(
false, linkId);
303 auto& link = clientMac->GetLink(linkId);
304 auto bssid = *link.bssid;
305 auto remoteManager = clientMac->GetWifiRemoteStationManager(linkId);
306 const auto& mldCap = remoteManager->GetStationMldCapabilities(bssid);
307 NS_ASSERT_MSG(mldCap,
"Expected MLD Capabilities info for AP MLD");
308 auto apNegSupport = mldCap->get().tidToLinkMappingSupport;
309 if (apNegSupport > 0)
321 const auto setupLinks = clientMac->GetSetupLinkIds();
322 for (
const auto linkId : setupLinks)
326 apMac->StaSwitchingToActiveModeOrDeassociated(clientMac->GetAddress(), linkId);
330 apMac->StaSwitchingToPsMode(clientMac->GetAddress(), linkId);
338 const std::set<tid_t>& tids,
339 std::optional<Mac48Address> gcrGroupAddr)
343 for (
auto i = clientDevs.
Begin(); i != clientDevs.
End(); ++i)
347 if (!clientDev->GetHtConfiguration())
352 for (
const auto tid : tids)
364 std::optional<Mac48Address> gcrGroupAddr)
379 std::optional<Mac48Address> gcrGroupAddr)
384 const auto originatorMac = originatorDev->GetMac();
385 const auto originatorLinkId = *(originatorMac->GetLinkIds().begin());
387 originatorMac->GetFrameExchangeManager(originatorLinkId));
388 NS_ASSERT_MSG(originatorFem,
"Block ACK setup requires HT support");
389 const auto originatorBaManager = originatorMac->GetQosTxop(tid)->GetBaManager();
392 const auto recipientMac = recipientDev->GetMac();
393 const auto recipientLinkId = *(recipientMac->GetLinkIds().begin());
394 const auto recipientFem =
396 NS_ASSERT_MSG(recipientFem,
"Block ACK setup requires HT support");
397 const auto recipientBaManager = recipientMac->GetQosTxop(tid)->GetBaManager();
403 if (originatorMac->GetBaAgreementEstablishedAsOriginator(recipientAddr, tid, gcrGroupAddr))
429 auto agrBufferSize = std::min(reqHdr.
GetBufferSize(), recipientMac->GetMpduBufferSize());
437 originatorBaManager->CreateOriginatorAgreement(reqHdr, recipientAddr);
438 recipientBaManager->CreateRecipientAgreement(respHdr,
441 recipientMac->m_rxMiddle);
442 auto recipientAgr [[maybe_unused]] =
443 recipientBaManager->GetAgreementAsRecipient(originatorAddr,
447 "No agreement as recipient found for originator " << originatorAddr <<
", TID "
449 originatorBaManager->UpdateOriginatorAgreement(respHdr,
452 auto originatorAgr [[maybe_unused]] =
453 originatorBaManager->GetAgreementAsOriginator(recipientAddr,
457 "No agreement as originator found for recipient " << recipientAddr <<
", TID "
468 return origAdhoc->GetAddress();
476 NS_ASSERT_MSG(origSta,
"Expected originator StaWifiMac type");
477 return origSta->GetLocalAddress(recAdhoc->GetAddress());
481 auto isOriginatorClient{
true};
486 isOriginatorClient =
false;
488 NS_ASSERT_MSG(staMac,
"Expected one of the MACs to be StaWifiMac type");
490 const auto setupLinks = staMac->GetSetupLinkIds();
491 const auto nSetupLinks = setupLinks.size();
492 if (nSetupLinks != 1)
494 return originatorMac->GetAddress();
500 const auto linkId = *(setupLinks.cbegin());
501 if (isOriginatorClient)
503 const auto fem = originatorMac->GetFrameExchangeManager(linkId);
504 return fem->GetAddress();
508 const auto fem = recipientMac->GetFrameExchangeManager(linkId);
509 return fem->GetBssid();
535 NS_ASSERT_MSG(clientMac->IsAssociated(),
"Expected Association complete");
536 auto setupLinks = clientMac->GetSetupLinkIds();
538 if (
const auto isMldAssoc = (setupLinks.size() > 1); !isMldAssoc)
540 NS_LOG_DEBUG(
"Multi-link setup not performed, skipping EMLSR static setup");
543 if (!clientDev->IsEmlsrActivated())
545 NS_LOG_DEBUG(
"Non-AP MLD does not support EMLSR, not performing EMLSR static setup");
553 std::map<linkId_t, WifiPowerManagementMode> pmModes;
554 for (
const auto linkId : setupLinks)
556 pmModes[linkId] = clientMac->GetPmMode(linkId);
559 auto emlsrManager = clientMac->GetEmlsrManager();
561 emlsrManager->ComputeOperatingChannels();
562 auto emlOmnReq = emlsrManager->GetEmlOmn();
563 auto emlsrLinkId = emlsrManager->GetLinkToSendEmlOmn();
564 emlsrManager->ChangeEmlsrMode(emlsrLinkId);
565 auto clientLinkAddr = clientMac->GetFrameExchangeManager(emlsrLinkId)->GetAddress();
568 apMac->ReceiveEmlOmn(emlOmnReq, clientLinkAddr, emlsrLinkId);
569 apMac->EmlOmnExchangeCompleted(emlOmnReq, clientLinkAddr, emlsrLinkId);
572 for (
const auto& [linkId, pmMode] : pmModes)
574 clientMac->GetLink(linkId).pmMode = pmMode;
592 if ((!apMac->GetEhtSupported()) || (apMac->GetNLinks() == 1))
594 NS_LOG_DEBUG(
"AP does not support MLD, not performing EMLSR static setup");
598 if (!apDev->IsEmlsrActivated())
600 NS_LOG_DEBUG(
"AP MLD does not support EMLSR, not performing EMLSR static setup");
604 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 Time Now()
Return the current simulation virtual time.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
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 AlignApViewOfStaPmMode(Ptr< ApWifiMac > apMac, Ptr< StaWifiMac > clientMac)
Align the knowledge that the AP has about the PM mode of the STAs affiliated with the client device t...
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.