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("BeaconArrival",
127 "Time of beacons arrival from associated AP",
129 "ns3::Time::TracedCallback")
130 .AddTraceSource("ReceivedBeaconInfo",
131 "Information about every received Beacon frame",
133 "ns3::ApInfo::TracedCallback")
134 .AddTraceSource("EmlsrLinkSwitch",
135 "Trace start/end of EMLSR link switch events: when a PHY operating on "
136 "a link starts switching, provides the ID of the link and a null "
137 "pointer (indicating no PHY is operating on that link); when a PHY "
138 "completes switching to a link, provides the ID of the link and a "
139 "pointer to the PHY (that is now operating on that link)",
141 "ns3::StaWifiMac::EmlsrLinkSwitchCallback");
142 return tid;
143}
144
146 : m_state(UNASSOCIATED),
147 m_aid(0),
148 m_assocRequestEvent()
149{
150 NS_LOG_FUNCTION(this);
151
152 // Let the lower layers know that we are acting as a non-AP STA in
153 // an infrastructure BSS.
155}
156
157void
159{
160 NS_LOG_FUNCTION(this);
161 // an EMLSR client must perform ML setup by using its main PHY
163 {
164 auto mainPhyId = m_emlsrManager->GetMainPhyId();
165 auto linkId = GetLinkForPhy(mainPhyId);
166 NS_ASSERT(linkId);
167 m_assocManager->SetAttribute(
168 "AllowedLinks",
169 AttributeContainerValue<UintegerValue>(std::list<uint8_t>{*linkId}));
170 }
171 if (m_emlsrManager)
172 {
173 m_emlsrManager->Initialize();
174 }
178}
179
180void
182{
183 NS_LOG_FUNCTION(this);
184 if (m_assocManager)
185 {
186 m_assocManager->Dispose();
187 }
188 m_assocManager = nullptr;
189 if (m_emlsrManager)
190 {
191 m_emlsrManager->Dispose();
192 }
193 m_emlsrManager = nullptr;
194 for (auto& [phyId, event] : m_emlsrLinkSwitch)
195 {
196 event.Cancel();
197 }
198 m_emlsrLinkSwitch.clear();
200}
201
206
207void
212
217
218std::unique_ptr<WifiMac::LinkEntity>
220{
221 return std::make_unique<StaLinkEntity>();
222}
223
225StaWifiMac::GetLink(uint8_t linkId) const
226{
227 return static_cast<StaLinkEntity&>(WifiMac::GetLink(linkId));
228}
229
231StaWifiMac::GetStaLink(const std::unique_ptr<WifiMac::LinkEntity>& link) const
232{
233 return static_cast<StaLinkEntity&>(*link);
234}
235
236int64_t
238{
239 NS_LOG_FUNCTION(this << stream);
240 m_probeDelay->SetStream(stream);
241 auto currentStream = stream + 1;
242 currentStream += WifiMac::AssignStreams(currentStream);
243 return (currentStream - stream);
244}
245
246void
248{
249 NS_LOG_FUNCTION(this << assocManager);
250 m_assocManager = assocManager;
251 m_assocManager->SetStaWifiMac(this);
252}
253
254void
256{
257 NS_LOG_FUNCTION(this << emlsrManager);
258 m_emlsrManager = emlsrManager;
259 m_emlsrManager->SetWifiMac(this);
260}
261
264{
265 return m_emlsrManager;
266}
267
268uint16_t
270{
271 NS_ASSERT_MSG(IsAssociated(), "This station is not associated to any AP");
272 return m_aid;
273}
274
275void
277{
278 NS_LOG_FUNCTION(this << enable);
279 m_activeProbing = enable;
280 if (m_state == SCANNING)
281 {
282 NS_LOG_DEBUG("STA is still scanning, reset scanning process");
284 }
285}
286
287bool
289{
290 return m_activeProbing;
291}
292
293void
294StaWifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
295{
296 NS_LOG_FUNCTION(this);
298 for (auto& phy : phys)
299 {
300 phy->SetCapabilitiesChangedCallback(
302 }
303}
304
306StaWifiMac::GetCurrentChannel(uint8_t linkId) const
307{
308 auto phy = GetWifiPhy(linkId);
309 const auto width = phy->GetOperatingChannel().IsOfdm() ? 20 : phy->GetChannelWidth();
310 uint8_t ch = phy->GetPrimaryChannelNumber(width);
311 return {ch, phy->GetPhyBand()};
312}
313
314void
315StaWifiMac::NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds)
316{
317 std::stringstream ss;
318 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
319 {
320 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
321 }
322 NS_LOG_FUNCTION(this << ss.str());
323
324 for (const auto& [linkId, lnk] : GetLinks())
325 {
326 auto& link = GetStaLink(lnk);
327
328 if (linkIds.contains(linkId))
329 {
330 // EMLSR mode enabled
331 link.emlsrEnabled = true;
332 link.pmMode = WIFI_PM_ACTIVE;
333 }
334 else
335 {
336 // EMLSR mode disabled
337 if (link.emlsrEnabled)
338 {
339 link.pmMode = WIFI_PM_POWERSAVE;
340 }
341 link.emlsrEnabled = false;
342 }
343 }
344}
345
346bool
347StaWifiMac::IsEmlsrLink(uint8_t linkId) const
348{
349 return GetLink(linkId).emlsrEnabled;
350}
351
352void
354{
355 NS_LOG_FUNCTION(this << linkId);
356 WifiMacHeader hdr;
361 hdr.SetDsNotFrom();
362 hdr.SetDsNotTo();
363 Ptr<Packet> packet = Create<Packet>();
365 probe.Get<Ssid>() = GetSsid();
366 auto supportedRates = GetSupportedRates(linkId);
367 probe.Get<SupportedRates>() = supportedRates.rates;
368 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
369 if (GetHtSupported(linkId))
370 {
372 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
373 }
374 if (GetVhtSupported(linkId))
375 {
376 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
377 }
378 if (GetHeSupported())
379 {
380 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
381 if (Is6GhzBand(linkId))
382 {
384 }
385 }
386 if (GetEhtSupported())
387 {
388 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
389 }
390 packet->AddHeader(probe);
391
392 if (!GetQosSupported())
393 {
394 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
395 }
396 // "A QoS STA that transmits a Management frame determines access category used
397 // for medium access in transmission of the Management frame as follows
398 // (If dot11QMFActivated is false or not present)
399 // — If the Management frame is individually addressed to a non-QoS STA, category
400 // AC_BE should be selected.
401 // — If category AC_BE was not selected by the previous step, category AC_VO
402 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
403 else
404 {
405 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
406 }
407}
408
409std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>
410StaWifiMac::GetAssociationRequest(bool isReassoc, uint8_t linkId) const
411{
412 NS_LOG_FUNCTION(this << isReassoc << +linkId);
413
414 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader> mgtFrame;
415
416 if (isReassoc)
417 {
419 reassoc.SetCurrentApAddress(GetBssid(linkId));
420 mgtFrame = std::move(reassoc);
421 }
422 else
423 {
424 mgtFrame = MgtAssocRequestHeader();
425 }
426
427 // lambda to set the fields of the (Re)Association Request
428 auto fill = [&](auto&& frame) {
429 frame.template Get<Ssid>() = GetSsid();
430 auto supportedRates = GetSupportedRates(linkId);
431 frame.template Get<SupportedRates>() = supportedRates.rates;
432 frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
433 frame.Capabilities() = GetCapabilities(linkId);
434 frame.SetListenInterval(0);
435 if (GetHtSupported(linkId))
436 {
437 frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
438 frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
439 }
440 if (GetVhtSupported(linkId))
441 {
442 frame.template Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
443 }
444 if (GetHeSupported())
445 {
446 frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
447 if (Is6GhzBand(linkId))
448 {
449 frame.template Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
450 }
451 }
452 if (GetEhtSupported())
453 {
454 frame.template Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
455 }
456 };
457
458 std::visit(fill, mgtFrame);
459 return mgtFrame;
460}
461
463StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
464{
465 NS_LOG_FUNCTION(this << isReassoc << +linkId);
466
468 // The Common info field of the Basic Multi-Link element carried in the (Re)Association
469 // Request frame shall include the MLD MAC address, the MLD Capabilities and Operations,
470 // and the EML Capabilities subfields, and shall not include the Link ID Info, the BSS
471 // Parameters Change Count, and the Medium Synchronization Delay Information subfields
472 // (Sec. 35.3.5.4 of 802.11be D2.0)
473 // TODO Add the MLD Capabilities and Operations subfield
474 multiLinkElement.SetMldMacAddress(GetAddress());
475
476 if (m_emlsrManager) // EMLSR Manager is only installed if EMLSR is activated
477 {
478 multiLinkElement.SetEmlsrSupported(true);
479 TimeValue time;
480 m_emlsrManager->GetAttribute("EmlsrPaddingDelay", time);
481 multiLinkElement.SetEmlsrPaddingDelay(time.Get());
482 m_emlsrManager->GetAttribute("EmlsrTransitionDelay", time);
483 multiLinkElement.SetEmlsrTransitionDelay(time.Get());
484 // When the Transition Timeout subfield is included in a frame sent by a non-AP STA
485 // affiliated with a non-AP MLD, the Transition Timeout subfield is reserved
486 // (Section 9.4.2.312.2.3 of 802.11be D2.3)
487 // The Medium Synchronization Delay Information subfield in the Common Info subfield is
488 // not present if the Basic Multi-Link element is sent by a non-AP STA. (Section
489 // 9.4.2.312.2.3 of 802.11be D3.1)
490 }
491
492 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
493 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
494 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
495 auto& mldCapabilities = multiLinkElement.GetCommonInfoBasic().m_mldCapabilities;
496 mldCapabilities.emplace();
497 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
498 mldCapabilities->srsSupport = 0;
499
500 auto ehtConfiguration = GetEhtConfiguration();
501 NS_ASSERT(ehtConfiguration);
502
503 mldCapabilities->tidToLinkMappingSupport =
504 static_cast<uint8_t>(ehtConfiguration->m_tidLinkMappingSupport);
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
549 auto negSupport = ehtConfig->m_tidLinkMappingSupport;
550
552 "Cannot request TID-to-Link Mapping if negotiation is not supported");
553
554 // store the mappings, so that we can enforce them when the AP MLD accepts them
555 m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
556 m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
557
561 negSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET && !mappingValidForNegType1,
562 "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
563
564 if (apNegSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET && !mappingValidForNegType1)
565 {
566 // If the TID-to-link Mapping Negotiation Support subfield value received from a peer
567 // MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
568 // peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
569 // the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
570 // this requirement.
571 NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
574 }
575
576 std::vector<TidToLinkMapping> ret(1);
577
578 ret.back().m_control.direction = WifiDirection::DOWNLINK;
579
580 // lambda to fill the last TID-to-Link Mapping IE in the vector to return
581 auto fillIe = [&ret](const auto& mapping) {
582 ret.back().m_control.defaultMapping = mapping.empty();
583
584 for (const auto& [tid, linkSet] : mapping)
585 {
586 // At any point in time, a TID shall always be mapped to at least one setup link both
587 // in DL and UL, which means that a TID-to-link mapping change is only valid and
588 // successful if it will not result in having any TID for which the link set for DL
589 // or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
590 NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
591 ret.back().SetLinkMappingOfTid(tid, linkSet);
592 }
593 };
594
596
598 {
599 ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
600 return ret;
601 }
602
603 ret.emplace_back();
604 ret.back().m_control.direction = WifiDirection::UPLINK;
606
607 return ret;
608}
609
610void
612{
613 // find the link where the (Re)Association Request has to be sent
614 auto it = GetLinks().cbegin();
615 while (it != GetLinks().cend())
616 {
617 if (GetStaLink(it->second).sendAssocReq)
618 {
619 break;
620 }
621 it++;
622 }
623 NS_ABORT_MSG_IF(it == GetLinks().cend(),
624 "No link selected to send the (Re)Association Request");
625 uint8_t linkId = it->first;
626 auto& link = GetLink(linkId);
627 NS_ABORT_MSG_IF(!link.bssid.has_value(),
628 "No BSSID set for the link on which the (Re)Association Request is to be sent");
629
630 NS_LOG_FUNCTION(this << *link.bssid << isReassoc);
631 WifiMacHeader hdr;
633 hdr.SetAddr1(*link.bssid);
634 hdr.SetAddr2(link.feManager->GetAddress());
635 hdr.SetAddr3(*link.bssid);
636 hdr.SetDsNotFrom();
637 hdr.SetDsNotTo();
638 Ptr<Packet> packet = Create<Packet>();
639
640 auto frame = GetAssociationRequest(isReassoc, linkId);
641
642 // include a Multi-Link Element if this device has multiple links (independently
643 // of how many links will be setup) and the AP is a multi-link device;
644 // if the AP MLD has indicated a support of TID-to-link mapping negotiation, also
645 // include the TID-to-link Mapping element(s)
646 if (GetNLinks() > 1 &&
647 GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
648 {
649 auto addMle = [&](auto&& frame) {
650 frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
651 };
652 std::visit(addMle, frame);
653
655 if (const auto& mldCapabilities =
656 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
657 mldCapabilities && (negSupport = static_cast<WifiTidToLinkMappingNegSupport>(
658 mldCapabilities->get().tidToLinkMappingSupport)) >
660 {
661 auto addTlm = [&](auto&& frame) {
662 frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
663 };
664 std::visit(addTlm, frame);
665 }
666 }
667
668 if (!isReassoc)
669 {
670 packet->AddHeader(std::get<MgtAssocRequestHeader>(frame));
671 }
672 else
673 {
674 packet->AddHeader(std::get<MgtReassocRequestHeader>(frame));
675 }
676
677 if (!GetQosSupported())
678 {
679 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
680 }
681 // "A QoS STA that transmits a Management frame determines access category used
682 // for medium access in transmission of the Management frame as follows
683 // (If dot11QMFActivated is false or not present)
684 // — If the Management frame is individually addressed to a non-QoS STA, category
685 // AC_BE should be selected.
686 // — If category AC_BE was not selected by the previous step, category AC_VO
687 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
688 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(*link.bssid))
689 {
690 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
691 }
692 else
693 {
694 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
695 }
696
698 {
700 }
703}
704
705void
707{
708 NS_LOG_FUNCTION(this);
709 switch (m_state)
710 {
711 case ASSOCIATED:
712 return;
713 case SCANNING:
714 /* we have initiated active or passive scanning, continue to wait
715 and gather beacons or probe responses until the scanning timeout
716 */
717 break;
718 case UNASSOCIATED:
719 /* we were associated but we missed a bunch of beacons
720 * so we should assume we are not associated anymore.
721 * We try to initiate a scan now.
722 */
723 m_linkDown();
725 break;
726 case WAIT_ASSOC_RESP:
727 /* we have sent an association request so we do not need to
728 re-send an association request right now. We just need to
729 wait until either assoc-request-timeout or until
730 we get an association response.
731 */
732 case REFUSED:
733 /* we have sent an association request and received a negative
734 association response. We wait until someone restarts an
735 association with a given SSID.
736 */
737 break;
738 }
739}
740
741void
743{
744 NS_LOG_FUNCTION(this);
747
748 WifiScanParams scanParams;
749 scanParams.ssid = GetSsid();
750 for (const auto& [id, link] : GetLinks())
751 {
753 (link->phy->HasFixedPhyBand()) ? WifiScanParams::Channel{0, link->phy->GetPhyBand()}
755
756 scanParams.channelList.push_back(channel);
757 }
758 if (m_activeProbing)
759 {
760 scanParams.type = WifiScanType::ACTIVE;
762 scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
763 }
764 else
765 {
766 scanParams.type = WifiScanType::PASSIVE;
768 }
769
770 m_assocManager->StartScanning(std::move(scanParams));
771}
772
773void
774StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& bestAp)
775{
776 NS_LOG_FUNCTION(this);
777
778 if (!bestAp.has_value())
779 {
780 NS_LOG_DEBUG("Exhausted list of candidate AP; restart scanning");
782 return;
783 }
784
785 NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
786 UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
787 // reset info on links to setup
788 for (auto& [id, link] : GetLinks())
789 {
790 auto& staLink = GetStaLink(link);
791 staLink.sendAssocReq = false;
792 staLink.bssid = std::nullopt;
793 }
794 // send Association Request on the link where the Beacon/Probe Response was received
795 GetLink(bestAp->m_linkId).sendAssocReq = true;
796 GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
797 std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
798 // update info on links to setup (11be MLDs only)
799 const auto& mle =
800 std::visit([](auto&& frame) { return frame.template Get<MultiLinkElement>(); },
801 bestAp->m_frame);
802 std::map<uint8_t, uint8_t> swapInfo;
803 for (const auto& [localLinkId, apLinkId, bssid] : bestAp->m_setupLinks)
804 {
805 NS_ASSERT_MSG(mle, "We get here only for ML setup");
806 NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
807 << ")");
808 GetLink(localLinkId).bssid = bssid;
809 if (!mleCommonInfo)
810 {
811 mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
812 }
813 GetWifiRemoteStationManager(localLinkId)->AddStationMleCommonInfo(bssid, mleCommonInfo);
814 swapInfo.emplace(localLinkId, apLinkId);
815 }
816
817 SwapLinks(swapInfo);
818
819 // lambda to get beacon interval from Beacon or Probe Response
820 auto getBeaconInterval = [](auto&& frame) {
821 using T = std::decay_t<decltype(frame)>;
822 if constexpr (std::is_same_v<T, MgtBeaconHeader> ||
823 std::is_same_v<T, MgtProbeResponseHeader>)
824 {
825 return MicroSeconds(frame.GetBeaconIntervalUs());
826 }
827 else
828 {
829 NS_ABORT_MSG("Unexpected frame type");
830 return Seconds(0);
831 }
832 };
833 Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
834 Time delay = beaconInterval * m_maxMissedBeacons;
835 // restart beacon watchdog
837
840}
841
842void
849
850void
852{
853 NS_LOG_FUNCTION(this);
854
856 {
858 {
860 }
863 this);
864 return;
865 }
866 NS_LOG_DEBUG("beacon missed");
867 // We need to switch to the UNASSOCIATED state. However, if we are receiving a frame, wait
868 // until the RX is completed (otherwise, crashes may occur if we are receiving a MU frame
869 // because its reception requires the STA-ID). We need to check that a PHY is operating on
870 // the given link, because this may (temporarily) not be the case for EMLSR clients.
871 Time delay;
872 for (const auto& [id, link] : GetLinks())
873 {
874 if (link->phy && link->phy->IsStateRx())
875 {
876 delay = std::max(delay, link->phy->GetDelayUntilIdle());
877 }
878 }
880}
881
882void
884{
885 NS_LOG_FUNCTION(this);
886
887 Mac48Address apAddr; // the AP address to trace (MLD address in case of ML setup)
888
889 for (const auto& [id, link] : GetLinks())
890 {
891 auto& bssid = GetStaLink(link).bssid;
892 if (bssid)
893 {
894 apAddr = GetWifiRemoteStationManager(id)->GetMldAddress(*bssid).value_or(*bssid);
895 }
896 bssid = std::nullopt; // link is no longer setup
897 }
898
899 NS_LOG_DEBUG("Set state to UNASSOCIATED and start scanning");
901 // cancel the association request timer (see issue #862)
903 m_deAssocLogger(apAddr);
904 m_aid = 0; // reset AID
906}
907
908void
910{
911 NS_LOG_FUNCTION(this << delay);
912
915 {
916 NS_LOG_DEBUG("really restart watchdog.");
918 }
919}
920
921bool
923{
924 return m_state == ASSOCIATED;
925}
926
927bool
929{
930 return m_state == WAIT_ASSOC_RESP;
931}
932
933std::set<uint8_t>
935{
936 if (!IsAssociated())
937 {
938 return {};
939 }
940
941 std::set<uint8_t> linkIds;
942 for (const auto& [id, link] : GetLinks())
943 {
944 if (GetStaLink(link).bssid)
945 {
946 linkIds.insert(id);
947 }
948 }
949 return linkIds;
950}
951
954{
955 for (const auto& [id, link] : GetLinks())
956 {
957 if (GetStaLink(link).bssid == remoteAddr)
958 {
959 // the remote address is the address of the (single link) AP we are associated with;
960 return link->feManager->GetAddress();
961 }
962 }
963
964 // the remote address is unknown
965 return GetAddress();
966}
967
968bool
973
974void
980
981void
983{
984 NS_LOG_FUNCTION(this << *mpdu << to << from);
985
986 auto& hdr = mpdu->GetHeader();
987
988 // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for
989 // non-broadcast data frames exchanged between two MLDs
990 auto linkIds = GetSetupLinkIds();
991 NS_ASSERT(!linkIds.empty());
992 uint8_t linkId = *linkIds.begin();
993 const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId));
994
995 hdr.SetAddr1(apMldAddr.value_or(GetBssid(linkId)));
996 hdr.SetAddr2(apMldAddr ? GetAddress() : GetFrameExchangeManager(linkId)->GetAddress());
997 hdr.SetAddr3(to);
998 hdr.SetDsNotFrom();
999 hdr.SetDsTo();
1000
1001 auto txop = hdr.IsQosData() ? StaticCast<Txop>(GetQosTxop(hdr.GetQosTid())) : GetTxop();
1002 NS_ASSERT(txop);
1003 txop->Queue(mpdu);
1004}
1005
1006void
1008{
1009 NS_LOG_FUNCTION(this << linkId << reason);
1010
1011 auto bssid = GetBssid(linkId);
1012 auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1013
1014 BlockUnicastTxOnLinks(reason, apAddress, {linkId});
1015 // the only type of broadcast frames that a non-AP STA can send are management frames
1016 for (const auto& [acIndex, ac] : wifiAcList)
1017 {
1018 GetMacQueueScheduler()->BlockQueues(reason,
1019 acIndex,
1022 GetFrameExchangeManager(linkId)->GetAddress(),
1023 {},
1024 {linkId});
1025 }
1026}
1027
1028void
1029StaWifiMac::UnblockTxOnLink(std::set<uint8_t> linkIds, WifiQueueBlockedReason reason)
1030{
1031 std::stringstream ss;
1032 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
1033 NS_LOG_FUNCTION(this << ss.str() << reason);
1034
1035 const auto linkId = *linkIds.cbegin();
1036 const auto bssid = GetBssid(linkId);
1037 const auto apAddress =
1038 GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1039
1040 UnblockUnicastTxOnLinks(reason, apAddress, linkIds);
1041 // the only type of broadcast frames that a non-AP STA can send are management frames
1042 for (const auto& [acIndex, ac] : wifiAcList)
1043 {
1044 GetMacQueueScheduler()->UnblockQueues(reason,
1045 acIndex,
1048 GetFrameExchangeManager(linkId)->GetAddress(),
1049 {},
1050 linkIds);
1051 }
1052}
1053
1054void
1056{
1057 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1058 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1059 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1060 Ptr<const Packet> packet = mpdu->GetPacket();
1061 NS_ASSERT(!hdr->IsCtl());
1063 : GetFrameExchangeManager(linkId)->GetAddress();
1064 if (hdr->GetAddr3() == myAddr)
1065 {
1066 NS_LOG_LOGIC("packet sent by us.");
1067 return;
1068 }
1069 if (hdr->GetAddr1() != myAddr && !hdr->GetAddr1().IsGroup())
1070 {
1071 NS_LOG_LOGIC("packet is not for us");
1072 NotifyRxDrop(packet);
1073 return;
1074 }
1075 if (hdr->IsData())
1076 {
1077 if (!IsAssociated())
1078 {
1079 NS_LOG_LOGIC("Received data frame while not associated: ignore");
1080 NotifyRxDrop(packet);
1081 return;
1082 }
1083 if (!(hdr->IsFromDs() && !hdr->IsToDs()))
1084 {
1085 NS_LOG_LOGIC("Received data frame not from the DS: ignore");
1086 NotifyRxDrop(packet);
1087 return;
1088 }
1089 std::set<Mac48Address> apAddresses; // link addresses of AP
1090 for (auto id : GetSetupLinkIds())
1091 {
1092 apAddresses.insert(GetBssid(id));
1093 }
1094 if (!apAddresses.contains(mpdu->GetHeader().GetAddr2()))
1095 {
1096 NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
1097 NotifyRxDrop(packet);
1098 return;
1099 }
1100 if (!hdr->HasData())
1101 {
1102 NS_LOG_LOGIC("Received (QoS) Null Data frame: ignore");
1103 NotifyRxDrop(packet);
1104 return;
1105 }
1106 if (hdr->IsQosData())
1107 {
1108 if (hdr->IsQosAmsdu())
1109 {
1110 NS_ASSERT(apAddresses.contains(mpdu->GetHeader().GetAddr3()));
1112 packet = nullptr;
1113 }
1114 else
1115 {
1116 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1117 }
1118 }
1119 else
1120 {
1121 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1122 }
1123 return;
1124 }
1125
1126 switch (hdr->GetType())
1127 {
1131 // This is a frame aimed at an AP, so we can safely ignore it.
1132 NotifyRxDrop(packet);
1133 break;
1134
1136 ReceiveBeacon(mpdu, linkId);
1137 break;
1138
1140 ReceiveProbeResp(mpdu, linkId);
1141 break;
1142
1145 ReceiveAssocResp(mpdu, linkId);
1146 break;
1147
1149 if (auto [category, action] = WifiActionHeader::Peek(packet);
1150 category == WifiActionHeader::PROTECTED_EHT &&
1151 action.protectedEhtAction ==
1153 {
1154 // this is handled by the EMLSR Manager
1155 break;
1156 }
1157
1158 default:
1159 // Invoke the receive handler of our parent class to deal with any other frames
1160 WifiMac::Receive(mpdu, linkId);
1161 }
1162
1163 if (m_emlsrManager)
1164 {
1165 m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
1166 }
1167}
1168
1169void
1171{
1172 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1173 const WifiMacHeader& hdr = mpdu->GetHeader();
1174 NS_ASSERT(hdr.IsBeacon());
1175
1176 NS_LOG_DEBUG("Beacon received");
1177 MgtBeaconHeader beacon;
1178 mpdu->GetPacket()->PeekHeader(beacon);
1179 const auto& capabilities = beacon.Capabilities();
1180 NS_ASSERT(capabilities.IsEss());
1181 bool goodBeacon;
1182 if (IsWaitAssocResp() || IsAssociated())
1183 {
1184 // we have to process this Beacon only if sent by the AP we are associated
1185 // with or from which we are waiting an Association Response frame
1186 auto bssid = GetLink(linkId).bssid;
1187 goodBeacon = bssid.has_value() && (hdr.GetAddr3() == *bssid);
1188 }
1189 else
1190 {
1191 // we retain this Beacon as candidate AP if the supported rates fit the
1192 // configured BSS membership selector
1193 goodBeacon = CheckSupportedRates(beacon, linkId);
1194 }
1195
1196 SnrTag snrTag;
1197 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1198 NS_ASSERT(found);
1199 ApInfo apInfo = {.m_bssid = hdr.GetAddr3(),
1200 .m_apAddr = hdr.GetAddr2(),
1201 .m_snr = snrTag.Get(),
1202 .m_frame = std::move(beacon),
1203 .m_channel = {GetCurrentChannel(linkId)},
1204 .m_linkId = linkId};
1205
1206 if (!m_beaconInfo.IsEmpty())
1207 {
1208 m_beaconInfo(apInfo);
1209 }
1210
1211 if (!goodBeacon)
1212 {
1213 NS_LOG_LOGIC("Beacon is not for us");
1214 return;
1215 }
1216 if (m_state == ASSOCIATED)
1217 {
1219 Time delay = MicroSeconds(std::get<MgtBeaconHeader>(apInfo.m_frame).GetBeaconIntervalUs() *
1221 RestartBeaconWatchdog(delay);
1222 UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1223 }
1224 else
1225 {
1226 NS_LOG_DEBUG("Beacon received from " << hdr.GetAddr2());
1227 m_assocManager->NotifyApInfo(std::move(apInfo));
1228 }
1229}
1230
1231void
1233{
1234 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1235 const WifiMacHeader& hdr = mpdu->GetHeader();
1236 NS_ASSERT(hdr.IsProbeResp());
1237
1238 NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2());
1239 MgtProbeResponseHeader probeResp;
1240 mpdu->GetPacket()->PeekHeader(probeResp);
1241 if (!CheckSupportedRates(probeResp, linkId))
1242 {
1243 return;
1244 }
1245 SnrTag snrTag;
1246 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1247 NS_ASSERT(found);
1248 m_assocManager->NotifyApInfo(ApInfo{.m_bssid = hdr.GetAddr3(),
1249 .m_apAddr = hdr.GetAddr2(),
1250 .m_snr = snrTag.Get(),
1251 .m_frame = std::move(probeResp),
1252 .m_channel = {GetCurrentChannel(linkId)},
1253 .m_linkId = linkId});
1254}
1255
1256void
1258{
1259 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1260 const WifiMacHeader& hdr = mpdu->GetHeader();
1261 NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp());
1262
1263 if (m_state != WAIT_ASSOC_RESP)
1264 {
1265 return;
1266 }
1267
1268 std::optional<Mac48Address> apMldAddress;
1269 MgtAssocResponseHeader assocResp;
1270 mpdu->GetPacket()->PeekHeader(assocResp);
1272 {
1274 }
1275 if (assocResp.GetStatusCode().IsSuccess())
1276 {
1277 m_aid = assocResp.GetAssociationId();
1278 NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed"));
1279 UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1280 NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
1281 SetBssid(hdr.GetAddr3(), linkId);
1283 if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
1284 {
1285 // this is an ML setup, trace the setup link
1286 m_setupCompleted(linkId, hdr.GetAddr3());
1287 apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
1288 NS_ASSERT(apMldAddress);
1289
1290 if (const auto& mldCapabilities =
1291 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
1292 mldCapabilities && static_cast<WifiTidToLinkMappingNegSupport>(
1293 mldCapabilities->get().tidToLinkMappingSupport) >
1295 {
1296 // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
1297 // TID-to-Link Mapping element(s) in the Association Request.
1298 if (assocResp.Get<TidToLinkMapping>().empty())
1299 {
1300 // The AP MLD did not include a TID-to-Link Mapping element in the Association
1301 // Response, hence it accepted the mapping, which we can now store.
1302 UpdateTidToLinkMapping(*apMldAddress,
1305 UpdateTidToLinkMapping(*apMldAddress,
1308
1309 // Apply the negotiated TID-to-Link Mapping (if any) for UL direction
1311 }
1312 }
1313 }
1314 else
1315 {
1316 m_assocLogger(hdr.GetAddr3());
1317 }
1318 if (!m_linkUp.IsNull())
1319 {
1320 m_linkUp();
1321 }
1322 }
1323 else
1324 {
1325 // If the link on which the (Re)Association Request frame was received cannot be
1326 // accepted by the AP MLD, the AP MLD shall treat the multi-link (re)setup as a
1327 // failure and shall not accept any requested links. If the link on which the
1328 // (Re)Association Request frame was received is accepted by the AP MLD, the
1329 // multi-link (re)setup is successful. (Sec. 35.3.5.1 of 802.11be D3.1)
1330 NS_LOG_DEBUG("association refused");
1332 StartScanning();
1333 return;
1334 }
1335
1336 // if this is an MLD, check if we can setup (other) links
1337 if (GetNLinks() > 1)
1338 {
1339 // create a list of all local Link IDs. IDs are removed as we find a corresponding
1340 // Per-STA Profile Subelements indicating successful association. Links with
1341 // remaining IDs are not setup
1342 std::list<uint8_t> setupLinks;
1343 for (const auto& [id, link] : GetLinks())
1344 {
1345 setupLinks.push_back(id);
1346 }
1347 if (assocResp.GetStatusCode().IsSuccess())
1348 {
1349 setupLinks.remove(linkId);
1350 }
1351
1352 // if a Multi-Link Element is present, check its content
1353 if (const auto& mle = assocResp.Get<MultiLinkElement>())
1354 {
1355 NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
1356 "The link on which the Association Response was received "
1357 "is not a link we requested to setup");
1358 NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
1359 "The link ID of the AP that transmitted the Association "
1360 "Response does not match the stored link ID");
1362 mle->GetMldMacAddress(),
1363 "The AP MLD MAC address in the received Multi-Link Element does not "
1364 "match the address stored in the station manager for link "
1365 << +linkId);
1366 // process the Per-STA Profile Subelements in the Multi-Link Element
1367 for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
1368 {
1369 auto& perStaProfile = mle->GetPerStaProfile(elem);
1370 uint8_t apLinkId = perStaProfile.GetLinkId();
1371 auto it = GetLinks().find(apLinkId);
1372 uint8_t staLinkid = 0;
1373 std::optional<Mac48Address> bssid;
1374 NS_ABORT_MSG_IF(it == GetLinks().cend() ||
1375 !(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
1376 "Setup for AP link ID " << apLinkId << " was not requested");
1377 NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
1378 "The BSSID in the Per-STA Profile for link ID "
1379 << +staLinkid << " does not match the stored BSSID");
1382 perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
1383 "The AP MLD MAC address in the received Multi-Link Element does not "
1384 "match the address stored in the station manager for link "
1385 << +staLinkid);
1386 // process the Association Response contained in this Per-STA Profile
1387 MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
1388 if (assoc.GetStatusCode().IsSuccess())
1389 {
1390 NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
1391 "AID should be the same for all the links");
1392 m_aid = assoc.GetAssociationId();
1393 NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
1394 UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
1395 SetBssid(*bssid, staLinkid);
1396 m_setupCompleted(staLinkid, *bssid);
1398 apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
1399 if (!m_linkUp.IsNull())
1400 {
1401 m_linkUp();
1402 }
1403 }
1404 // remove the ID of the link we setup
1405 setupLinks.remove(staLinkid);
1406 }
1407 }
1408 // remaining links in setupLinks are not setup and hence must be disabled
1409 for (const auto& id : setupLinks)
1410 {
1411 GetLink(id).bssid = std::nullopt;
1412 GetLink(id).phy->SetOffMode();
1413 }
1414 if (apMldAddress)
1415 {
1416 // this is an ML setup, trace the MLD address of the AP (only once)
1417 m_assocLogger(*apMldAddress);
1418 }
1419 }
1420
1421 // the station that associated with the AP may have dissociated and then associated again.
1422 // In this case, the station may store packets from the previous period in which it was
1423 // associated. Have the station restart access if it has packets queued.
1424 for (const auto& [id, link] : GetLinks())
1425 {
1426 if (GetStaLink(link).bssid)
1427 {
1428 if (const auto txop = GetTxop())
1429 {
1430 txop->StartAccessAfterEvent(id,
1433 }
1434 for (const auto& [acIndex, ac] : wifiAcList)
1435 {
1436 if (const auto edca = GetQosTxop(acIndex))
1437 {
1438 edca->StartAccessAfterEvent(id,
1441 }
1442 }
1443 }
1444 }
1445
1447}
1448
1449void
1451{
1452 NS_LOG_FUNCTION(this << linkId);
1453
1454 // STAs operating on setup links may need to transition to a new PM mode after the
1455 // acknowledgement of the Association Response. For this purpose, we connect a callback to
1456 // the PHY TX begin trace to catch the Ack transmitted after the Association Response.
1458 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
1459 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
1460 psduMap.begin()->second->GetHeader(0).IsAck(),
1461 "Expected a Normal Ack after Association Response frame");
1462
1463 auto ackDuration =
1464 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
1465
1466 for (const auto& [id, lnk] : GetLinks())
1467 {
1468 auto& link = GetStaLink(lnk);
1469
1470 if (!link.bssid)
1471 {
1472 // link has not been setup
1473 continue;
1474 }
1475
1476 if (id == linkId)
1477 {
1478 /**
1479 * When a link becomes enabled for a non-AP STA that is affiliated with a
1480 * non-AP MLD after successful association with an AP MLD with (Re)Association
1481 * Request/Response frames transmitted on that link [..], the power management
1482 * mode of the non-AP STA, immediately after the acknowledgement of the
1483 * (Re)Association Response frame [..], is active mode.
1484 * (Sec. 35.3.7.1.4 of 802.11be D3.0)
1485 */
1486 // if the user requested this link to be in powersave mode, we have to
1487 // switch PM mode
1488 if (link.pmMode == WIFI_PM_POWERSAVE)
1489 {
1490 Simulator::Schedule(ackDuration,
1492 this,
1493 std::pair<bool, uint8_t>{true, id});
1494 }
1495 link.pmMode = WIFI_PM_ACTIVE;
1496 }
1497 else
1498 {
1499 /**
1500 * When a link becomes enabled for a non-AP STA that is affiliated with a
1501 * non-AP MLD after successful association with an AP MLD with (Re)Association
1502 * Request/Response frames transmitted on another link [..], the power
1503 * management mode of the non-AP STA, immediately after the acknowledgement of
1504 * the (Re)Association Response frame [..], is power save mode, and its power
1505 * state is doze. (Sec. 35.3.7.1.4 of 802.11be D3.0)
1506 */
1507 // if the user requested this link to be in active mode, we have to
1508 // switch PM mode
1509 if (link.pmMode == WIFI_PM_ACTIVE)
1510 {
1511 Simulator::Schedule(ackDuration,
1513 this,
1514 std::pair<bool, uint8_t>{false, id});
1515 }
1516 link.pmMode = WIFI_PM_POWERSAVE;
1517 }
1518 }
1519 });
1520
1521 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
1522 // after its transmission begins
1523 auto phy = GetLink(linkId).phy;
1524 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
1525 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
1526 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
1527}
1528
1529bool
1530StaWifiMac::CheckSupportedRates(std::variant<MgtBeaconHeader, MgtProbeResponseHeader> frame,
1531 uint8_t linkId)
1532{
1533 NS_LOG_FUNCTION(this << +linkId);
1534
1535 // lambda to invoke on the current frame variant
1536 auto check = [&](auto&& mgtFrame) -> bool {
1537 // check supported rates
1538 NS_ASSERT(mgtFrame.template Get<SupportedRates>());
1539 const auto rates = AllSupportedRates{*mgtFrame.template Get<SupportedRates>(),
1540 mgtFrame.template Get<ExtendedSupportedRatesIE>()};
1541 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1542 {
1543 if (!rates.IsBssMembershipSelectorRate(selector))
1544 {
1545 NS_LOG_DEBUG("Supported rates do not fit with the BSS membership selector");
1546 return false;
1547 }
1548 }
1549
1550 return true;
1551 };
1552
1553 return std::visit(check, frame);
1554}
1555
1556void
1558 const Mac48Address& apAddr,
1559 const Mac48Address& bssid,
1560 uint8_t linkId)
1561{
1562 NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId);
1563
1564 // ERP Information is not present in Association Response frames
1565 const std::optional<ErpInformation>* erpInformation = nullptr;
1566
1567 if (const auto* beacon = std::get_if<MgtBeaconHeader>(&frame))
1568 {
1569 erpInformation = &beacon->Get<ErpInformation>();
1570 }
1571 else if (const auto* probe = std::get_if<MgtProbeResponseHeader>(&frame))
1572 {
1573 erpInformation = &probe->Get<ErpInformation>();
1574 }
1575
1576 // lambda processing Information Elements included in all frame types
1577 auto commonOps = [&](auto&& frame) {
1578 const auto& capabilities = frame.Capabilities();
1579 NS_ASSERT(frame.template Get<SupportedRates>());
1580 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1581 frame.template Get<ExtendedSupportedRatesIE>()};
1582 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1583 {
1584 if (rates.IsSupportedRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1585 {
1586 GetWifiRemoteStationManager(linkId)->AddSupportedMode(apAddr, mode);
1587 if (rates.IsBasicRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1588 {
1589 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
1590 }
1591 }
1592 }
1593
1594 bool isShortPreambleEnabled = capabilities.IsShortPreamble();
1595 if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId))
1596 {
1597 isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode();
1598 if ((*erpInformation)->GetUseProtection() != 0)
1599 {
1600 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(true);
1601 }
1602 else
1603 {
1604 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(false);
1605 }
1606 if (capabilities.IsShortSlotTime() == true)
1607 {
1608 // enable short slot time
1609 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1610 }
1611 else
1612 {
1613 // disable short slot time
1614 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1615 }
1616 }
1617 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled);
1618 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1619 capabilities.IsShortSlotTime());
1620
1621 if (!GetQosSupported())
1622 {
1623 return;
1624 }
1625 /* QoS station */
1626 bool qosSupported = false;
1627 const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
1628 if (edcaParameters.has_value())
1629 {
1630 qosSupported = true;
1631 // The value of the TXOP Limit field is specified as an unsigned integer, with the least
1632 // significant octet transmitted first, in units of 32 μs.
1634 edcaParameters->GetBeCWmin(),
1635 edcaParameters->GetBeCWmax(),
1636 edcaParameters->GetBeAifsn(),
1637 32 * MicroSeconds(edcaParameters->GetBeTxopLimit())},
1638 linkId);
1640 edcaParameters->GetBkCWmin(),
1641 edcaParameters->GetBkCWmax(),
1642 edcaParameters->GetBkAifsn(),
1643 32 * MicroSeconds(edcaParameters->GetBkTxopLimit())},
1644 linkId);
1646 edcaParameters->GetViCWmin(),
1647 edcaParameters->GetViCWmax(),
1648 edcaParameters->GetViAifsn(),
1649 32 * MicroSeconds(edcaParameters->GetViTxopLimit())},
1650 linkId);
1652 edcaParameters->GetVoCWmin(),
1653 edcaParameters->GetVoCWmax(),
1654 edcaParameters->GetVoAifsn(),
1655 32 * MicroSeconds(edcaParameters->GetVoTxopLimit())},
1656 linkId);
1657 }
1658 GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
1659
1660 if (GetHtSupported(linkId))
1661 {
1662 /* HT station */
1663 if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
1664 htCapabilities.has_value())
1665 {
1666 GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
1667 *htCapabilities);
1668 }
1669 else
1670 {
1671 GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
1672 }
1673 // TODO: process ExtendedCapabilities
1674 // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
1675 }
1676
1677 // we do not return if VHT is not supported because HE STAs operating in
1678 // the 2.4 GHz band do not support VHT
1679 if (GetVhtSupported(linkId))
1680 {
1681 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1682 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1683 // to check whether it supports VHT
1684 if (vhtCapabilities.has_value() &&
1685 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1686 {
1687 GetWifiRemoteStationManager(linkId)->AddStationVhtCapabilities(apAddr,
1688 *vhtCapabilities);
1689 // const auto& vhtOperation = frame.GetVhtOperation ();
1690 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_VHT))
1691 {
1692 if (vhtCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1693 {
1694 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1695 }
1696 }
1697 }
1698 }
1699
1700 if (!GetHeSupported())
1701 {
1702 return;
1703 }
1704 /* HE station */
1705 const auto& heCapabilities = frame.template Get<HeCapabilities>();
1706 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1707 {
1708 GetWifiRemoteStationManager(linkId)->AddStationHeCapabilities(apAddr, *heCapabilities);
1709 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_HE))
1710 {
1711 if (heCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1712 {
1713 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1714 }
1715 }
1716 if (const auto& heOperation = frame.template Get<HeOperation>();
1717 heOperation.has_value())
1718 {
1719 GetHeConfiguration()->m_bssColor = heOperation->m_bssColorInfo.m_bssColor;
1720 }
1721 }
1722
1723 const auto& muEdcaParameters = frame.template Get<MuEdcaParameterSet>();
1724 if (muEdcaParameters.has_value())
1725 {
1727 muEdcaParameters->GetMuCwMin(AC_BE),
1728 muEdcaParameters->GetMuCwMax(AC_BE),
1729 muEdcaParameters->GetMuAifsn(AC_BE),
1730 muEdcaParameters->GetMuEdcaTimer(AC_BE)},
1731 linkId);
1733 muEdcaParameters->GetMuCwMin(AC_BK),
1734 muEdcaParameters->GetMuCwMax(AC_BK),
1735 muEdcaParameters->GetMuAifsn(AC_BK),
1736 muEdcaParameters->GetMuEdcaTimer(AC_BK)},
1737 linkId);
1739 muEdcaParameters->GetMuCwMin(AC_VI),
1740 muEdcaParameters->GetMuCwMax(AC_VI),
1741 muEdcaParameters->GetMuAifsn(AC_VI),
1742 muEdcaParameters->GetMuEdcaTimer(AC_VI)},
1743 linkId);
1745 muEdcaParameters->GetMuCwMin(AC_VO),
1746 muEdcaParameters->GetMuCwMax(AC_VO),
1747 muEdcaParameters->GetMuAifsn(AC_VO),
1748 muEdcaParameters->GetMuEdcaTimer(AC_VO)},
1749 linkId);
1750 }
1751
1752 if (Is6GhzBand(linkId))
1753 {
1754 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
1755 {
1756 GetWifiRemoteStationManager(linkId)->AddStationHe6GhzCapabilities(
1757 apAddr,
1758 *he6GhzCapabilities);
1759 }
1760 }
1761
1762 if (!GetEhtSupported())
1763 {
1764 return;
1765 }
1766 /* EHT station */
1767 const auto& ehtCapabilities = frame.template Get<EhtCapabilities>();
1768 // TODO: once we support non constant rate managers, we should add checks here whether EHT
1769 // is supported by the peer
1770 GetWifiRemoteStationManager(linkId)->AddStationEhtCapabilities(apAddr, *ehtCapabilities);
1771
1772 if (const auto& mle = frame.template Get<MultiLinkElement>(); mle && m_emlsrManager)
1773 {
1774 if (mle->HasEmlCapabilities())
1775 {
1776 m_emlsrManager->SetTransitionTimeout(mle->GetTransitionTimeout());
1777 }
1778 if (const auto& common = mle->GetCommonInfoBasic(); common.m_mediumSyncDelayInfo)
1779 {
1780 m_emlsrManager->SetMediumSyncDuration(common.GetMediumSyncDelayTimer());
1781 m_emlsrManager->SetMediumSyncOfdmEdThreshold(common.GetMediumSyncOfdmEdThreshold());
1782 m_emlsrManager->SetMediumSyncMaxNTxops(common.GetMediumSyncMaxNTxops());
1783 }
1784 }
1785 };
1786
1787 // process Information Elements included in the current frame variant
1788 std::visit(commonOps, frame);
1789}
1790
1791void
1792StaWifiMac::SetPowerSaveMode(const std::pair<bool, uint8_t>& enableLinkIdPair)
1793{
1794 const auto [enable, linkId] = enableLinkIdPair;
1795 NS_LOG_FUNCTION(this << enable << linkId);
1796
1797 auto& link = GetLink(linkId);
1798
1799 if (!IsAssociated())
1800 {
1801 NS_LOG_DEBUG("Not associated yet, record the PM mode to switch to upon association");
1802 link.pmMode = enable ? WIFI_PM_POWERSAVE : WIFI_PM_ACTIVE;
1803 return;
1804 }
1805
1806 if (!link.bssid)
1807 {
1808 NS_LOG_DEBUG("Link " << +linkId << " has not been setup, ignore request");
1809 return;
1810 }
1811
1812 if ((enable && link.pmMode == WIFI_PM_POWERSAVE) || (!enable && link.pmMode == WIFI_PM_ACTIVE))
1813 {
1814 NS_LOG_DEBUG("No PM mode change needed");
1815 return;
1816 }
1817
1819
1820 // reschedule a call to this function to make sure that the PM mode switch
1821 // is eventually completed
1824 this,
1825 enableLinkIdPair);
1826
1827 if (HasFramesToTransmit(linkId))
1828 {
1829 NS_LOG_DEBUG("Next transmitted frame will be sent with PM=" << enable);
1830 return;
1831 }
1832
1833 // No queued frames. Enqueue a Data Null frame to inform the AP of the PM mode change
1835
1836 hdr.SetAddr1(GetBssid(linkId));
1838 hdr.SetAddr3(GetBssid(linkId));
1839 hdr.SetDsNotFrom();
1840 hdr.SetDsTo();
1841 enable ? hdr.SetPowerManagement() : hdr.SetNoPowerManagement();
1842 if (GetQosSupported())
1843 {
1845 }
1846 else
1847 {
1849 }
1850}
1851
1853StaWifiMac::GetPmMode(uint8_t linkId) const
1854{
1855 return GetLink(linkId).pmMode;
1856}
1857
1858void
1860{
1861 NS_LOG_FUNCTION(this << *mpdu);
1862
1863 auto linkId = GetLinkIdByAddress(mpdu->GetHeader().GetAddr2());
1864
1865 if (!linkId)
1866 {
1867 // the given MPDU may be the original copy containing MLD addresses and not carrying
1868 // a valid PM bit (which is set on the aliases).
1869 auto linkIds = mpdu->GetInFlightLinkIds();
1870 NS_ASSERT_MSG(!linkIds.empty(),
1871 "The TA of the acked MPDU (" << *mpdu
1872 << ") is not a link "
1873 "address and the MPDU is not inflight");
1874 // in case the ack'ed MPDU is inflight on multiple links, we cannot really know if
1875 // it was received by the AP on all links or only on some links. Hence, we only
1876 // consider the first link ID in the set, given that in the most common case of MPDUs
1877 // that cannot be sent concurrently on multiple links, there will be only one link ID
1878 linkId = *linkIds.begin();
1879 mpdu = GetTxopQueue(mpdu->GetQueueAc())->GetAlias(mpdu, *linkId);
1880 }
1881
1882 auto& link = GetLink(*linkId);
1883 const WifiMacHeader& hdr = mpdu->GetHeader();
1884
1885 // we received an acknowledgment while switching PM mode; the PM mode change is effective now
1886 if (hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_PS)
1887 {
1888 link.pmMode = WIFI_PM_POWERSAVE;
1889 }
1890 else if (!hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_ACTIVE)
1891 {
1892 link.pmMode = WIFI_PM_ACTIVE;
1893 }
1894}
1895
1898{
1899 AllSupportedRates rates;
1900 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1901 {
1902 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
1903 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
1904 rates.AddSupportedRate(modeDataRate);
1905 }
1906 if (GetHtSupported(linkId))
1907 {
1908 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1909 {
1910 rates.AddBssMembershipSelectorRate(selector);
1911 }
1912 }
1913 return rates;
1914}
1915
1917StaWifiMac::GetCapabilities(uint8_t linkId) const
1918{
1919 CapabilityInformation capabilities;
1920 capabilities.SetShortPreamble(GetWifiPhy(linkId)->GetShortPhyPreambleSupported() ||
1921 GetErpSupported(linkId));
1923 return capabilities;
1924}
1925
1926void
1928{
1929 m_state = value;
1930}
1931
1932void
1933StaWifiMac::SetEdcaParameters(const EdcaParams& params, uint8_t linkId)
1934{
1935 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1936 edca->SetMinCw(params.cwMin, linkId);
1937 edca->SetMaxCw(params.cwMax, linkId);
1938 edca->SetAifsn(params.aifsn, linkId);
1939 edca->SetTxopLimit(params.txopLimit, linkId);
1940}
1941
1942void
1943StaWifiMac::SetMuEdcaParameters(const MuEdcaParams& params, uint8_t linkId)
1944{
1945 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1946 edca->SetMuCwMin(params.cwMin, linkId);
1947 edca->SetMuCwMax(params.cwMax, linkId);
1948 edca->SetMuAifsn(params.aifsn, linkId);
1949 edca->SetMuEdcaTimer(params.muEdcaTimer, linkId);
1950}
1951
1952void
1954{
1955 NS_LOG_FUNCTION(this);
1956 if (IsAssociated())
1957 {
1958 NS_LOG_DEBUG("PHY capabilities changed: send reassociation request");
1961 }
1962}
1963
1964/**
1965 * Initial configuration:
1966 *
1967 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
1968 * Link A │FEM│RSM│CAM│◄──────►│Main├──────►│Channel│
1969 * │ │ │ │ │PHY │ │ A │
1970 * └───┴───┴───┘ └────┘ └───────┘
1971 *
1972 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
1973 * Link B │FEM│RSM│CAM│ │Aux │ │Channel│
1974 * │ │ │ │◄──────►│PHY ├──────►│ B │
1975 * └───┴───┴───┘ └────┘ └───────┘
1976 *
1977 * A link switching/swapping is notified by the EMLSR Manager and the Channel Access Manager
1978 * (CAM) notifies us that a first PHY (i.e., the Main PHY) switches to Channel B. We connect
1979 * the Main PHY to the MAC stack B:
1980 *
1981 *
1982 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
1983 * Link A │FEM│RSM│CAM│ ┌───►│Main├───┐ │Channel│
1984 * │ │ │ │ │ │PHY │ │ │ A │
1985 * └───┴───┴───┘ │ └────┘ │ └───────┘
1986 * │ │
1987 * ┌───┬───┬───┐ │ ┌────┐ │ ┌───────┐
1988 * Link B │FEM│RSM│CAM│◄──┘ │Aux │ └──►│Channel│
1989 * │ │ │ │◄─ ─ ─ ─│PHY ├──────►│ B │
1990 * └───┴───┴───┘INACTIVE└────┘ └───────┘
1991 *
1992 * MAC stack B keeps a PHY listener associated with the Aux PHY, even though it is inactive,
1993 * meaning that the PHY listener will only notify channel switches (no CCA, no RX).
1994 * If the EMLSR Manager requested a link switching, this configuration will be kept until
1995 * further requests. If the EMLSR Manager requested a link swapping, link B's CAM will be
1996 * notified by its (inactive) PHY listener upon the channel switch performed by the Aux PHY.
1997 * In this case, we remove the inactive PHY listener and connect the Aux PHY to MAC stack A:
1998 *
1999 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2000 * Link A │FEM│RSM│CAM│◄─┐ ┌──►│Main├───┐ │Channel│
2001 * │ │ │ │ │ │ │PHY │ ┌─┼──►│ A │
2002 * └───┴───┴───┘ │ │ └────┘ │ │ └───────┘
2003 * │ │ │ │
2004 * ┌───┬───┬───┐ │ │ ┌────┐ │ │ ┌───────┐
2005 * Link B │FEM│RSM│CAM│◄─┼─┘ │Aux │ │ └──►│Channel│
2006 * │ │ │ │ └────►│PHY ├─┘ │ B │
2007 * └───┴───┴───┘ └────┘ └───────┘
2008 */
2009
2010void
2012{
2013 NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
2014
2015 // If the PHY is switching channel to operate on another link, then it is no longer operating
2016 // on the current link. If any link (other than the current link) points to the PHY that is
2017 // switching channel, reset the phy pointer of the link
2018 for (auto& [id, link] : GetLinks())
2019 {
2020 if (link->phy == phy && id != linkId)
2021 {
2022 link->phy = nullptr;
2023 m_emlsrLinkSwitchLogger(id, nullptr);
2024 }
2025 }
2026
2027 // lambda to connect the PHY to the new link
2028 auto connectPhy = [=, this]() mutable {
2029 auto& newLink = GetLink(linkId);
2030 // The MAC stack associated with the new link uses the given PHY
2031 newLink.phy = phy;
2032 // Setup a PHY listener for the given PHY on the CAM associated with the new link
2033 newLink.channelAccessManager->SetupPhyListener(phy);
2035 if (m_emlsrManager->GetCamStateReset())
2036 {
2037 newLink.channelAccessManager->ResetState();
2038 }
2039 // Disconnect the FEM on the new link from the current PHY
2040 newLink.feManager->ResetPhy();
2041 // Connect the FEM on the new link to the given PHY
2042 newLink.feManager->SetWifiPhy(phy);
2043 // Connect the station manager on the new link to the given PHY
2044 newLink.stationManager->SetupPhy(phy);
2045 // log link switch
2046 m_emlsrLinkSwitchLogger(linkId, phy);
2047 };
2048
2049 // cancel any pending event for the given PHY to switch link
2050 if (auto eventIt = m_emlsrLinkSwitch.find(phy->GetPhyId()); eventIt != m_emlsrLinkSwitch.end())
2051 {
2052 eventIt->second.Cancel();
2053 m_emlsrLinkSwitch.erase(eventIt);
2054 }
2055
2056 // connect the PHY to the new link when the channel switch is completed, so that the PHY
2057 // operating on the new link can possibly continue receiving frames in the meantime.
2058 m_emlsrLinkSwitch.emplace(phy->GetPhyId(), Simulator::Schedule(delay, connectPhy));
2059}
2060
2061void
2063{
2064 NS_LOG_FUNCTION(this << +linkId);
2065
2067
2068 if (IsInitialized() && IsAssociated())
2069 {
2070 Disassociated();
2071 }
2072
2073 // notify association manager
2074 m_assocManager->NotifyChannelSwitched(linkId);
2075}
2076
2077std::ostream&
2078operator<<(std::ostream& os, const StaWifiMac::ApInfo& apInfo)
2079{
2080 os << "BSSID=" << apInfo.m_bssid << ", AP addr=" << apInfo.m_apAddr << ", SNR=" << apInfo.m_snr
2081 << ", Channel={" << apInfo.m_channel.number << "," << apInfo.m_channel.band
2082 << "}, Link ID=" << +apInfo.m_linkId << ", Frame=[";
2083 std::visit([&os](auto&& frame) { frame.Print(os); }, apInfo.m_frame);
2084 os << "]";
2085 return os;
2086}
2087
2088} // namespace ns3
A container for one type of attribute.
AttributeValue implementation for Boolean.
Definition boolean.h:26
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.
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
Introspection did not find any typical Config paths.
Definition snr-tag.h:24
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.
TracedCallback< uint8_t, Ptr< WifiPhy > > m_emlsrLinkSwitchLogger
EMLSR link switch logger.
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.
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
AttributeValue implementation for Time.
Definition nstime.h:1431
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
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:2322
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:2357
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:2265
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:1402
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition wifi-phy.cc:835
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1099
void SetOffMode()
Put in off mode.
Definition wifi-phy.cc:1463
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:2113
std::list< WifiMode > GetModeList() const
The WifiPhy::GetModeList() method is used (e.g., by a WifiRemoteStationManager) to determine the set ...
Definition wifi-phy.cc:2064
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 AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakePairAccessor(T1 a1)
Create an AttributeAccessor for std::pair<>.
Definition pair.h:403
Ptr< AttributeChecker > MakePairChecker()
Make a PairChecker without abscissa and ordinate AttributeCheckers.
Definition pair.h:289
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
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1432
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1452
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#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:1368
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
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.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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
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
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