A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
sta-wifi-mac.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006, 2009 INRIA
3 * Copyright (c) 2009 MIRKO BANCHI
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
8 * Mirko Banchi <mk.banchi@gmail.com>
9 */
10
11#include "sta-wifi-mac.h"
12
15#include "mgt-action-headers.h"
16#include "mgt-headers.h"
17#include "qos-txop.h"
18#include "snr-tag.h"
19#include "wifi-assoc-manager.h"
20#include "wifi-mac-queue.h"
21#include "wifi-net-device.h"
22#include "wifi-phy.h"
23
24#include "ns3/attribute-container.h"
25#include "ns3/eht-configuration.h"
26#include "ns3/emlsr-manager.h"
27#include "ns3/he-configuration.h"
28#include "ns3/ht-configuration.h"
29#include "ns3/log.h"
30#include "ns3/packet.h"
31#include "ns3/pair.h"
32#include "ns3/pointer.h"
33#include "ns3/random-variable-stream.h"
34#include "ns3/simulator.h"
35#include "ns3/string.h"
36
37#include <iterator>
38#include <numeric>
39#include <sstream>
40
41namespace ns3
42{
43
44NS_LOG_COMPONENT_DEFINE("StaWifiMac");
45
47
48TypeId
50{
51 static TypeId tid =
52 TypeId("ns3::StaWifiMac")
54 .SetGroupName("Wifi")
55 .AddConstructor<StaWifiMac>()
56 .AddAttribute("ProbeRequestTimeout",
57 "The duration to actively probe the channel.",
58 TimeValue(Seconds(0.05)),
61 .AddAttribute("WaitBeaconTimeout",
62 "The duration to dwell on a channel while passively scanning for beacon",
66 .AddAttribute("AssocRequestTimeout",
67 "The interval between two consecutive association request attempts.",
68 TimeValue(Seconds(0.5)),
71 .AddAttribute("MaxMissedBeacons",
72 "Number of beacons which much be consecutively missed before "
73 "we attempt to restart association.",
74 UintegerValue(10),
77 .AddAttribute(
78 "ActiveProbing",
79 "If true, we send probe requests. If false, we don't."
80 "NOTE: if more than one STA in your simulation is using active probing, "
81 "you should enable it at a different simulation time for each STA, "
82 "otherwise all the STAs will start sending probes at the same time resulting in "
83 "collisions. "
84 "See bug 1060 for more info.",
85 BooleanValue(false),
88 .AddAttribute("ProbeDelay",
89 "Delay (in microseconds) to be used prior to transmitting a "
90 "Probe frame during active scanning.",
91 StringValue("ns3::UniformRandomVariable[Min=50.0|Max=250.0]"),
94 .AddAttribute(
95 "PowerSaveMode",
96 "Enable/disable power save mode on the given link. The power management mode is "
97 "actually changed when the AP acknowledges a frame sent with the Power Management "
98 "field set to the value corresponding to the requested mode",
99 TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
104 .AddAttribute("PmModeSwitchTimeout",
105 "If switching to a new Power Management mode is not completed within "
106 "this amount of time, make another attempt at switching Power "
107 "Management mode.",
108 TimeValue(Seconds(0.1)),
111 .AddTraceSource("Assoc",
112 "Associated with an access point. If this is an MLD that associated "
113 "with an AP MLD, the AP MLD address is provided.",
115 "ns3::Mac48Address::TracedCallback")
116 .AddTraceSource("LinkSetupCompleted",
117 "A link was setup in the context of ML setup with an AP MLD. "
118 "Provides ID of the setup link and AP MAC address",
120 "ns3::StaWifiMac::LinkSetupCallback")
121 .AddTraceSource("DeAssoc",
122 "Association with an access point lost. If this is an MLD "
123 "that disassociated with an AP MLD, the AP MLD address is provided.",
125 "ns3::Mac48Address::TracedCallback")
126 .AddTraceSource("LinkSetupCanceled",
127 "A link setup in the context of ML setup with an AP MLD was torn down. "
128 "Provides ID of the setup link and AP MAC address",
130 "ns3::StaWifiMac::LinkSetupCallback",
132 "Disassociation only occurs at MLD level; use DeAssoc trace.")
133 .AddTraceSource("BeaconArrival",
134 "Time of beacons arrival from associated AP",
136 "ns3::Time::TracedCallback")
137 .AddTraceSource("ReceivedBeaconInfo",
138 "Information about every received Beacon frame",
140 "ns3::ApInfo::TracedCallback");
141 return tid;
142}
143
145 : m_state(UNASSOCIATED),
146 m_aid(0),
147 m_assocRequestEvent()
148{
149 NS_LOG_FUNCTION(this);
150
151 // Let the lower layers know that we are acting as a non-AP STA in
152 // an infrastructure BSS.
154}
155
156void
158{
159 NS_LOG_FUNCTION(this);
160 // an EMLSR client must perform ML setup by using its main PHY
162 {
163 auto mainPhyId = m_emlsrManager->GetMainPhyId();
164 auto linkId = GetLinkForPhy(mainPhyId);
165 NS_ASSERT(linkId);
166 m_assocManager->SetAttribute(
167 "AllowedLinks",
168 AttributeContainerValue<UintegerValue>(std::list<uint8_t>{*linkId}));
169 }
170 if (m_emlsrManager)
171 {
172 m_emlsrManager->Initialize();
173 }
177}
178
179void
181{
182 NS_LOG_FUNCTION(this);
183 if (m_assocManager)
184 {
185 m_assocManager->Dispose();
186 }
187 m_assocManager = nullptr;
188 if (m_emlsrManager)
189 {
190 m_emlsrManager->Dispose();
191 }
192 m_emlsrManager = nullptr;
193 for (auto& [phyId, event] : m_emlsrLinkSwitch)
194 {
195 event.Cancel();
196 }
197 m_emlsrLinkSwitch.clear();
199}
200
205
206void
211
216
217std::unique_ptr<WifiMac::LinkEntity>
219{
220 return std::make_unique<StaLinkEntity>();
221}
222
224StaWifiMac::GetLink(uint8_t linkId) const
225{
226 return static_cast<StaLinkEntity&>(WifiMac::GetLink(linkId));
227}
228
230StaWifiMac::GetStaLink(const std::unique_ptr<WifiMac::LinkEntity>& link) const
231{
232 return static_cast<StaLinkEntity&>(*link);
233}
234
235int64_t
237{
238 NS_LOG_FUNCTION(this << stream);
239 m_probeDelay->SetStream(stream);
240 auto currentStream = stream + 1;
241 currentStream += WifiMac::AssignStreams(currentStream);
242 return (currentStream - stream);
243}
244
245void
247{
248 NS_LOG_FUNCTION(this << assocManager);
249 m_assocManager = assocManager;
250 m_assocManager->SetStaWifiMac(this);
251}
252
253void
255{
256 NS_LOG_FUNCTION(this << emlsrManager);
257 m_emlsrManager = emlsrManager;
258 m_emlsrManager->SetWifiMac(this);
259}
260
263{
264 return m_emlsrManager;
265}
266
267uint16_t
269{
270 NS_ASSERT_MSG(IsAssociated(), "This station is not associated to any AP");
271 return m_aid;
272}
273
274void
276{
277 NS_LOG_FUNCTION(this << enable);
278 m_activeProbing = enable;
279 if (m_state == SCANNING)
280 {
281 NS_LOG_DEBUG("STA is still scanning, reset scanning process");
283 }
284}
285
286bool
288{
289 return m_activeProbing;
290}
291
292void
293StaWifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
294{
295 NS_LOG_FUNCTION(this);
297 for (auto& phy : phys)
298 {
299 phy->SetCapabilitiesChangedCallback(
301 }
302}
303
305StaWifiMac::GetCurrentChannel(uint8_t linkId) const
306{
307 auto phy = GetWifiPhy(linkId);
308 const auto width = phy->GetOperatingChannel().IsOfdm() ? 20 : phy->GetChannelWidth();
309 uint8_t ch = phy->GetPrimaryChannelNumber(width);
310 return {ch, phy->GetPhyBand()};
311}
312
313void
314StaWifiMac::NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds)
315{
316 std::stringstream ss;
317 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
318 {
319 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
320 }
321 NS_LOG_FUNCTION(this << ss.str());
322
323 for (const auto& [linkId, lnk] : GetLinks())
324 {
325 auto& link = GetStaLink(lnk);
326
327 if (linkIds.contains(linkId))
328 {
329 // EMLSR mode enabled
330 link.emlsrEnabled = true;
331 link.pmMode = WIFI_PM_ACTIVE;
332 }
333 else
334 {
335 // EMLSR mode disabled
336 if (link.emlsrEnabled)
337 {
338 link.pmMode = WIFI_PM_POWERSAVE;
339 }
340 link.emlsrEnabled = false;
341 }
342 }
343}
344
345bool
346StaWifiMac::IsEmlsrLink(uint8_t linkId) const
347{
348 return GetLink(linkId).emlsrEnabled;
349}
350
351void
353{
354 NS_LOG_FUNCTION(this << linkId);
355 WifiMacHeader hdr;
360 hdr.SetDsNotFrom();
361 hdr.SetDsNotTo();
362 Ptr<Packet> packet = Create<Packet>();
364 probe.Get<Ssid>() = GetSsid();
365 auto supportedRates = GetSupportedRates(linkId);
366 probe.Get<SupportedRates>() = supportedRates.rates;
367 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
368 if (GetHtSupported(linkId))
369 {
371 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
372 }
373 if (GetVhtSupported(linkId))
374 {
375 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
376 }
377 if (GetHeSupported())
378 {
379 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
380 if (Is6GhzBand(linkId))
381 {
383 }
384 }
385 if (GetEhtSupported())
386 {
387 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
388 }
389 packet->AddHeader(probe);
390
391 if (!GetQosSupported())
392 {
393 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
394 }
395 // "A QoS STA that transmits a Management frame determines access category used
396 // for medium access in transmission of the Management frame as follows
397 // (If dot11QMFActivated is false or not present)
398 // — If the Management frame is individually addressed to a non-QoS STA, category
399 // AC_BE should be selected.
400 // — If category AC_BE was not selected by the previous step, category AC_VO
401 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
402 else
403 {
404 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
405 }
406}
407
408std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>
409StaWifiMac::GetAssociationRequest(bool isReassoc, uint8_t linkId) const
410{
411 NS_LOG_FUNCTION(this << isReassoc << +linkId);
412
413 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader> mgtFrame;
414
415 if (isReassoc)
416 {
418 reassoc.SetCurrentApAddress(GetBssid(linkId));
419 mgtFrame = std::move(reassoc);
420 }
421 else
422 {
423 mgtFrame = MgtAssocRequestHeader();
424 }
425
426 // lambda to set the fields of the (Re)Association Request
427 auto fill = [&](auto&& frame) {
428 frame.template Get<Ssid>() = GetSsid();
429 auto supportedRates = GetSupportedRates(linkId);
430 frame.template Get<SupportedRates>() = supportedRates.rates;
431 frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
432 frame.Capabilities() = GetCapabilities(linkId);
433 frame.SetListenInterval(0);
434 if (GetHtSupported(linkId))
435 {
436 frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
437 frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
438 }
439 if (GetVhtSupported(linkId))
440 {
441 frame.template Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
442 }
443 if (GetHeSupported())
444 {
445 frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
446 if (Is6GhzBand(linkId))
447 {
448 frame.template Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
449 }
450 }
451 if (GetEhtSupported())
452 {
453 frame.template Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
454 }
455 };
456
457 std::visit(fill, mgtFrame);
458 return mgtFrame;
459}
460
462StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
463{
464 NS_LOG_FUNCTION(this << isReassoc << +linkId);
465
467 // The Common info field of the Basic Multi-Link element carried in the (Re)Association
468 // Request frame shall include the MLD MAC address, the MLD Capabilities and Operations,
469 // and the EML Capabilities subfields, and shall not include the Link ID Info, the BSS
470 // Parameters Change Count, and the Medium Synchronization Delay Information subfields
471 // (Sec. 35.3.5.4 of 802.11be D2.0)
472 // TODO Add the MLD Capabilities and Operations subfield
473 multiLinkElement.SetMldMacAddress(GetAddress());
474
475 if (m_emlsrManager) // EMLSR Manager is only installed if EMLSR is activated
476 {
477 multiLinkElement.SetEmlsrSupported(true);
478 TimeValue time;
479 m_emlsrManager->GetAttribute("EmlsrPaddingDelay", time);
480 multiLinkElement.SetEmlsrPaddingDelay(time.Get());
481 m_emlsrManager->GetAttribute("EmlsrTransitionDelay", time);
482 multiLinkElement.SetEmlsrTransitionDelay(time.Get());
483 // When the Transition Timeout subfield is included in a frame sent by a non-AP STA
484 // affiliated with a non-AP MLD, the Transition Timeout subfield is reserved
485 // (Section 9.4.2.312.2.3 of 802.11be D2.3)
486 // The Medium Synchronization Delay Information subfield in the Common Info subfield is
487 // not present if the Basic Multi-Link element is sent by a non-AP STA. (Section
488 // 9.4.2.312.2.3 of 802.11be D3.1)
489 }
490
491 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
492 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
493 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
494 auto& mldCapabilities = multiLinkElement.GetCommonInfoBasic().m_mldCapabilities;
495 mldCapabilities.emplace();
496 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
497 mldCapabilities->srsSupport = 0;
498
499 auto ehtConfiguration = GetEhtConfiguration();
500 NS_ASSERT(ehtConfiguration);
502 ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
503
504 mldCapabilities->tidToLinkMappingSupport = static_cast<uint8_t>(negSupport.Get());
505 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
506 mldCapabilities->aarSupport = 0; // not supported yet
507
508 // For each requested link in addition to the link on which the (Re)Association Request
509 // frame is transmitted, the Link Info field of the Basic Multi-Link element carried
510 // in the (Re)Association Request frame shall contain the corresponding Per-STA Profile
511 // subelement(s).
512 for (const auto& [index, link] : GetLinks())
513 {
514 const auto& staLink = GetStaLink(link);
515
516 if (index != linkId && staLink.bssid.has_value())
517 {
518 multiLinkElement.AddPerStaProfileSubelement();
519 auto& perStaProfile = multiLinkElement.GetPerStaProfile(
520 multiLinkElement.GetNPerStaProfileSubelements() - 1);
521 // The Link ID subfield of the STA Control field of the Per-STA Profile subelement
522 // for the corresponding non-AP STA that requests a link for multi-link (re)setup
523 // with the AP MLD is set to the link ID of the AP affiliated with the AP MLD that
524 // is operating on that link. The link ID is obtained during multi-link discovery
525 perStaProfile.SetLinkId(index);
526 // For each Per-STA Profile subelement included in the Link Info field, the
527 // Complete Profile subfield of the STA Control field shall be set to 1
528 perStaProfile.SetCompleteProfile();
529 // The MAC Address Present subfield indicates the presence of the STA MAC Address
530 // subfield in the STA Info field and is set to 1 if the STA MAC Address subfield
531 // is present in the STA Info field; otherwise set to 0. An STA sets this subfield
532 // to 1 when the element carries complete profile.
533 perStaProfile.SetStaMacAddress(staLink.feManager->GetAddress());
534 perStaProfile.SetAssocRequest(GetAssociationRequest(isReassoc, index));
535 }
536 }
537
538 return multiLinkElement;
539}
540
541std::vector<TidToLinkMapping>
543{
544 NS_LOG_FUNCTION(this << apNegSupport);
545
546 auto ehtConfig = GetEhtConfiguration();
547 NS_ASSERT(ehtConfig);
548
550 ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
551
553 "Cannot request TID-to-Link Mapping if negotiation is not supported");
554
555 // store the mappings, so that we can enforce them when the AP MLD accepts them
556 m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
557 m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
558
563 !mappingValidForNegType1,
564 "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
565
566 if (apNegSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET && !mappingValidForNegType1)
567 {
568 // If the TID-to-link Mapping Negotiation Support subfield value received from a peer
569 // MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
570 // peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
571 // the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
572 // this requirement.
573 NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
576 }
577
578 std::vector<TidToLinkMapping> ret(1);
579
580 ret.back().m_control.direction = WifiDirection::DOWNLINK;
581
582 // lambda to fill the last TID-to-Link Mapping IE in the vector to return
583 auto fillIe = [&ret](const auto& mapping) {
584 ret.back().m_control.defaultMapping = mapping.empty();
585
586 for (const auto& [tid, linkSet] : mapping)
587 {
588 // At any point in time, a TID shall always be mapped to at least one setup link both
589 // in DL and UL, which means that a TID-to-link mapping change is only valid and
590 // successful if it will not result in having any TID for which the link set for DL
591 // or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
592 NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
593 ret.back().SetLinkMappingOfTid(tid, linkSet);
594 }
595 };
596
598
600 {
601 ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
602 return ret;
603 }
604
605 ret.emplace_back();
606 ret.back().m_control.direction = WifiDirection::UPLINK;
608
609 return ret;
610}
611
612void
614{
615 // find the link where the (Re)Association Request has to be sent
616 auto it = GetLinks().cbegin();
617 while (it != GetLinks().cend())
618 {
619 if (GetStaLink(it->second).sendAssocReq)
620 {
621 break;
622 }
623 it++;
624 }
625 NS_ABORT_MSG_IF(it == GetLinks().cend(),
626 "No link selected to send the (Re)Association Request");
627 uint8_t linkId = it->first;
628 auto& link = GetLink(linkId);
629 NS_ABORT_MSG_IF(!link.bssid.has_value(),
630 "No BSSID set for the link on which the (Re)Association Request is to be sent");
631
632 NS_LOG_FUNCTION(this << *link.bssid << isReassoc);
633 WifiMacHeader hdr;
635 hdr.SetAddr1(*link.bssid);
636 hdr.SetAddr2(link.feManager->GetAddress());
637 hdr.SetAddr3(*link.bssid);
638 hdr.SetDsNotFrom();
639 hdr.SetDsNotTo();
640 Ptr<Packet> packet = Create<Packet>();
641
642 auto frame = GetAssociationRequest(isReassoc, linkId);
643
644 // include a Multi-Link Element if this device has multiple links (independently
645 // of how many links will be setup) and the AP is a multi-link device;
646 // if the AP MLD has indicated a support of TID-to-link mapping negotiation, also
647 // include the TID-to-link Mapping element(s)
648 if (GetNLinks() > 1 &&
649 GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
650 {
651 auto addMle = [&](auto&& frame) {
652 frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
653 };
654 std::visit(addMle, frame);
655
657 if (const auto& mldCapabilities =
658 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
659 mldCapabilities && (negSupport = static_cast<WifiTidToLinkMappingNegSupport>(
660 mldCapabilities->get().tidToLinkMappingSupport)) >
662 {
663 auto addTlm = [&](auto&& frame) {
664 frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
665 };
666 std::visit(addTlm, frame);
667 }
668 }
669
670 if (!isReassoc)
671 {
672 packet->AddHeader(std::get<MgtAssocRequestHeader>(frame));
673 }
674 else
675 {
676 packet->AddHeader(std::get<MgtReassocRequestHeader>(frame));
677 }
678
679 if (!GetQosSupported())
680 {
681 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
682 }
683 // "A QoS STA that transmits a Management frame determines access category used
684 // for medium access in transmission of the Management frame as follows
685 // (If dot11QMFActivated is false or not present)
686 // — If the Management frame is individually addressed to a non-QoS STA, category
687 // AC_BE should be selected.
688 // — If category AC_BE was not selected by the previous step, category AC_VO
689 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
690 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(*link.bssid))
691 {
692 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
693 }
694 else
695 {
696 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
697 }
698
700 {
702 }
705}
706
707void
709{
710 NS_LOG_FUNCTION(this);
711 switch (m_state)
712 {
713 case ASSOCIATED:
714 return;
715 case SCANNING:
716 /* we have initiated active or passive scanning, continue to wait
717 and gather beacons or probe responses until the scanning timeout
718 */
719 break;
720 case UNASSOCIATED:
721 /* we were associated but we missed a bunch of beacons
722 * so we should assume we are not associated anymore.
723 * We try to initiate a scan now.
724 */
725 m_linkDown();
727 break;
728 case WAIT_ASSOC_RESP:
729 /* we have sent an association request so we do not need to
730 re-send an association request right now. We just need to
731 wait until either assoc-request-timeout or until
732 we get an association response.
733 */
734 case REFUSED:
735 /* we have sent an association request and received a negative
736 association response. We wait until someone restarts an
737 association with a given SSID.
738 */
739 break;
740 }
741}
742
743void
745{
746 NS_LOG_FUNCTION(this);
749
750 WifiScanParams scanParams;
751 scanParams.ssid = GetSsid();
752 for (const auto& [id, link] : GetLinks())
753 {
755 (link->phy->HasFixedPhyBand()) ? WifiScanParams::Channel{0, link->phy->GetPhyBand()}
757
758 scanParams.channelList.push_back(channel);
759 }
760 if (m_activeProbing)
761 {
762 scanParams.type = WifiScanType::ACTIVE;
764 scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
765 }
766 else
767 {
768 scanParams.type = WifiScanType::PASSIVE;
770 }
771
772 m_assocManager->StartScanning(std::move(scanParams));
773}
774
775void
776StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& bestAp)
777{
778 NS_LOG_FUNCTION(this);
779
780 if (!bestAp.has_value())
781 {
782 NS_LOG_DEBUG("Exhausted list of candidate AP; restart scanning");
784 return;
785 }
786
787 NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
788 UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
789 // reset info on links to setup
790 for (auto& [id, link] : GetLinks())
791 {
792 auto& staLink = GetStaLink(link);
793 staLink.sendAssocReq = false;
794 staLink.bssid = std::nullopt;
795 }
796 // send Association Request on the link where the Beacon/Probe Response was received
797 GetLink(bestAp->m_linkId).sendAssocReq = true;
798 GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
799 std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
800 // update info on links to setup (11be MLDs only)
801 const auto& mle =
802 std::visit([](auto&& frame) { return frame.template Get<MultiLinkElement>(); },
803 bestAp->m_frame);
804 std::map<uint8_t, uint8_t> swapInfo;
805 for (const auto& [localLinkId, apLinkId, bssid] : bestAp->m_setupLinks)
806 {
807 NS_ASSERT_MSG(mle, "We get here only for ML setup");
808 NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
809 << ")");
810 GetLink(localLinkId).bssid = bssid;
811 if (!mleCommonInfo)
812 {
813 mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
814 }
815 GetWifiRemoteStationManager(localLinkId)->AddStationMleCommonInfo(bssid, mleCommonInfo);
816 swapInfo.emplace(localLinkId, apLinkId);
817 }
818
819 SwapLinks(swapInfo);
820
821 // lambda to get beacon interval from Beacon or Probe Response
822 auto getBeaconInterval = [](auto&& frame) {
823 using T = std::decay_t<decltype(frame)>;
824 if constexpr (std::is_same_v<T, MgtBeaconHeader> ||
825 std::is_same_v<T, MgtProbeResponseHeader>)
826 {
827 return MicroSeconds(frame.GetBeaconIntervalUs());
828 }
829 else
830 {
831 NS_ABORT_MSG("Unexpected frame type");
832 return Seconds(0);
833 }
834 };
835 Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
836 Time delay = beaconInterval * m_maxMissedBeacons;
837 // restart beacon watchdog
839
842}
843
844void
851
852void
854{
855 NS_LOG_FUNCTION(this);
856
858 {
860 {
862 }
865 this);
866 return;
867 }
868 NS_LOG_DEBUG("beacon missed");
869 // We need to switch to the UNASSOCIATED state. However, if we are receiving a frame, wait
870 // until the RX is completed (otherwise, crashes may occur if we are receiving a MU frame
871 // because its reception requires the STA-ID). We need to check that a PHY is operating on
872 // the given link, because this may (temporarily) not be the case for EMLSR clients.
873 Time delay = Seconds(0);
874 for (const auto& [id, link] : GetLinks())
875 {
876 if (link->phy && link->phy->IsStateRx())
877 {
878 delay = std::max(delay, link->phy->GetDelayUntilIdle());
879 }
880 }
882}
883
884void
886{
887 NS_LOG_FUNCTION(this);
888
889 Mac48Address apAddr; // the AP address to trace (MLD address in case of ML setup)
890
891 for (const auto& [id, link] : GetLinks())
892 {
893 auto& bssid = GetStaLink(link).bssid;
894 if (bssid)
895 {
896 apAddr = GetWifiRemoteStationManager(id)->GetMldAddress(*bssid).value_or(*bssid);
897 }
898 bssid = std::nullopt; // link is no longer setup
899 }
900
901 NS_LOG_DEBUG("Set state to UNASSOCIATED and start scanning");
903 // cancel the association request timer (see issue #862)
905 m_deAssocLogger(apAddr);
906 m_aid = 0; // reset AID
908}
909
910void
912{
913 NS_LOG_FUNCTION(this << delay);
914
917 {
918 NS_LOG_DEBUG("really restart watchdog.");
920 }
921}
922
923bool
925{
926 return m_state == ASSOCIATED;
927}
928
929bool
931{
932 return m_state == WAIT_ASSOC_RESP;
933}
934
935std::set<uint8_t>
937{
938 if (!IsAssociated())
939 {
940 return {};
941 }
942
943 std::set<uint8_t> linkIds;
944 for (const auto& [id, link] : GetLinks())
945 {
946 if (GetStaLink(link).bssid)
947 {
948 linkIds.insert(id);
949 }
950 }
951 return linkIds;
952}
953
956{
957 for (const auto& [id, link] : GetLinks())
958 {
959 if (GetStaLink(link).bssid == remoteAddr)
960 {
961 // the remote address is the address of the (single link) AP we are associated with;
962 return link->feManager->GetAddress();
963 }
964 }
965
966 // the remote address is unknown
967 return GetAddress();
968}
969
970bool
975
976void
982
983void
985{
986 NS_LOG_FUNCTION(this << *mpdu << to << from);
987
988 auto& hdr = mpdu->GetHeader();
989
990 // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for
991 // non-broadcast data frames exchanged between two MLDs
992 auto linkIds = GetSetupLinkIds();
993 NS_ASSERT(!linkIds.empty());
994 uint8_t linkId = *linkIds.begin();
995 const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId));
996
997 hdr.SetAddr1(apMldAddr.value_or(GetBssid(linkId)));
998 hdr.SetAddr2(apMldAddr ? GetAddress() : GetFrameExchangeManager(linkId)->GetAddress());
999 hdr.SetAddr3(to);
1000 hdr.SetDsNotFrom();
1001 hdr.SetDsTo();
1002
1003 auto txop = hdr.IsQosData() ? StaticCast<Txop>(GetQosTxop(hdr.GetQosTid())) : GetTxop();
1004 NS_ASSERT(txop);
1005 txop->Queue(mpdu);
1006}
1007
1008void
1010{
1011 NS_LOG_FUNCTION(this << linkId << reason);
1012
1013 auto bssid = GetBssid(linkId);
1014 auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1015
1016 BlockUnicastTxOnLinks(reason, apAddress, {linkId});
1017 // the only type of broadcast frames that a non-AP STA can send are management frames
1018 for (const auto& [acIndex, ac] : wifiAcList)
1019 {
1020 GetMacQueueScheduler()->BlockQueues(reason,
1021 acIndex,
1024 GetFrameExchangeManager(linkId)->GetAddress(),
1025 {},
1026 {linkId});
1027 }
1028}
1029
1030void
1031StaWifiMac::UnblockTxOnLink(std::set<uint8_t> linkIds, WifiQueueBlockedReason reason)
1032{
1033 std::stringstream ss;
1034 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
1035 NS_LOG_FUNCTION(this << ss.str() << reason);
1036
1037 const auto linkId = *linkIds.cbegin();
1038 const auto bssid = GetBssid(linkId);
1039 const auto apAddress =
1040 GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1041
1042 UnblockUnicastTxOnLinks(reason, apAddress, linkIds);
1043 // the only type of broadcast frames that a non-AP STA can send are management frames
1044 for (const auto& [acIndex, ac] : wifiAcList)
1045 {
1046 GetMacQueueScheduler()->UnblockQueues(reason,
1047 acIndex,
1050 GetFrameExchangeManager(linkId)->GetAddress(),
1051 {},
1052 linkIds);
1053 }
1054}
1055
1056void
1058{
1059 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1060 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1061 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1062 Ptr<const Packet> packet = mpdu->GetPacket();
1063 NS_ASSERT(!hdr->IsCtl());
1065 : GetFrameExchangeManager(linkId)->GetAddress();
1066 if (hdr->GetAddr3() == myAddr)
1067 {
1068 NS_LOG_LOGIC("packet sent by us.");
1069 return;
1070 }
1071 if (hdr->GetAddr1() != myAddr && !hdr->GetAddr1().IsGroup())
1072 {
1073 NS_LOG_LOGIC("packet is not for us");
1074 NotifyRxDrop(packet);
1075 return;
1076 }
1077 if (hdr->IsData())
1078 {
1079 if (!IsAssociated())
1080 {
1081 NS_LOG_LOGIC("Received data frame while not associated: ignore");
1082 NotifyRxDrop(packet);
1083 return;
1084 }
1085 if (!(hdr->IsFromDs() && !hdr->IsToDs()))
1086 {
1087 NS_LOG_LOGIC("Received data frame not from the DS: ignore");
1088 NotifyRxDrop(packet);
1089 return;
1090 }
1091 std::set<Mac48Address> apAddresses; // link addresses of AP
1092 for (auto id : GetSetupLinkIds())
1093 {
1094 apAddresses.insert(GetBssid(id));
1095 }
1096 if (!apAddresses.contains(mpdu->GetHeader().GetAddr2()))
1097 {
1098 NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
1099 NotifyRxDrop(packet);
1100 return;
1101 }
1102 if (!hdr->HasData())
1103 {
1104 NS_LOG_LOGIC("Received (QoS) Null Data frame: ignore");
1105 NotifyRxDrop(packet);
1106 return;
1107 }
1108 if (hdr->IsQosData())
1109 {
1110 if (hdr->IsQosAmsdu())
1111 {
1112 NS_ASSERT(apAddresses.contains(mpdu->GetHeader().GetAddr3()));
1114 packet = nullptr;
1115 }
1116 else
1117 {
1118 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1119 }
1120 }
1121 else
1122 {
1123 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1124 }
1125 return;
1126 }
1127
1128 switch (hdr->GetType())
1129 {
1133 // This is a frame aimed at an AP, so we can safely ignore it.
1134 NotifyRxDrop(packet);
1135 break;
1136
1138 ReceiveBeacon(mpdu, linkId);
1139 break;
1140
1142 ReceiveProbeResp(mpdu, linkId);
1143 break;
1144
1147 ReceiveAssocResp(mpdu, linkId);
1148 break;
1149
1151 if (auto [category, action] = WifiActionHeader::Peek(packet);
1152 category == WifiActionHeader::PROTECTED_EHT &&
1153 action.protectedEhtAction ==
1155 {
1156 // this is handled by the EMLSR Manager
1157 break;
1158 }
1159
1160 default:
1161 // Invoke the receive handler of our parent class to deal with any other frames
1162 WifiMac::Receive(mpdu, linkId);
1163 }
1164
1165 if (m_emlsrManager)
1166 {
1167 m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
1168 }
1169}
1170
1171void
1173{
1174 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1175 const WifiMacHeader& hdr = mpdu->GetHeader();
1176 NS_ASSERT(hdr.IsBeacon());
1177
1178 NS_LOG_DEBUG("Beacon received");
1179 MgtBeaconHeader beacon;
1180 mpdu->GetPacket()->PeekHeader(beacon);
1181 const auto& capabilities = beacon.Capabilities();
1182 NS_ASSERT(capabilities.IsEss());
1183 bool goodBeacon;
1184 if (IsWaitAssocResp() || IsAssociated())
1185 {
1186 // we have to process this Beacon only if sent by the AP we are associated
1187 // with or from which we are waiting an Association Response frame
1188 auto bssid = GetLink(linkId).bssid;
1189 goodBeacon = bssid.has_value() && (hdr.GetAddr3() == *bssid);
1190 }
1191 else
1192 {
1193 // we retain this Beacon as candidate AP if the supported rates fit the
1194 // configured BSS membership selector
1195 goodBeacon = CheckSupportedRates(beacon, linkId);
1196 }
1197
1198 SnrTag snrTag;
1199 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1200 NS_ASSERT(found);
1201 ApInfo apInfo = {.m_bssid = hdr.GetAddr3(),
1202 .m_apAddr = hdr.GetAddr2(),
1203 .m_snr = snrTag.Get(),
1204 .m_frame = std::move(beacon),
1205 .m_channel = {GetCurrentChannel(linkId)},
1206 .m_linkId = linkId};
1207
1208 if (!m_beaconInfo.IsEmpty())
1209 {
1210 m_beaconInfo(apInfo);
1211 }
1212
1213 if (!goodBeacon)
1214 {
1215 NS_LOG_LOGIC("Beacon is not for us");
1216 return;
1217 }
1218 if (m_state == ASSOCIATED)
1219 {
1221 Time delay = MicroSeconds(std::get<MgtBeaconHeader>(apInfo.m_frame).GetBeaconIntervalUs() *
1223 RestartBeaconWatchdog(delay);
1224 UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1225 }
1226 else
1227 {
1228 NS_LOG_DEBUG("Beacon received from " << hdr.GetAddr2());
1229 m_assocManager->NotifyApInfo(std::move(apInfo));
1230 }
1231}
1232
1233void
1235{
1236 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1237 const WifiMacHeader& hdr = mpdu->GetHeader();
1238 NS_ASSERT(hdr.IsProbeResp());
1239
1240 NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2());
1241 MgtProbeResponseHeader probeResp;
1242 mpdu->GetPacket()->PeekHeader(probeResp);
1243 if (!CheckSupportedRates(probeResp, linkId))
1244 {
1245 return;
1246 }
1247 SnrTag snrTag;
1248 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1249 NS_ASSERT(found);
1250 m_assocManager->NotifyApInfo(ApInfo{.m_bssid = hdr.GetAddr3(),
1251 .m_apAddr = hdr.GetAddr2(),
1252 .m_snr = snrTag.Get(),
1253 .m_frame = std::move(probeResp),
1254 .m_channel = {GetCurrentChannel(linkId)},
1255 .m_linkId = linkId});
1256}
1257
1258void
1260{
1261 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1262 const WifiMacHeader& hdr = mpdu->GetHeader();
1263 NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp());
1264
1265 if (m_state != WAIT_ASSOC_RESP)
1266 {
1267 return;
1268 }
1269
1270 std::optional<Mac48Address> apMldAddress;
1271 MgtAssocResponseHeader assocResp;
1272 mpdu->GetPacket()->PeekHeader(assocResp);
1274 {
1276 }
1277 if (assocResp.GetStatusCode().IsSuccess())
1278 {
1279 m_aid = assocResp.GetAssociationId();
1280 NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed"));
1281 UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1282 NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
1283 SetBssid(hdr.GetAddr3(), linkId);
1285 if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
1286 {
1287 // this is an ML setup, trace the setup link
1288 m_setupCompleted(linkId, hdr.GetAddr3());
1289 apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
1290 NS_ASSERT(apMldAddress);
1291
1292 if (const auto& mldCapabilities =
1293 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
1294 mldCapabilities && static_cast<WifiTidToLinkMappingNegSupport>(
1295 mldCapabilities->get().tidToLinkMappingSupport) >
1297 {
1298 // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
1299 // TID-to-Link Mapping element(s) in the Association Request.
1300 if (assocResp.Get<TidToLinkMapping>().empty())
1301 {
1302 // The AP MLD did not include a TID-to-Link Mapping element in the Association
1303 // Response, hence it accepted the mapping, which we can now store.
1304 UpdateTidToLinkMapping(*apMldAddress,
1307 UpdateTidToLinkMapping(*apMldAddress,
1310
1311 // Apply the negotiated TID-to-Link Mapping (if any) for UL direction
1313 }
1314 }
1315 }
1316 else
1317 {
1318 m_assocLogger(hdr.GetAddr3());
1319 }
1320 if (!m_linkUp.IsNull())
1321 {
1322 m_linkUp();
1323 }
1324 }
1325 else
1326 {
1327 // If the link on which the (Re)Association Request frame was received cannot be
1328 // accepted by the AP MLD, the AP MLD shall treat the multi-link (re)setup as a
1329 // failure and shall not accept any requested links. If the link on which the
1330 // (Re)Association Request frame was received is accepted by the AP MLD, the
1331 // multi-link (re)setup is successful. (Sec. 35.3.5.1 of 802.11be D3.1)
1332 NS_LOG_DEBUG("association refused");
1334 StartScanning();
1335 return;
1336 }
1337
1338 // if this is an MLD, check if we can setup (other) links
1339 if (GetNLinks() > 1)
1340 {
1341 // create a list of all local Link IDs. IDs are removed as we find a corresponding
1342 // Per-STA Profile Subelements indicating successful association. Links with
1343 // remaining IDs are not setup
1344 std::list<uint8_t> setupLinks;
1345 for (const auto& [id, link] : GetLinks())
1346 {
1347 setupLinks.push_back(id);
1348 }
1349 if (assocResp.GetStatusCode().IsSuccess())
1350 {
1351 setupLinks.remove(linkId);
1352 }
1353
1354 // if a Multi-Link Element is present, check its content
1355 if (const auto& mle = assocResp.Get<MultiLinkElement>())
1356 {
1357 NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
1358 "The link on which the Association Response was received "
1359 "is not a link we requested to setup");
1360 NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
1361 "The link ID of the AP that transmitted the Association "
1362 "Response does not match the stored link ID");
1364 mle->GetMldMacAddress(),
1365 "The AP MLD MAC address in the received Multi-Link Element does not "
1366 "match the address stored in the station manager for link "
1367 << +linkId);
1368 // process the Per-STA Profile Subelements in the Multi-Link Element
1369 for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
1370 {
1371 auto& perStaProfile = mle->GetPerStaProfile(elem);
1372 uint8_t apLinkId = perStaProfile.GetLinkId();
1373 auto it = GetLinks().find(apLinkId);
1374 uint8_t staLinkid = 0;
1375 std::optional<Mac48Address> bssid;
1376 NS_ABORT_MSG_IF(it == GetLinks().cend() ||
1377 !(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
1378 "Setup for AP link ID " << apLinkId << " was not requested");
1379 NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
1380 "The BSSID in the Per-STA Profile for link ID "
1381 << +staLinkid << " does not match the stored BSSID");
1384 perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
1385 "The AP MLD MAC address in the received Multi-Link Element does not "
1386 "match the address stored in the station manager for link "
1387 << +staLinkid);
1388 // process the Association Response contained in this Per-STA Profile
1389 MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
1390 if (assoc.GetStatusCode().IsSuccess())
1391 {
1392 NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
1393 "AID should be the same for all the links");
1394 m_aid = assoc.GetAssociationId();
1395 NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
1396 UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
1397 SetBssid(*bssid, staLinkid);
1398 m_setupCompleted(staLinkid, *bssid);
1400 apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
1401 if (!m_linkUp.IsNull())
1402 {
1403 m_linkUp();
1404 }
1405 }
1406 // remove the ID of the link we setup
1407 setupLinks.remove(staLinkid);
1408 }
1409 }
1410 // remaining links in setupLinks are not setup and hence must be disabled
1411 for (const auto& id : setupLinks)
1412 {
1413 GetLink(id).bssid = std::nullopt;
1414 GetLink(id).phy->SetOffMode();
1415 }
1416 if (apMldAddress)
1417 {
1418 // this is an ML setup, trace the MLD address of the AP (only once)
1419 m_assocLogger(*apMldAddress);
1420 }
1421 }
1422
1423 // the station that associated with the AP may have dissociated and then associated again.
1424 // In this case, the station may store packets from the previous period in which it was
1425 // associated. Have the station restart access if it has packets queued.
1426 for (const auto& [id, link] : GetLinks())
1427 {
1428 if (GetStaLink(link).bssid)
1429 {
1430 if (const auto txop = GetTxop())
1431 {
1432 txop->StartAccessAfterEvent(id,
1435 }
1436 for (const auto& [acIndex, ac] : wifiAcList)
1437 {
1438 if (const auto edca = GetQosTxop(acIndex))
1439 {
1440 edca->StartAccessAfterEvent(id,
1443 }
1444 }
1445 }
1446 }
1447
1449}
1450
1451void
1453{
1454 NS_LOG_FUNCTION(this << linkId);
1455
1456 // STAs operating on setup links may need to transition to a new PM mode after the
1457 // acknowledgement of the Association Response. For this purpose, we connect a callback to
1458 // the PHY TX begin trace to catch the Ack transmitted after the Association Response.
1460 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
1461 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
1462 psduMap.begin()->second->GetHeader(0).IsAck(),
1463 "Expected a Normal Ack after Association Response frame");
1464
1465 auto ackDuration =
1466 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
1467
1468 for (const auto& [id, lnk] : GetLinks())
1469 {
1470 auto& link = GetStaLink(lnk);
1471
1472 if (!link.bssid)
1473 {
1474 // link has not been setup
1475 continue;
1476 }
1477
1478 if (id == linkId)
1479 {
1480 /**
1481 * When a link becomes enabled for a non-AP STA that is affiliated with a
1482 * non-AP MLD after successful association with an AP MLD with (Re)Association
1483 * Request/Response frames transmitted on that link [..], the power management
1484 * mode of the non-AP STA, immediately after the acknowledgement of the
1485 * (Re)Association Response frame [..], is active mode.
1486 * (Sec. 35.3.7.1.4 of 802.11be D3.0)
1487 */
1488 // if the user requested this link to be in powersave mode, we have to
1489 // switch PM mode
1490 if (link.pmMode == WIFI_PM_POWERSAVE)
1491 {
1492 Simulator::Schedule(ackDuration,
1494 this,
1495 std::pair<bool, uint8_t>{true, id});
1496 }
1497 link.pmMode = WIFI_PM_ACTIVE;
1498 }
1499 else
1500 {
1501 /**
1502 * When a link becomes enabled for a non-AP STA that is affiliated with a
1503 * non-AP MLD after successful association with an AP MLD with (Re)Association
1504 * Request/Response frames transmitted on another link [..], the power
1505 * management mode of the non-AP STA, immediately after the acknowledgement of
1506 * the (Re)Association Response frame [..], is power save mode, and its power
1507 * state is doze. (Sec. 35.3.7.1.4 of 802.11be D3.0)
1508 */
1509 // if the user requested this link to be in active mode, we have to
1510 // switch PM mode
1511 if (link.pmMode == WIFI_PM_ACTIVE)
1512 {
1513 Simulator::Schedule(ackDuration,
1515 this,
1516 std::pair<bool, uint8_t>{false, id});
1517 }
1518 link.pmMode = WIFI_PM_POWERSAVE;
1519 }
1520 }
1521 });
1522
1523 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
1524 // after its transmission begins
1525 auto phy = GetLink(linkId).phy;
1526 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
1527 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
1528 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
1529}
1530
1531bool
1532StaWifiMac::CheckSupportedRates(std::variant<MgtBeaconHeader, MgtProbeResponseHeader> frame,
1533 uint8_t linkId)
1534{
1535 NS_LOG_FUNCTION(this << +linkId);
1536
1537 // lambda to invoke on the current frame variant
1538 auto check = [&](auto&& mgtFrame) -> bool {
1539 // check supported rates
1540 NS_ASSERT(mgtFrame.template Get<SupportedRates>());
1541 const auto rates = AllSupportedRates{*mgtFrame.template Get<SupportedRates>(),
1542 mgtFrame.template Get<ExtendedSupportedRatesIE>()};
1543 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1544 {
1545 if (!rates.IsBssMembershipSelectorRate(selector))
1546 {
1547 NS_LOG_DEBUG("Supported rates do not fit with the BSS membership selector");
1548 return false;
1549 }
1550 }
1551
1552 return true;
1553 };
1554
1555 return std::visit(check, frame);
1556}
1557
1558void
1560 const Mac48Address& apAddr,
1561 const Mac48Address& bssid,
1562 uint8_t linkId)
1563{
1564 NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId);
1565
1566 // ERP Information is not present in Association Response frames
1567 const std::optional<ErpInformation>* erpInformation = nullptr;
1568
1569 if (const auto* beacon = std::get_if<MgtBeaconHeader>(&frame))
1570 {
1571 erpInformation = &beacon->Get<ErpInformation>();
1572 }
1573 else if (const auto* probe = std::get_if<MgtProbeResponseHeader>(&frame))
1574 {
1575 erpInformation = &probe->Get<ErpInformation>();
1576 }
1577
1578 // lambda processing Information Elements included in all frame types
1579 auto commonOps = [&](auto&& frame) {
1580 const auto& capabilities = frame.Capabilities();
1581 NS_ASSERT(frame.template Get<SupportedRates>());
1582 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1583 frame.template Get<ExtendedSupportedRatesIE>()};
1584 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1585 {
1586 if (rates.IsSupportedRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1587 {
1588 GetWifiRemoteStationManager(linkId)->AddSupportedMode(apAddr, mode);
1589 if (rates.IsBasicRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1590 {
1591 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
1592 }
1593 }
1594 }
1595
1596 bool isShortPreambleEnabled = capabilities.IsShortPreamble();
1597 if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId))
1598 {
1599 isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode();
1600 if ((*erpInformation)->GetUseProtection() != 0)
1601 {
1602 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(true);
1603 }
1604 else
1605 {
1606 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(false);
1607 }
1608 if (capabilities.IsShortSlotTime() == true)
1609 {
1610 // enable short slot time
1611 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1612 }
1613 else
1614 {
1615 // disable short slot time
1616 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1617 }
1618 }
1619 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled);
1620 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1621 capabilities.IsShortSlotTime());
1622
1623 if (!GetQosSupported())
1624 {
1625 return;
1626 }
1627 /* QoS station */
1628 bool qosSupported = false;
1629 const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
1630 if (edcaParameters.has_value())
1631 {
1632 qosSupported = true;
1633 // The value of the TXOP Limit field is specified as an unsigned integer, with the least
1634 // significant octet transmitted first, in units of 32 μs.
1636 edcaParameters->GetBeCWmin(),
1637 edcaParameters->GetBeCWmax(),
1638 edcaParameters->GetBeAifsn(),
1639 32 * MicroSeconds(edcaParameters->GetBeTxopLimit())},
1640 linkId);
1642 edcaParameters->GetBkCWmin(),
1643 edcaParameters->GetBkCWmax(),
1644 edcaParameters->GetBkAifsn(),
1645 32 * MicroSeconds(edcaParameters->GetBkTxopLimit())},
1646 linkId);
1648 edcaParameters->GetViCWmin(),
1649 edcaParameters->GetViCWmax(),
1650 edcaParameters->GetViAifsn(),
1651 32 * MicroSeconds(edcaParameters->GetViTxopLimit())},
1652 linkId);
1654 edcaParameters->GetVoCWmin(),
1655 edcaParameters->GetVoCWmax(),
1656 edcaParameters->GetVoAifsn(),
1657 32 * MicroSeconds(edcaParameters->GetVoTxopLimit())},
1658 linkId);
1659 }
1660 GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
1661
1662 if (GetHtSupported(linkId))
1663 {
1664 /* HT station */
1665 if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
1666 htCapabilities.has_value())
1667 {
1668 GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
1669 *htCapabilities);
1670 }
1671 else
1672 {
1673 GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
1674 }
1675 // TODO: process ExtendedCapabilities
1676 // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
1677 }
1678
1679 // we do not return if VHT is not supported because HE STAs operating in
1680 // the 2.4 GHz band do not support VHT
1681 if (GetVhtSupported(linkId))
1682 {
1683 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1684 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1685 // to check whether it supports VHT
1686 if (vhtCapabilities.has_value() &&
1687 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1688 {
1689 GetWifiRemoteStationManager(linkId)->AddStationVhtCapabilities(apAddr,
1690 *vhtCapabilities);
1691 // const auto& vhtOperation = frame.GetVhtOperation ();
1692 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_VHT))
1693 {
1694 if (vhtCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1695 {
1696 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1697 }
1698 }
1699 }
1700 }
1701
1702 if (!GetHeSupported())
1703 {
1704 return;
1705 }
1706 /* HE station */
1707 const auto& heCapabilities = frame.template Get<HeCapabilities>();
1708 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1709 {
1710 GetWifiRemoteStationManager(linkId)->AddStationHeCapabilities(apAddr, *heCapabilities);
1711 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_HE))
1712 {
1713 if (heCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1714 {
1715 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1716 }
1717 }
1718 if (const auto& heOperation = frame.template Get<HeOperation>();
1719 heOperation.has_value())
1720 {
1721 GetHeConfiguration()->SetAttribute(
1722 "BssColor",
1723 UintegerValue(heOperation->m_bssColorInfo.m_bssColor));
1724 }
1725 }
1726
1727 const auto& muEdcaParameters = frame.template Get<MuEdcaParameterSet>();
1728 if (muEdcaParameters.has_value())
1729 {
1731 muEdcaParameters->GetMuCwMin(AC_BE),
1732 muEdcaParameters->GetMuCwMax(AC_BE),
1733 muEdcaParameters->GetMuAifsn(AC_BE),
1734 muEdcaParameters->GetMuEdcaTimer(AC_BE)},
1735 linkId);
1737 muEdcaParameters->GetMuCwMin(AC_BK),
1738 muEdcaParameters->GetMuCwMax(AC_BK),
1739 muEdcaParameters->GetMuAifsn(AC_BK),
1740 muEdcaParameters->GetMuEdcaTimer(AC_BK)},
1741 linkId);
1743 muEdcaParameters->GetMuCwMin(AC_VI),
1744 muEdcaParameters->GetMuCwMax(AC_VI),
1745 muEdcaParameters->GetMuAifsn(AC_VI),
1746 muEdcaParameters->GetMuEdcaTimer(AC_VI)},
1747 linkId);
1749 muEdcaParameters->GetMuCwMin(AC_VO),
1750 muEdcaParameters->GetMuCwMax(AC_VO),
1751 muEdcaParameters->GetMuAifsn(AC_VO),
1752 muEdcaParameters->GetMuEdcaTimer(AC_VO)},
1753 linkId);
1754 }
1755
1756 if (Is6GhzBand(linkId))
1757 {
1758 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
1759 {
1760 GetWifiRemoteStationManager(linkId)->AddStationHe6GhzCapabilities(
1761 apAddr,
1762 *he6GhzCapabilities);
1763 }
1764 }
1765
1766 if (!GetEhtSupported())
1767 {
1768 return;
1769 }
1770 /* EHT station */
1771 const auto& ehtCapabilities = frame.template Get<EhtCapabilities>();
1772 // TODO: once we support non constant rate managers, we should add checks here whether EHT
1773 // is supported by the peer
1774 GetWifiRemoteStationManager(linkId)->AddStationEhtCapabilities(apAddr, *ehtCapabilities);
1775
1776 if (const auto& mle = frame.template Get<MultiLinkElement>(); mle && m_emlsrManager)
1777 {
1778 if (mle->HasEmlCapabilities())
1779 {
1780 m_emlsrManager->SetTransitionTimeout(mle->GetTransitionTimeout());
1781 }
1782 if (const auto& common = mle->GetCommonInfoBasic(); common.m_mediumSyncDelayInfo)
1783 {
1784 m_emlsrManager->SetMediumSyncDuration(common.GetMediumSyncDelayTimer());
1785 m_emlsrManager->SetMediumSyncOfdmEdThreshold(common.GetMediumSyncOfdmEdThreshold());
1786 m_emlsrManager->SetMediumSyncMaxNTxops(common.GetMediumSyncMaxNTxops());
1787 }
1788 }
1789 };
1790
1791 // process Information Elements included in the current frame variant
1792 std::visit(commonOps, frame);
1793}
1794
1795void
1796StaWifiMac::SetPowerSaveMode(const std::pair<bool, uint8_t>& enableLinkIdPair)
1797{
1798 const auto [enable, linkId] = enableLinkIdPair;
1799 NS_LOG_FUNCTION(this << enable << linkId);
1800
1801 auto& link = GetLink(linkId);
1802
1803 if (!IsAssociated())
1804 {
1805 NS_LOG_DEBUG("Not associated yet, record the PM mode to switch to upon association");
1806 link.pmMode = enable ? WIFI_PM_POWERSAVE : WIFI_PM_ACTIVE;
1807 return;
1808 }
1809
1810 if (!link.bssid)
1811 {
1812 NS_LOG_DEBUG("Link " << +linkId << " has not been setup, ignore request");
1813 return;
1814 }
1815
1816 if ((enable && link.pmMode == WIFI_PM_POWERSAVE) || (!enable && link.pmMode == WIFI_PM_ACTIVE))
1817 {
1818 NS_LOG_DEBUG("No PM mode change needed");
1819 return;
1820 }
1821
1823
1824 // reschedule a call to this function to make sure that the PM mode switch
1825 // is eventually completed
1828 this,
1829 enableLinkIdPair);
1830
1831 if (HasFramesToTransmit(linkId))
1832 {
1833 NS_LOG_DEBUG("Next transmitted frame will be sent with PM=" << enable);
1834 return;
1835 }
1836
1837 // No queued frames. Enqueue a Data Null frame to inform the AP of the PM mode change
1839
1840 hdr.SetAddr1(GetBssid(linkId));
1842 hdr.SetAddr3(GetBssid(linkId));
1843 hdr.SetDsNotFrom();
1844 hdr.SetDsTo();
1845 enable ? hdr.SetPowerManagement() : hdr.SetNoPowerManagement();
1846 if (GetQosSupported())
1847 {
1849 }
1850 else
1851 {
1853 }
1854}
1855
1857StaWifiMac::GetPmMode(uint8_t linkId) const
1858{
1859 return GetLink(linkId).pmMode;
1860}
1861
1862void
1864{
1865 NS_LOG_FUNCTION(this << *mpdu);
1866
1867 auto linkId = GetLinkIdByAddress(mpdu->GetHeader().GetAddr2());
1868
1869 if (!linkId)
1870 {
1871 // the given MPDU may be the original copy containing MLD addresses and not carrying
1872 // a valid PM bit (which is set on the aliases).
1873 auto linkIds = mpdu->GetInFlightLinkIds();
1874 NS_ASSERT_MSG(!linkIds.empty(),
1875 "The TA of the acked MPDU (" << *mpdu
1876 << ") is not a link "
1877 "address and the MPDU is not inflight");
1878 // in case the ack'ed MPDU is inflight on multiple links, we cannot really know if
1879 // it was received by the AP on all links or only on some links. Hence, we only
1880 // consider the first link ID in the set, given that in the most common case of MPDUs
1881 // that cannot be sent concurrently on multiple links, there will be only one link ID
1882 linkId = *linkIds.begin();
1883 mpdu = GetTxopQueue(mpdu->GetQueueAc())->GetAlias(mpdu, *linkId);
1884 }
1885
1886 auto& link = GetLink(*linkId);
1887 const WifiMacHeader& hdr = mpdu->GetHeader();
1888
1889 // we received an acknowledgment while switching PM mode; the PM mode change is effective now
1890 if (hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_PS)
1891 {
1892 link.pmMode = WIFI_PM_POWERSAVE;
1893 }
1894 else if (!hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_ACTIVE)
1895 {
1896 link.pmMode = WIFI_PM_ACTIVE;
1897 }
1898}
1899
1902{
1903 AllSupportedRates rates;
1904 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1905 {
1906 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
1907 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
1908 rates.AddSupportedRate(modeDataRate);
1909 }
1910 if (GetHtSupported(linkId))
1911 {
1912 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1913 {
1914 rates.AddBssMembershipSelectorRate(selector);
1915 }
1916 }
1917 return rates;
1918}
1919
1921StaWifiMac::GetCapabilities(uint8_t linkId) const
1922{
1923 CapabilityInformation capabilities;
1924 capabilities.SetShortPreamble(GetWifiPhy(linkId)->GetShortPhyPreambleSupported() ||
1925 GetErpSupported(linkId));
1927 return capabilities;
1928}
1929
1930void
1932{
1933 m_state = value;
1934}
1935
1936void
1937StaWifiMac::SetEdcaParameters(const EdcaParams& params, uint8_t linkId)
1938{
1939 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1940 edca->SetMinCw(params.cwMin, linkId);
1941 edca->SetMaxCw(params.cwMax, linkId);
1942 edca->SetAifsn(params.aifsn, linkId);
1943 edca->SetTxopLimit(params.txopLimit, linkId);
1944}
1945
1946void
1947StaWifiMac::SetMuEdcaParameters(const MuEdcaParams& params, uint8_t linkId)
1948{
1949 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1950 edca->SetMuCwMin(params.cwMin, linkId);
1951 edca->SetMuCwMax(params.cwMax, linkId);
1952 edca->SetMuAifsn(params.aifsn, linkId);
1953 edca->SetMuEdcaTimer(params.muEdcaTimer, linkId);
1954}
1955
1956void
1958{
1959 NS_LOG_FUNCTION(this);
1960 if (IsAssociated())
1961 {
1962 NS_LOG_DEBUG("PHY capabilities changed: send reassociation request");
1965 }
1966}
1967
1968/**
1969 * Initial configuration:
1970 *
1971 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
1972 * Link A │FEM│RSM│CAM│◄──────►│Main├──────►│Channel│
1973 * │ │ │ │ │PHY │ │ A │
1974 * └───┴───┴───┘ └────┘ └───────┘
1975 *
1976 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
1977 * Link B │FEM│RSM│CAM│ │Aux │ │Channel│
1978 * │ │ │ │◄──────►│PHY ├──────►│ B │
1979 * └───┴───┴───┘ └────┘ └───────┘
1980 *
1981 * A link switching/swapping is notified by the EMLSR Manager and the Channel Access Manager
1982 * (CAM) notifies us that a first PHY (i.e., the Main PHY) switches to Channel B. We connect
1983 * the Main PHY to the MAC stack B:
1984 *
1985 *
1986 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
1987 * Link A │FEM│RSM│CAM│ ┌───►│Main├───┐ │Channel│
1988 * │ │ │ │ │ │PHY │ │ │ A │
1989 * └───┴───┴───┘ │ └────┘ │ └───────┘
1990 * │ │
1991 * ┌───┬───┬───┐ │ ┌────┐ │ ┌───────┐
1992 * Link B │FEM│RSM│CAM│◄──┘ │Aux │ └──►│Channel│
1993 * │ │ │ │◄─ ─ ─ ─│PHY ├──────►│ B │
1994 * └───┴───┴───┘INACTIVE└────┘ └───────┘
1995 *
1996 * MAC stack B keeps a PHY listener associated with the Aux PHY, even though it is inactive,
1997 * meaning that the PHY listener will only notify channel switches (no CCA, no RX).
1998 * If the EMLSR Manager requested a link switching, this configuration will be kept until
1999 * further requests. If the EMLSR Manager requested a link swapping, link B's CAM will be
2000 * notified by its (inactive) PHY listener upon the channel switch performed by the Aux PHY.
2001 * In this case, we remove the inactive PHY listener and connect the Aux PHY to MAC stack A:
2002 *
2003 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2004 * Link A │FEM│RSM│CAM│◄─┐ ┌──►│Main├───┐ │Channel│
2005 * │ │ │ │ │ │ │PHY │ ┌─┼──►│ A │
2006 * └───┴───┴───┘ │ │ └────┘ │ │ └───────┘
2007 * │ │ │ │
2008 * ┌───┬───┬───┐ │ │ ┌────┐ │ │ ┌───────┐
2009 * Link B │FEM│RSM│CAM│◄─┼─┘ │Aux │ │ └──►│Channel│
2010 * │ │ │ │ └────►│PHY ├─┘ │ B │
2011 * └───┴───┴───┘ └────┘ └───────┘
2012 */
2013
2014void
2016{
2017 NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
2018
2019 // If the PHY is switching channel to operate on another link, then it is no longer operating
2020 // on the current link. If any link (other than the current link) points to the PHY that is
2021 // switching channel, reset the phy pointer of the link
2022 for (auto& [id, link] : GetLinks())
2023 {
2024 if (link->phy == phy && id != linkId)
2025 {
2026 link->phy = nullptr;
2027 }
2028 }
2029
2030 // lambda to connect the PHY to the new link
2031 auto connectPhy = [=, this]() mutable {
2032 auto& newLink = GetLink(linkId);
2033 // The MAC stack associated with the new link uses the given PHY
2034 newLink.phy = phy;
2035 // Setup a PHY listener for the given PHY on the CAM associated with the new link
2036 newLink.channelAccessManager->SetupPhyListener(phy);
2038 if (m_emlsrManager->GetCamStateReset())
2039 {
2040 newLink.channelAccessManager->ResetState();
2041 }
2042 // Disconnect the FEM on the new link from the current PHY
2043 newLink.feManager->ResetPhy();
2044 // Connect the FEM on the new link to the given PHY
2045 newLink.feManager->SetWifiPhy(phy);
2046 // Connect the station manager on the new link to the given PHY
2047 newLink.stationManager->SetupPhy(phy);
2048 };
2049
2050 // cancel any pending event for the given PHY to switch link
2051 if (auto eventIt = m_emlsrLinkSwitch.find(phy->GetPhyId()); eventIt != m_emlsrLinkSwitch.end())
2052 {
2053 eventIt->second.Cancel();
2054 m_emlsrLinkSwitch.erase(eventIt);
2055 }
2056
2057 // if there is no PHY operating on the new link, connect the PHY to the new link now.
2058 // Otherwise, wait until the channel switch is completed, so that the PHY operating on the new
2059 // link can possibly continue receiving frames in the meantime.
2060 if (!GetLink(linkId).phy)
2061 {
2062 connectPhy();
2063 }
2064 else
2065 {
2066 m_emlsrLinkSwitch.emplace(phy->GetPhyId(), Simulator::Schedule(delay, connectPhy));
2067 }
2068}
2069
2070void
2072{
2073 NS_LOG_FUNCTION(this << +linkId);
2074
2076
2077 if (IsInitialized() && IsAssociated())
2078 {
2079 Disassociated();
2080 }
2081
2082 // notify association manager
2083 m_assocManager->NotifyChannelSwitched(linkId);
2084}
2085
2086std::ostream&
2087operator<<(std::ostream& os, const StaWifiMac::ApInfo& apInfo)
2088{
2089 os << "BSSID=" << apInfo.m_bssid << ", AP addr=" << apInfo.m_apAddr << ", SNR=" << apInfo.m_snr
2090 << ", Channel={" << apInfo.m_channel.number << "," << apInfo.m_channel.band
2091 << "}, Link ID=" << +apInfo.m_linkId << ", Frame=[";
2092 std::visit([&os](auto&& frame) { frame.Print(os); }, apInfo.m_frame);
2093 os << "]";
2094 return os;
2095}
2096
2097} // namespace ns3
A container for one type of attribute.
Base class for Callback class.
Definition callback.h:344
Callback template class.
Definition callback.h:422
bool IsNull() const
Check for null implementation.
Definition callback.h:555
void SetShortSlotTime(bool shortSlotTime)
Set the short slot time bit in the capability information field.
void SetShortPreamble(bool shortPreamble)
Set the short preamble bit in the capability information field.
The IEEE 802.11be EHT Capabilities.
Hold variables of type enum.
Definition enum.h:52
T Get() const
Definition enum.h:87
The ErpInformation Information Element.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition event-id.cc:58
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
The HE 6 GHz Band Capabilities (IEEE 802.11ax-2021 9.4.2.263)
The IEEE 802.11ax HE Capabilities.
The HT Capabilities Information Element.
an EUI-48 address
bool IsGroup() const
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address GetBroadcast()
Implement the header for management frames of type association request.
Implement the header for management frames of type association and reassociation response.
StatusCode GetStatusCode()
Return the status code.
uint16_t GetAssociationId() const
Return the association ID.
Implement the header for management frames of type beacon.
Implement the header for management frames of type probe request.
Implement the header for management frames of type probe response.
CapabilityInformation & Capabilities()
Implement the header for management frames of type reassociation request.
void SetCurrentApAddress(Mac48Address currentApAddr)
Set the address of the current access point.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
bool IsInitialized() const
Check if the object has been initialized.
Definition object.cc:240
AttributeValue implementation for Pair.
Definition pair.h:54
Smart pointer class similar to boost::intrusive_ptr.
virtual double GetValue()=0
Get the next random value drawn from the distribution.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
double Get() const
Return the SNR value.
Definition snr-tag.cc:79
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
The Wifi MAC high model for a non-AP STA in a BSS.
std::set< uint8_t > GetSetupLinkIds() const
Get the IDs of the setup links (if any).
void ScanningTimeout(const std::optional< ApInfo > &bestAp)
This method is called after wait beacon timeout or wait probe request timeout has occurred.
Time m_waitBeaconTimeout
wait beacon timeout
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
void SetPowerSaveMode(const std::pair< bool, uint8_t > &enableLinkIdPair)
Enable or disable Power Save mode on the given link.
Ptr< WifiAssocManager > m_assocManager
Association Manager.
void DoCompleteConfig() override
Allow subclasses to complete the configuration of the MAC layer components.
bool m_activeProbing
active probing
void DoInitialize() override
Initialize() implementation.
void SetAssocManager(Ptr< WifiAssocManager > assocManager)
Set the Association Manager.
bool CanForwardPacketsTo(Mac48Address to) const override
Return true if packets can be forwarded to the given destination, false otherwise.
std::unique_ptr< LinkEntity > CreateLinkEntity() const override
Create a LinkEntity object.
void SetState(MacState value)
Set the current MAC state.
Time m_beaconWatchdogEnd
beacon watchdog end
AllSupportedRates GetSupportedRates(uint8_t linkId) const
Return an instance of SupportedRates that contains all rates that we support including HT rates.
void SetEdcaParameters(const EdcaParams &params, uint8_t linkId)
Set the EDCA parameters for the given link.
TracedCallback< Mac48Address > m_deAssocLogger
disassociation logger
MacState
The current MAC state of the STA.
void NotifyChannelSwitching(uint8_t linkId) override
Notify that channel on the given link has been switched.
bool GetActiveProbing() const
Return whether active probing is enabled.
EventId m_beaconWatchdog
beacon watchdog
void PhyCapabilitiesChanged()
Indicate that PHY capabilities have changed.
StaLinkEntity & GetStaLink(const std::unique_ptr< WifiMac::LinkEntity > &link) const
Cast the given LinkEntity object to StaLinkEntity.
void ReceiveProbeResp(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Probe Response frame received on the given link.
void SetPmModeAfterAssociation(uint8_t linkId)
Set the Power Management mode of the setup links after association.
WifiScanParams::Channel GetCurrentChannel(uint8_t linkId) const
Get the current primary20 channel used on the given link as a (channel number, PHY band) pair.
uint16_t GetAssociationId() const
Return the association ID.
void TryToEnsureAssociated()
Try to ensure that we are associated with an AP by taking an appropriate action depending on the curr...
void ReceiveAssocResp(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the (Re)Association Response frame received on the given link.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, uint8_t linkId, Time delay)
Notify that the given PHY switched channel to operate on another EMLSR link.
std::variant< MgtAssocRequestHeader, MgtReassocRequestHeader > GetAssociationRequest(bool isReassoc, uint8_t linkId) const
Get the (Re)Association Request frame to send on a given link.
static TypeId GetTypeId()
Get the type ID.
void DoDispose() override
Destructor implementation.
void SendProbeRequest(uint8_t linkId)
Enqueue a probe request packet for transmission on the given link.
void BlockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
Block transmissions on the given link for the given reason.
std::map< uint8_t, EventId > m_emlsrLinkSwitch
maps PHY ID to the event scheduled to switch the corresponding PHY to a new EMLSR link
StaLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
uint32_t m_maxMissedBeacons
maximum missed beacons
TracedCallback< uint8_t, Mac48Address > m_setupCompleted
link setup completed logger
TracedCallback< Mac48Address > m_assocLogger
association logger
void SetWifiPhys(const std::vector< Ptr< WifiPhy > > &phys) override
void SetMuEdcaParameters(const MuEdcaParams &params, uint8_t linkId)
Set the MU EDCA parameters for the given link.
TracedCallback< uint8_t, Mac48Address > m_setupCanceled
link setup canceled logger
void NotifyEmlsrModeChanged(const std::set< uint8_t > &linkIds)
Notify the MAC that EMLSR mode has changed on the given set of links.
bool CheckSupportedRates(std::variant< MgtBeaconHeader, MgtProbeResponseHeader > frame, uint8_t linkId)
Determine whether the supported rates indicated in a given Beacon frame or Probe Response frame fit w...
Mac48Address DoGetLocalAddress(const Mac48Address &remoteAddr) const override
This method is called if this device is an MLD to determine the MAC address of the affiliated STA use...
void RestartBeaconWatchdog(Time delay)
Restarts the beacon timer.
void SetEmlsrManager(Ptr< EmlsrManager > emlsrManager)
Set the EMLSR Manager.
void NotifyDropPacketToEnqueue(Ptr< Packet > packet, Mac48Address to) override
Allow subclasses to take actions when a packet to enqueue has been dropped.
Time m_pmModeSwitchTimeout
PM mode switch timeout.
void Disassociated()
Set the state to unassociated and try to associate again.
Ptr< EmlsrManager > GetEmlsrManager() const
void TxOk(Ptr< const WifiMpdu > mpdu)
Notify that the MPDU we sent was successfully received by the receiver (i.e.
void Receive(Ptr< const WifiMpdu > mpdu, uint8_t linkId) override
This method acts as the MacRxMiddle receive callback and is invoked to notify us that a frame has bee...
WifiTidLinkMapping m_ulTidLinkMappingInAssocReq
store the UL TID-to-Link Mapping included in the Association Request frame
WifiPowerManagementMode GetPmMode(uint8_t linkId) const
Ptr< RandomVariableStream > m_probeDelay
RandomVariable used to randomize the time of the first Probe Response on each channel.
TracedCallback< ApInfo > m_beaconInfo
beacon info logger
void MissedBeacons()
This method is called after we have not received a beacon from the AP on any link.
uint16_t m_aid
Association AID.
MacState m_state
MAC state.
bool IsEmlsrLink(uint8_t linkId) const
void StartScanning()
Start the scanning process which trigger active or passive scanning based on the active probing flag.
std::vector< TidToLinkMapping > GetTidToLinkMappingElements(WifiTidToLinkMappingNegSupport apNegSupport)
TracedCallback< Time > m_beaconArrival
beacon arrival logger
void UnblockTxOnLink(std::set< uint8_t > linkIds, WifiQueueBlockedReason reason)
Unblock transmissions on the given links for the given reason.
void AssocRequestTimeout()
This method is called after the association timeout occurred.
void Enqueue(Ptr< WifiMpdu > mpdu, Mac48Address to, Mac48Address from) override
Ptr< EmlsrManager > m_emlsrManager
EMLSR Manager.
void UpdateApInfo(const MgtFrameType &frame, const Mac48Address &apAddr, const Mac48Address &bssid, uint8_t linkId)
Update associated AP's information from the given management frame (Beacon, Probe Response or Associa...
Time m_assocRequestTimeout
association request timeout
void ReceiveBeacon(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Beacon frame received on the given link.
Time m_probeRequestTimeout
probe request timeout
void SetActiveProbing(bool enable)
Enable or disable active probing.
std::variant< MgtBeaconHeader, MgtProbeResponseHeader, MgtAssocResponseHeader > MgtFrameType
type of the management frames used to get info about APs
CapabilityInformation GetCapabilities(uint8_t linkId) const
Return the Capability information for the given link.
bool IsAssociated() const
Return whether we are associated with an AP.
~StaWifiMac() override
bool IsWaitAssocResp() const
Return whether we are waiting for an association response from an AP.
MultiLinkElement GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
Return the Multi-Link Element to include in the management frames transmitted on the given link.
EventId m_assocRequestEvent
association request event
void SendAssociationRequest(bool isReassoc)
Forward an association or reassociation request packet to the DCF.
WifiTidLinkMapping m_dlTidLinkMappingInAssocReq
store the DL TID-to-Link Mapping included in the Association Request frame
bool IsSuccess() const
Return whether the status code is success.
Hold variables of type string.
Definition string.h:45
The Supported Rates Information Element.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ US
microsecond
Definition nstime.h:107
Time Get() const
Definition time.cc:519
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition txop.h:390
virtual void Queue(Ptr< WifiMpdu > mpdu)
Definition txop.cc:612
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
Definition txop.h:392
a unique identifier for an interface.
Definition type-id.h:48
@ ATTR_GET
The attribute can be read.
Definition type-id.h:53
@ ATTR_SET
The attribute can be written.
Definition type-id.h:54
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
@ OBSOLETE
Attribute or trace source is not used anymore; simulation fails.
Definition type-id.h:65
Hold an unsigned integer type.
Definition uinteger.h:34
The IEEE 802.11ac VHT Capabilities.
static std::pair< CategoryValue, ActionValue > Peek(Ptr< const Packet > pkt)
Peek an Action header from the given packet.
Implements the IEEE 802.11 MAC header.
bool IsQosAmsdu() const
Check if the A-MSDU present bit is set in the QoS control field.
Mac48Address GetAddr3() const
Return the address in the Address 3 field.
bool IsBeacon() const
Return true if the header is a Beacon header.
bool IsAssocResp() const
Return true if the header is an Association Response header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
bool IsCtl() const
Return true if the Type is Control.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsProbeResp() const
Return true if the header is a Probe Response header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
bool IsData() const
Return true if the Type is DATA.
bool IsReassocResp() const
Return true if the header is a Reassociation Response header.
void SetDsTo()
Set the To DS bit in the Frame Control field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
bool IsPowerManagement() const
Return if the Power Management bit is set.
void SetPowerManagement()
Set the Power Management bit in the Frame Control field.
void SetNoPowerManagement()
Un-set the Power Management bit in the Frame Control field.
base class for all MAC-level wifi objects.
Definition wifi-mac.h:89
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition wifi-mac.cc:996
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition wifi-mac.cc:637
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition wifi-mac.cc:686
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition wifi-mac.cc:1798
Mac48Address GetBssid(uint8_t linkId) const
Definition wifi-mac.cc:532
Ptr< HeConfiguration > GetHeConfiguration() const
Definition wifi-mac.cc:1915
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition wifi-mac.cc:1072
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition wifi-mac.cc:557
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition wifi-mac.cc:2184
Callback< void > m_linkDown
Callback when a link is down.
Definition wifi-mac.h:942
bool GetQosSupported() const
Return whether the device supports QoS.
Definition wifi-mac.cc:1380
Ptr< Txop > m_txop
TXOP used for transmission of frames to non-QoS peers.
Definition wifi-mac.h:938
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition wifi-mac.cc:680
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition wifi-mac.cc:1087
void SwapLinks(std::map< uint8_t, uint8_t > links)
Swap the links based on the information included in the given map.
Definition wifi-mac.cc:1149
void DoInitialize() override
Initialize() implementation.
Definition wifi-mac.cc:403
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Definition wifi-mac.cc:1591
Ssid GetSsid() const
Definition wifi-mac.cc:519
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition wifi-mac.cc:1386
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition wifi-mac.cc:625
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition wifi-mac.cc:469
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition wifi-mac.cc:1348
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Definition wifi-mac.cc:1545
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition wifi-mac.cc:1948
bool GetHeSupported() const
Return whether the device supports HE.
Definition wifi-mac.cc:1942
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition wifi-mac.cc:2125
virtual std::optional< uint8_t > GetLinkIdByAddress(const Mac48Address &address) const
Get the ID of the link having the given MAC address, if any.
Definition wifi-mac.cc:1115
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the MAC has frames to transmit over the given link.
Definition wifi-mac.cc:656
void ApplyTidLinkMapping(const Mac48Address &mldAddr, WifiDirection dir)
Apply the TID-to-Link Mapping negotiated with the given MLD for the given direction by properly confi...
Definition wifi-mac.cc:1463
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition wifi-mac.cc:1921
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition wifi-mac.cc:1934
virtual int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Definition wifi-mac.cc:374
virtual void DeaggregateAmsduAndForward(Ptr< const WifiMpdu > mpdu)
This method can be called to de-aggregate an A-MSDU and forward the constituent packets up the stack.
Definition wifi-mac.cc:1786
void SetBssid(Mac48Address bssid, uint8_t linkId)
Definition wifi-mac.cc:525
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition wifi-mac.cc:493
void UpdateTidToLinkMapping(const Mac48Address &mldAddr, WifiDirection dir, const WifiTidLinkMapping &mapping)
Update the TID-to-Link Mappings for the given MLD in the given direction based on the given negotiate...
Definition wifi-mac.cc:1246
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition wifi-mac.cc:2116
He6GhzBandCapabilities GetHe6GhzBandCapabilities(uint8_t linkId) const
Return the HE 6GHz band capabilities of the device for the given 6 GHz link.
Definition wifi-mac.cc:2324
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition wifi-mac.cc:649
std::optional< uint8_t > GetLinkForPhy(Ptr< const WifiPhy > phy) const
Get the ID of the link (if any) on which the given PHY is operating.
Definition wifi-mac.cc:1128
bool GetShortSlotTimeSupported() const
Definition wifi-mac.cc:1430
void NotifyRxDrop(Ptr< const Packet > packet)
Definition wifi-mac.cc:723
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition wifi-mac.cc:1060
bool GetHtSupported(uint8_t linkId) const
Return whether the device supports HT on the given link.
Definition wifi-mac.cc:1927
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition wifi-mac.cc:1749
bool Is6GhzBand(uint8_t linkId) const
Indicate if a given link is on the 6 GHz band.
Definition wifi-mac.cc:1238
virtual void Receive(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
This method acts as the MacRxMiddle receive callback and is invoked to notify us that a frame has bee...
Definition wifi-mac.cc:1756
Mac48Address GetAddress() const
Definition wifi-mac.cc:506
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition wifi-mac.cc:2359
Callback< void > m_linkUp
Callback when a link is up.
Definition wifi-mac.h:941
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition wifi-mac.cc:1078
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition wifi-mac.cc:2266
virtual void SetWifiPhys(const std::vector< Ptr< WifiPhy > > &phys)
Definition wifi-mac.cc:1326
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition wifi-mac.cc:603
void DoDispose() override
Destructor implementation.
Definition wifi-mac.cc:427
std::list< uint8_t > GetBssMembershipSelectorList() const
The WifiPhy::BssMembershipSelector() method is used (e.g., by a WifiRemoteStationManager) to determin...
Definition wifi-phy.cc:1396
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1572
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition wifi-phy.cc:829
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1093
void SetOffMode()
Put in off mode.
Definition wifi-phy.cc:1448
std::list< WifiMode > GetMcsList() const
The WifiPhy::GetMcsList() method is used (e.g., by a WifiRemoteStationManager) to determine the set o...
Definition wifi-phy.cc:2098
std::list< WifiMode > GetModeList() const
The WifiPhy::GetModeList() method is used (e.g., by a WifiRemoteStationManager) to determine the set ...
Definition wifi-phy.cc:2049
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeAccessor > MakePairAccessor(T1 a1)
Create an AttributeAccessor for std::pair<>.
Definition pair.h:401
Ptr< AttributeChecker > MakePairChecker()
Make a PairChecker without abscissa and ordinate AttributeCheckers.
Definition pair.h:287
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiPowerManagementMode
Enumeration for power management modes.
WifiQueueBlockedReason
Enumeration of the reasons to block container queues.
@ STA
Definition wifi-mac.h:58
@ WIFI_PM_SWITCHING_TO_ACTIVE
@ WIFI_PM_POWERSAVE
@ WIFI_PM_SWITCHING_TO_PS
@ WIFI_PM_ACTIVE
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition qos-utils.h:64
@ AC_VO
Voice.
Definition qos-utils.h:70
@ AC_VI
Video.
Definition qos-utils.h:68
@ AC_BK
Background.
Definition qos-utils.h:66
-style-clang-format
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1396
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
WifiTidToLinkMappingNegSupport
TID-to-Link Mapping Negotiation Support.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition qos-utils.cc:115
@ WIFI_MAC_MGT_PROBE_REQUEST
@ WIFI_MAC_DATA_NULL
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
@ WIFI_MAC_MGT_REASSOCIATION_REQUEST
@ WIFI_MAC_MGT_PROBE_RESPONSE
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping &dlLinkMapping, const WifiTidLinkMapping &ulLinkMapping)
Check if the given TID-to-Link Mappings are valid for a negotiation type of 1.
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition log.h:95
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
Struct containing all supported rates.
void AddBssMembershipSelectorRate(uint64_t bs)
Add a special value to the supported rate set, corresponding to a BSS membership selector.
void AddSupportedRate(uint64_t bs)
Add the given rate to the supported rates.
std::optional< MldCapabilities > m_mldCapabilities
MLD Capabilities.
Struct to hold information regarding observed AP through active/passive scanning.
MgtFrameType m_frame
The body of the management frame used to update AP info.
WifiScanParams::Channel m_channel
The channel the management frame was received on.
Mac48Address m_apAddr
AP MAC address.
uint8_t m_linkId
ID of the link used to communicate with the AP.
Mac48Address m_bssid
BSSID.
double m_snr
SNR in linear scale.
Struct identifying a channel to scan.
WifiPhyBand band
PHY band.
uint16_t number
channel number
Structure holding scan parameters.
std::list< Channel > ChannelList
typedef for a list of channels
std::vector< ChannelList > channelList
list of channels to scan, for each link
Time probeDelay
delay prior to transmitting a Probe Request
WifiScanType type
indicates either active or passive scanning
Time maxChannelTime
maximum time to spend on each channel
Ssid ssid
desired SSID or wildcard SSID
Time minChannelTime
minimum time to spend on each channel