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 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19 * Mirko Banchi <mk.banchi@gmail.com>
20 */
21
22#include "sta-wifi-mac.h"
23
26#include "mgt-action-headers.h"
27#include "mgt-headers.h"
28#include "qos-txop.h"
29#include "snr-tag.h"
30#include "wifi-assoc-manager.h"
31#include "wifi-mac-queue.h"
32#include "wifi-net-device.h"
33#include "wifi-phy.h"
34
35#include "ns3/attribute-container.h"
36#include "ns3/eht-configuration.h"
37#include "ns3/emlsr-manager.h"
38#include "ns3/he-configuration.h"
39#include "ns3/ht-configuration.h"
40#include "ns3/log.h"
41#include "ns3/packet.h"
42#include "ns3/pair.h"
43#include "ns3/pointer.h"
44#include "ns3/random-variable-stream.h"
45#include "ns3/simulator.h"
46#include "ns3/string.h"
47
48#include <iterator>
49#include <numeric>
50#include <sstream>
51
52namespace ns3
53{
54
55NS_LOG_COMPONENT_DEFINE("StaWifiMac");
56
58
59TypeId
61{
62 static TypeId tid =
63 TypeId("ns3::StaWifiMac")
65 .SetGroupName("Wifi")
66 .AddConstructor<StaWifiMac>()
67 .AddAttribute("ProbeRequestTimeout",
68 "The duration to actively probe the channel.",
69 TimeValue(Seconds(0.05)),
72 .AddAttribute("WaitBeaconTimeout",
73 "The duration to dwell on a channel while passively scanning for beacon",
77 .AddAttribute("AssocRequestTimeout",
78 "The interval between two consecutive association request attempts.",
79 TimeValue(Seconds(0.5)),
82 .AddAttribute("MaxMissedBeacons",
83 "Number of beacons which much be consecutively missed before "
84 "we attempt to restart association.",
85 UintegerValue(10),
87 MakeUintegerChecker<uint32_t>())
88 .AddAttribute(
89 "ActiveProbing",
90 "If true, we send probe requests. If false, we don't."
91 "NOTE: if more than one STA in your simulation is using active probing, "
92 "you should enable it at a different simulation time for each STA, "
93 "otherwise all the STAs will start sending probes at the same time resulting in "
94 "collisions. "
95 "See bug 1060 for more info.",
96 BooleanValue(false),
99 .AddAttribute("ProbeDelay",
100 "Delay (in microseconds) to be used prior to transmitting a "
101 "Probe frame during active scanning.",
102 StringValue("ns3::UniformRandomVariable[Min=50.0|Max=250.0]"),
104 MakePointerChecker<RandomVariableStream>())
105 .AddAttribute(
106 "PowerSaveMode",
107 "Enable/disable power save mode on the given link. The power management mode is "
108 "actually changed when the AP acknowledges a frame sent with the Power Management "
109 "field set to the value corresponding to the requested mode",
110 TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
112 MakePairAccessor<BooleanValue, UintegerValue>(&StaWifiMac::SetPowerSaveMode),
113 MakePairChecker<BooleanValue, UintegerValue>(MakeBooleanChecker(),
114 MakeUintegerChecker<uint8_t>()))
115 .AddAttribute("PmModeSwitchTimeout",
116 "If switching to a new Power Management mode is not completed within "
117 "this amount of time, make another attempt at switching Power "
118 "Management mode.",
119 TimeValue(Seconds(0.1)),
122 .AddTraceSource("Assoc",
123 "Associated with an access point. If this is an MLD that associated "
124 "with an AP MLD, the AP MLD address is provided.",
126 "ns3::Mac48Address::TracedCallback")
127 .AddTraceSource("LinkSetupCompleted",
128 "A link was setup in the context of ML setup with an AP MLD. "
129 "Provides ID of the setup link and AP MAC address",
131 "ns3::StaWifiMac::LinkSetupCallback")
132 .AddTraceSource("DeAssoc",
133 "Association with an access point lost. If this is an MLD "
134 "that disassociated with an AP MLD, the AP MLD address is provided.",
136 "ns3::Mac48Address::TracedCallback")
137 .AddTraceSource("LinkSetupCanceled",
138 "A link setup in the context of ML setup with an AP MLD was torn down. "
139 "Provides ID of the setup link and AP MAC address",
141 "ns3::StaWifiMac::LinkSetupCallback",
143 "Disassociation only occurs at MLD level; use DeAssoc trace.")
144 .AddTraceSource("BeaconArrival",
145 "Time of beacons arrival from associated AP",
147 "ns3::Time::TracedCallback")
148 .AddTraceSource("ReceivedBeaconInfo",
149 "Information about every received Beacon frame",
151 "ns3::ApInfo::TracedCallback");
152 return tid;
153}
154
156 : m_state(UNASSOCIATED),
157 m_aid(0),
158 m_assocRequestEvent()
159{
160 NS_LOG_FUNCTION(this);
161
162 // Let the lower layers know that we are acting as a non-AP STA in
163 // an infrastructure BSS.
165}
166
167void
169{
170 NS_LOG_FUNCTION(this);
171 // an EMLSR client must perform ML setup by using its main PHY
173 {
174 auto mainPhyId = m_emlsrManager->GetMainPhyId();
175 auto linkId = GetLinkForPhy(mainPhyId);
176 NS_ASSERT(linkId);
177 m_assocManager->SetAttribute(
178 "AllowedLinks",
179 AttributeContainerValue<UintegerValue>(std::list<uint8_t>{*linkId}));
180 }
181 if (m_emlsrManager)
182 {
183 m_emlsrManager->Initialize();
184 }
188}
189
190void
192{
193 NS_LOG_FUNCTION(this);
194 if (m_assocManager)
195 {
196 m_assocManager->Dispose();
197 }
198 m_assocManager = nullptr;
199 if (m_emlsrManager)
200 {
201 m_emlsrManager->Dispose();
202 }
203 m_emlsrManager = nullptr;
205}
206
208{
209 NS_LOG_FUNCTION(this);
210}
211
213{
215}
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 uint16_t width = phy->GetOperatingChannel().IsOfdm() ? 20 : phy->GetChannelWidth();
309 uint8_t ch = phy->GetOperatingChannel().GetPrimaryChannelNumber(width, phy->GetStandard());
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())
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 }
381 if (GetEhtSupported())
382 {
383 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
384 }
385 packet->AddHeader(probe);
386
387 if (!GetQosSupported())
388 {
389 GetTxop()->Queue(packet, hdr);
390 }
391 // "A QoS STA that transmits a Management frame determines access category used
392 // for medium access in transmission of the Management frame as follows
393 // (If dot11QMFActivated is false or not present)
394 // — If the Management frame is individually addressed to a non-QoS STA, category
395 // AC_BE should be selected.
396 // — If category AC_BE was not selected by the previous step, category AC_VO
397 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
398 else
399 {
400 GetVOQueue()->Queue(packet, hdr);
401 }
402}
403
404std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>
405StaWifiMac::GetAssociationRequest(bool isReassoc, uint8_t linkId) const
406{
407 NS_LOG_FUNCTION(this << isReassoc << +linkId);
408
409 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader> mgtFrame;
410
411 if (isReassoc)
412 {
414 reassoc.SetCurrentApAddress(GetBssid(linkId));
415 mgtFrame = std::move(reassoc);
416 }
417 else
418 {
419 mgtFrame = MgtAssocRequestHeader();
420 }
421
422 // lambda to set the fields of the (Re)Association Request
423 auto fill = [&](auto&& frame) {
424 frame.template Get<Ssid>() = GetSsid();
425 auto supportedRates = GetSupportedRates(linkId);
426 frame.template Get<SupportedRates>() = supportedRates.rates;
427 frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
428 frame.Capabilities() = GetCapabilities(linkId);
429 frame.SetListenInterval(0);
430 if (GetHtSupported())
431 {
432 frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
433 frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
434 }
435 if (GetVhtSupported(linkId))
436 {
437 frame.template Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
438 }
439 if (GetHeSupported())
440 {
441 frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
442 }
443 if (GetEhtSupported())
444 {
445 frame.template Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
446 }
447 };
448
449 std::visit(fill, mgtFrame);
450 return mgtFrame;
451}
452
454StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
455{
456 NS_LOG_FUNCTION(this << isReassoc << +linkId);
457
459 // The Common info field of the Basic Multi-Link element carried in the (Re)Association
460 // Request frame shall include the MLD MAC address, the MLD Capabilities and Operations,
461 // and the EML Capabilities subfields, and shall not include the Link ID Info, the BSS
462 // Parameters Change Count, and the Medium Synchronization Delay Information subfields
463 // (Sec. 35.3.5.4 of 802.11be D2.0)
464 // TODO Add the MLD Capabilities and Operations subfield
465 multiLinkElement.SetMldMacAddress(GetAddress());
466
467 if (m_emlsrManager) // EMLSR Manager is only installed if EMLSR is activated
468 {
469 multiLinkElement.SetEmlsrSupported(true);
470 TimeValue time;
471 m_emlsrManager->GetAttribute("EmlsrPaddingDelay", time);
472 multiLinkElement.SetEmlsrPaddingDelay(time.Get());
473 m_emlsrManager->GetAttribute("EmlsrTransitionDelay", time);
474 multiLinkElement.SetEmlsrTransitionDelay(time.Get());
475 // When the Transition Timeout subfield is included in a frame sent by a non-AP STA
476 // affiliated with a non-AP MLD, the Transition Timeout subfield is reserved
477 // (Section 9.4.2.312.2.3 of 802.11be D2.3)
478 // The Medium Synchronization Delay Information subfield in the Common Info subfield is
479 // not present if the Basic Multi-Link element is sent by a non-AP STA. (Section
480 // 9.4.2.312.2.3 of 802.11be D3.1)
481 }
482
483 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
484 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
485 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
486 auto& mldCapabilities = multiLinkElement.GetCommonInfoBasic().m_mldCapabilities;
487 mldCapabilities.emplace();
488 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
489 mldCapabilities->srsSupport = 0;
490
491 auto ehtConfiguration = GetEhtConfiguration();
492 NS_ASSERT(ehtConfiguration);
494 ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
495
496 mldCapabilities->tidToLinkMappingSupport = static_cast<uint8_t>(negSupport.Get());
497 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
498 mldCapabilities->aarSupport = 0; // not supported yet
499
500 // For each requested link in addition to the link on which the (Re)Association Request
501 // frame is transmitted, the Link Info field of the Basic Multi-Link element carried
502 // in the (Re)Association Request frame shall contain the corresponding Per-STA Profile
503 // subelement(s).
504 for (const auto& [index, link] : GetLinks())
505 {
506 const auto& staLink = GetStaLink(link);
507
508 if (index != linkId && staLink.bssid.has_value())
509 {
510 multiLinkElement.AddPerStaProfileSubelement();
511 auto& perStaProfile = multiLinkElement.GetPerStaProfile(
512 multiLinkElement.GetNPerStaProfileSubelements() - 1);
513 // The Link ID subfield of the STA Control field of the Per-STA Profile subelement
514 // for the corresponding non-AP STA that requests a link for multi-link (re)setup
515 // with the AP MLD is set to the link ID of the AP affiliated with the AP MLD that
516 // is operating on that link. The link ID is obtained during multi-link discovery
517 perStaProfile.SetLinkId(index);
518 // For each Per-STA Profile subelement included in the Link Info field, the
519 // Complete Profile subfield of the STA Control field shall be set to 1
520 perStaProfile.SetCompleteProfile();
521 // The MAC Address Present subfield indicates the presence of the STA MAC Address
522 // subfield in the STA Info field and is set to 1 if the STA MAC Address subfield
523 // is present in the STA Info field; otherwise set to 0. An STA sets this subfield
524 // to 1 when the element carries complete profile.
525 perStaProfile.SetStaMacAddress(staLink.feManager->GetAddress());
526 perStaProfile.SetAssocRequest(GetAssociationRequest(isReassoc, index));
527 }
528 }
529
530 return multiLinkElement;
531}
532
533std::vector<TidToLinkMapping>
535{
536 NS_LOG_FUNCTION(this << apNegSupport);
537
538 auto ehtConfig = GetEhtConfiguration();
539 NS_ASSERT(ehtConfig);
540
542 ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
543
545 "Cannot request TID-to-Link Mapping if negotiation is not supported");
546
547 // store the mappings, so that we can enforce them when the AP MLD accepts them
548 m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
549 m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
550
555 !mappingValidForNegType1,
556 "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
557
558 if (apNegSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET && !mappingValidForNegType1)
559 {
560 // If the TID-to-link Mapping Negotiation Support subfield value received from a peer
561 // MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
562 // peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
563 // the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
564 // this requirement.
565 NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
568 }
569
570 std::vector<TidToLinkMapping> ret(1);
571
572 ret.back().m_control.direction = WifiDirection::DOWNLINK;
573
574 // lambda to fill the last TID-to-Link Mapping IE in the vector to return
575 auto fillIe = [&ret](const auto& mapping) {
576 ret.back().m_control.defaultMapping = mapping.empty();
577
578 for (const auto& [tid, linkSet] : mapping)
579 {
580 // At any point in time, a TID shall always be mapped to at least one setup link both
581 // in DL and UL, which means that a TID-to-link mapping change is only valid and
582 // successful if it will not result in having any TID for which the link set for DL
583 // or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
584 NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
585 ret.back().SetLinkMappingOfTid(tid, linkSet);
586 }
587 };
588
590
592 {
593 ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
594 return ret;
595 }
596
597 ret.emplace_back();
598 ret.back().m_control.direction = WifiDirection::UPLINK;
600
601 return ret;
602}
603
604void
606{
607 // find the link where the (Re)Association Request has to be sent
608 auto it = GetLinks().cbegin();
609 while (it != GetLinks().cend())
610 {
611 if (GetStaLink(it->second).sendAssocReq)
612 {
613 break;
614 }
615 it++;
616 }
617 NS_ABORT_MSG_IF(it == GetLinks().cend(),
618 "No link selected to send the (Re)Association Request");
619 uint8_t linkId = it->first;
620 auto& link = GetLink(linkId);
621 NS_ABORT_MSG_IF(!link.bssid.has_value(),
622 "No BSSID set for the link on which the (Re)Association Request is to be sent");
623
624 NS_LOG_FUNCTION(this << *link.bssid << isReassoc);
625 WifiMacHeader hdr;
627 hdr.SetAddr1(*link.bssid);
628 hdr.SetAddr2(link.feManager->GetAddress());
629 hdr.SetAddr3(*link.bssid);
630 hdr.SetDsNotFrom();
631 hdr.SetDsNotTo();
632 Ptr<Packet> packet = Create<Packet>();
633
634 auto frame = GetAssociationRequest(isReassoc, linkId);
635
636 // include a Multi-Link Element if this device has multiple links (independently
637 // of how many links will be setup) and the AP is a multi-link device;
638 // if the AP MLD has indicated a support of TID-to-link mapping negotiation, also
639 // include the TID-to-link Mapping element(s)
640 if (GetNLinks() > 1 &&
641 GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
642 {
643 auto addMle = [&](auto&& frame) {
644 frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
645 };
646 std::visit(addMle, frame);
647
649 if (const auto& mldCapabilities =
650 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
651 mldCapabilities && (negSupport = static_cast<WifiTidToLinkMappingNegSupport>(
652 mldCapabilities->get().tidToLinkMappingSupport)) >
654 {
655 auto addTlm = [&](auto&& frame) {
656 frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
657 };
658 std::visit(addTlm, frame);
659 }
660 }
661
662 if (!isReassoc)
663 {
664 packet->AddHeader(std::get<MgtAssocRequestHeader>(frame));
665 }
666 else
667 {
668 packet->AddHeader(std::get<MgtReassocRequestHeader>(frame));
669 }
670
671 if (!GetQosSupported())
672 {
673 GetTxop()->Queue(packet, hdr);
674 }
675 // "A QoS STA that transmits a Management frame determines access category used
676 // for medium access in transmission of the Management frame as follows
677 // (If dot11QMFActivated is false or not present)
678 // — If the Management frame is individually addressed to a non-QoS STA, category
679 // AC_BE should be selected.
680 // — If category AC_BE was not selected by the previous step, category AC_VO
681 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
682 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(*link.bssid))
683 {
684 GetBEQueue()->Queue(packet, hdr);
685 }
686 else
687 {
688 GetVOQueue()->Queue(packet, hdr);
689 }
690
692 {
694 }
697}
698
699void
701{
702 NS_LOG_FUNCTION(this);
703 switch (m_state)
704 {
705 case ASSOCIATED:
706 return;
707 case SCANNING:
708 /* we have initiated active or passive scanning, continue to wait
709 and gather beacons or probe responses until the scanning timeout
710 */
711 break;
712 case UNASSOCIATED:
713 /* we were associated but we missed a bunch of beacons
714 * so we should assume we are not associated anymore.
715 * We try to initiate a scan now.
716 */
717 m_linkDown();
719 break;
720 case WAIT_ASSOC_RESP:
721 /* we have sent an association request so we do not need to
722 re-send an association request right now. We just need to
723 wait until either assoc-request-timeout or until
724 we get an association response.
725 */
726 break;
727 case REFUSED:
728 /* we have sent an association request and received a negative
729 association response. We wait until someone restarts an
730 association with a given SSID.
731 */
732 break;
733 }
734}
735
736void
738{
739 NS_LOG_FUNCTION(this);
742
743 WifiScanParams scanParams;
744 scanParams.ssid = GetSsid();
745 for (const auto& [id, link] : GetLinks())
746 {
748 (link->phy->HasFixedPhyBand()) ? WifiScanParams::Channel{0, link->phy->GetPhyBand()}
750
751 scanParams.channelList.push_back(channel);
752 }
753 if (m_activeProbing)
754 {
755 scanParams.type = WifiScanType::ACTIVE;
757 scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
758 }
759 else
760 {
761 scanParams.type = WifiScanType::PASSIVE;
763 }
764
765 m_assocManager->StartScanning(std::move(scanParams));
766}
767
768void
769StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& bestAp)
770{
771 NS_LOG_FUNCTION(this);
772
773 if (!bestAp.has_value())
774 {
775 NS_LOG_DEBUG("Exhausted list of candidate AP; restart scanning");
777 return;
778 }
779
780 NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
781 UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
782 // reset info on links to setup
783 for (auto& [id, link] : GetLinks())
784 {
785 auto& staLink = GetStaLink(link);
786 staLink.sendAssocReq = false;
787 staLink.bssid = std::nullopt;
788 }
789 // send Association Request on the link where the Beacon/Probe Response was received
790 GetLink(bestAp->m_linkId).sendAssocReq = true;
791 GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
792 std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
793 // update info on links to setup (11be MLDs only)
794 const auto& mle =
795 std::visit([](auto&& frame) { return frame.template Get<MultiLinkElement>(); },
796 bestAp->m_frame);
797 std::map<uint8_t, uint8_t> swapInfo;
798 for (const auto& [localLinkId, apLinkId, bssid] : bestAp->m_setupLinks)
799 {
800 NS_ASSERT_MSG(mle, "We get here only for ML setup");
801 NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
802 << ")");
803 GetLink(localLinkId).bssid = bssid;
804 if (!mleCommonInfo)
805 {
806 mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
807 }
808 GetWifiRemoteStationManager(localLinkId)->AddStationMleCommonInfo(bssid, mleCommonInfo);
809 swapInfo.emplace(localLinkId, apLinkId);
810 }
811
812 SwapLinks(swapInfo);
813
814 // lambda to get beacon interval from Beacon or Probe Response
815 auto getBeaconInterval = [](auto&& frame) {
816 using T = std::decay_t<decltype(frame)>;
817 if constexpr (std::is_same_v<T, MgtBeaconHeader> ||
818 std::is_same_v<T, MgtProbeResponseHeader>)
819 {
820 return MicroSeconds(frame.GetBeaconIntervalUs());
821 }
822 else
823 {
824 NS_ABORT_MSG("Unexpected frame type");
825 return Seconds(0);
826 }
827 };
828 Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
829 Time delay = beaconInterval * m_maxMissedBeacons;
830 // restart beacon watchdog
832
835}
836
837void
839{
840 NS_LOG_FUNCTION(this);
843}
844
845void
847{
848 NS_LOG_FUNCTION(this);
849
851 {
853 {
855 }
858 this);
859 return;
860 }
861 NS_LOG_DEBUG("beacon missed");
862 // We need to switch to the UNASSOCIATED state. However, if we are receiving a frame, wait
863 // until the RX is completed (otherwise, crashes may occur if we are receiving a MU frame
864 // because its reception requires the STA-ID). We need to check that a PHY is operating on
865 // the given link, because this may (temporarily) not be the case for EMLSR clients.
866 Time delay = Seconds(0);
867 for (const auto& [id, link] : GetLinks())
868 {
869 if (link->phy && link->phy->IsStateRx())
870 {
871 delay = std::max(delay, link->phy->GetDelayUntilIdle());
872 }
873 }
875}
876
877void
879{
880 NS_LOG_FUNCTION(this);
881
882 Mac48Address apAddr; // the AP address to trace (MLD address in case of ML setup)
883
884 for (const auto& [id, link] : GetLinks())
885 {
886 auto& bssid = GetStaLink(link).bssid;
887 if (bssid)
888 {
889 apAddr = GetWifiRemoteStationManager(id)->GetMldAddress(*bssid).value_or(*bssid);
890 }
891 bssid = std::nullopt; // link is no longer setup
892 }
893
894 NS_LOG_DEBUG("Set state to UNASSOCIATED and start scanning");
896 // cancel the association request timer (see issue #862)
898 m_deAssocLogger(apAddr);
899 m_aid = 0; // reset AID
901}
902
903void
905{
906 NS_LOG_FUNCTION(this << delay);
907
910 {
911 NS_LOG_DEBUG("really restart watchdog.");
913 }
914}
915
916bool
918{
919 return m_state == ASSOCIATED;
920}
921
922bool
924{
925 return m_state == WAIT_ASSOC_RESP;
926}
927
928std::set<uint8_t>
930{
931 if (!IsAssociated())
932 {
933 return {};
934 }
935
936 std::set<uint8_t> linkIds;
937 for (const auto& [id, link] : GetLinks())
938 {
939 if (GetStaLink(link).bssid)
940 {
941 linkIds.insert(id);
942 }
943 }
944 return linkIds;
945}
946
949{
950 auto linkIds = GetSetupLinkIds();
951 NS_ASSERT_MSG(!linkIds.empty(), "Not associated");
952 uint8_t linkId = *linkIds.begin();
953 return GetFrameExchangeManager(linkId)->GetAddress();
954}
955
956bool
958{
959 return IsAssociated();
960}
961
962void
964{
965 NS_LOG_FUNCTION(this << packet << to);
966 if (!CanForwardPacketsTo(to))
967 {
968 NotifyTxDrop(packet);
970 return;
971 }
972 WifiMacHeader hdr;
973
974 // If we are not a QoS AP then we definitely want to use AC_BE to
975 // transmit the packet. A TID of zero will map to AC_BE (through \c
976 // QosUtilsMapTidToAc()), so we use that as our default here.
977 uint8_t tid = 0;
978
979 // For now, an AP that supports QoS does not support non-QoS
980 // associations, and vice versa. In future the AP model should
981 // support simultaneously associated QoS and non-QoS STAs, at which
982 // point there will need to be per-association QoS state maintained
983 // by the association state machine, and consulted here.
984 if (GetQosSupported())
985 {
988 hdr.SetQosNoEosp();
989 hdr.SetQosNoAmsdu();
990 // Transmission of multiple frames in the same TXOP is not
991 // supported for now
992 hdr.SetQosTxopLimit(0);
993
994 // Fill in the QoS control field in the MAC header
995 tid = QosUtilsGetTidForPacket(packet);
996 // Any value greater than 7 is invalid and likely indicates that
997 // the packet had no QoS tag, so we revert to zero, which'll
998 // mean that AC_BE is used.
999 if (tid > 7)
1000 {
1001 tid = 0;
1002 }
1003 hdr.SetQosTid(tid);
1004 }
1005 else
1006 {
1008 }
1009 if (GetQosSupported())
1010 {
1011 hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
1012 // yet implemented (set it to 1 when implemented)
1013 }
1014
1015 // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for
1016 // non-broadcast data frames exchanged between two MLDs
1017 auto linkIds = GetSetupLinkIds();
1018 NS_ASSERT(!linkIds.empty());
1019 uint8_t linkId = *linkIds.begin();
1020 if (const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId)))
1021 {
1022 hdr.SetAddr1(*apMldAddr);
1023 hdr.SetAddr2(GetAddress());
1024 }
1025 else
1026 {
1027 hdr.SetAddr1(GetBssid(linkId));
1029 }
1030
1031 hdr.SetAddr3(to);
1032 hdr.SetDsNotFrom();
1033 hdr.SetDsTo();
1034
1035 if (GetQosSupported())
1036 {
1037 // Sanity check that the TID is valid
1038 NS_ASSERT(tid < 8);
1039 GetQosTxop(tid)->Queue(packet, hdr);
1040 }
1041 else
1042 {
1043 GetTxop()->Queue(packet, hdr);
1044 }
1045}
1046
1047void
1049{
1050 NS_LOG_FUNCTION(this << linkId << reason);
1051
1052 auto bssid = GetBssid(linkId);
1053 auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1054
1055 BlockUnicastTxOnLinks(reason, apAddress, {linkId});
1056 // the only type of broadcast frames that a non-AP STA can send are management frames
1057 for (const auto& [acIndex, ac] : wifiAcList)
1058 {
1059 GetMacQueueScheduler()->BlockQueues(reason,
1060 acIndex,
1063 GetFrameExchangeManager(linkId)->GetAddress(),
1064 {},
1065 {linkId});
1066 }
1067}
1068
1069void
1070StaWifiMac::UnblockTxOnLink(std::set<uint8_t> linkIds, WifiQueueBlockedReason reason)
1071{
1072 std::stringstream ss;
1073 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
1074 NS_LOG_FUNCTION(this << ss.str() << reason);
1075
1076 const auto linkId = *linkIds.cbegin();
1077 const auto bssid = GetBssid(linkId);
1078 const auto apAddress =
1079 GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1080
1081 UnblockUnicastTxOnLinks(reason, apAddress, linkIds);
1082 // the only type of broadcast frames that a non-AP STA can send are management frames
1083 for (const auto& [acIndex, ac] : wifiAcList)
1084 {
1085 GetMacQueueScheduler()->UnblockQueues(reason,
1086 acIndex,
1089 GetFrameExchangeManager(linkId)->GetAddress(),
1090 {},
1091 linkIds);
1092 }
1093}
1094
1095void
1097{
1098 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1099 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1100 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1101 Ptr<const Packet> packet = mpdu->GetPacket();
1102 NS_ASSERT(!hdr->IsCtl());
1104 : GetFrameExchangeManager(linkId)->GetAddress();
1105 if (hdr->GetAddr3() == myAddr)
1106 {
1107 NS_LOG_LOGIC("packet sent by us.");
1108 return;
1109 }
1110 if (hdr->GetAddr1() != myAddr && !hdr->GetAddr1().IsGroup())
1111 {
1112 NS_LOG_LOGIC("packet is not for us");
1113 NotifyRxDrop(packet);
1114 return;
1115 }
1116 if (hdr->IsData())
1117 {
1118 if (!IsAssociated())
1119 {
1120 NS_LOG_LOGIC("Received data frame while not associated: ignore");
1121 NotifyRxDrop(packet);
1122 return;
1123 }
1124 if (!(hdr->IsFromDs() && !hdr->IsToDs()))
1125 {
1126 NS_LOG_LOGIC("Received data frame not from the DS: ignore");
1127 NotifyRxDrop(packet);
1128 return;
1129 }
1130 std::set<Mac48Address> apAddresses; // link addresses of AP
1131 for (auto id : GetSetupLinkIds())
1132 {
1133 apAddresses.insert(GetBssid(id));
1134 }
1135 if (!apAddresses.contains(mpdu->GetHeader().GetAddr2()))
1136 {
1137 NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
1138 NotifyRxDrop(packet);
1139 return;
1140 }
1141 if (!hdr->HasData())
1142 {
1143 NS_LOG_LOGIC("Received (QoS) Null Data frame: ignore");
1144 NotifyRxDrop(packet);
1145 return;
1146 }
1147 if (hdr->IsQosData())
1148 {
1149 if (hdr->IsQosAmsdu())
1150 {
1151 NS_ASSERT(apAddresses.contains(mpdu->GetHeader().GetAddr3()));
1153 packet = nullptr;
1154 }
1155 else
1156 {
1157 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1158 }
1159 }
1160 else
1161 {
1162 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1163 }
1164 return;
1165 }
1166
1167 switch (hdr->GetType())
1168 {
1172 // This is a frame aimed at an AP, so we can safely ignore it.
1173 NotifyRxDrop(packet);
1174 break;
1175
1177 ReceiveBeacon(mpdu, linkId);
1178 break;
1179
1181 ReceiveProbeResp(mpdu, linkId);
1182 break;
1183
1186 ReceiveAssocResp(mpdu, linkId);
1187 break;
1188
1190 if (auto [category, action] = WifiActionHeader::Peek(packet);
1191 category == WifiActionHeader::PROTECTED_EHT &&
1192 action.protectedEhtAction ==
1194 {
1195 // this is handled by the EMLSR Manager
1196 break;
1197 }
1198
1199 default:
1200 // Invoke the receive handler of our parent class to deal with any
1201 // other frames. Specifically, this will handle Block Ack-related
1202 // Management Action frames.
1203 WifiMac::Receive(mpdu, linkId);
1204 }
1205
1206 if (m_emlsrManager)
1207 {
1208 m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
1209 }
1210}
1211
1212void
1214{
1215 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1216 const WifiMacHeader& hdr = mpdu->GetHeader();
1217 NS_ASSERT(hdr.IsBeacon());
1218
1219 NS_LOG_DEBUG("Beacon received");
1220 MgtBeaconHeader beacon;
1221 mpdu->GetPacket()->PeekHeader(beacon);
1222 const auto& capabilities = beacon.Capabilities();
1223 NS_ASSERT(capabilities.IsEss());
1224 bool goodBeacon;
1225 if (IsWaitAssocResp() || IsAssociated())
1226 {
1227 // we have to process this Beacon only if sent by the AP we are associated
1228 // with or from which we are waiting an Association Response frame
1229 auto bssid = GetLink(linkId).bssid;
1230 goodBeacon = bssid.has_value() && (hdr.GetAddr3() == *bssid);
1231 }
1232 else
1233 {
1234 // we retain this Beacon as candidate AP if the supported rates fit the
1235 // configured BSS membership selector
1236 goodBeacon = CheckSupportedRates(beacon, linkId);
1237 }
1238
1239 SnrTag snrTag;
1240 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1241 NS_ASSERT(found);
1242 ApInfo apInfo = {.m_bssid = hdr.GetAddr3(),
1243 .m_apAddr = hdr.GetAddr2(),
1244 .m_snr = snrTag.Get(),
1245 .m_frame = std::move(beacon),
1246 .m_channel = {GetCurrentChannel(linkId)},
1247 .m_linkId = linkId};
1248
1249 if (!m_beaconInfo.IsEmpty())
1250 {
1251 m_beaconInfo(apInfo);
1252 }
1253
1254 if (!goodBeacon)
1255 {
1256 NS_LOG_LOGIC("Beacon is not for us");
1257 return;
1258 }
1259 if (m_state == ASSOCIATED)
1260 {
1262 Time delay = MicroSeconds(std::get<MgtBeaconHeader>(apInfo.m_frame).GetBeaconIntervalUs() *
1264 RestartBeaconWatchdog(delay);
1265 UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1266 }
1267 else
1268 {
1269 NS_LOG_DEBUG("Beacon received from " << hdr.GetAddr2());
1270 m_assocManager->NotifyApInfo(std::move(apInfo));
1271 }
1272}
1273
1274void
1276{
1277 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1278 const WifiMacHeader& hdr = mpdu->GetHeader();
1279 NS_ASSERT(hdr.IsProbeResp());
1280
1281 NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2());
1282 MgtProbeResponseHeader probeResp;
1283 mpdu->GetPacket()->PeekHeader(probeResp);
1284 if (!CheckSupportedRates(probeResp, linkId))
1285 {
1286 return;
1287 }
1288 SnrTag snrTag;
1289 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1290 NS_ASSERT(found);
1291 m_assocManager->NotifyApInfo(ApInfo{.m_bssid = hdr.GetAddr3(),
1292 .m_apAddr = hdr.GetAddr2(),
1293 .m_snr = snrTag.Get(),
1294 .m_frame = std::move(probeResp),
1295 .m_channel = {GetCurrentChannel(linkId)},
1296 .m_linkId = linkId});
1297}
1298
1299void
1301{
1302 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1303 const WifiMacHeader& hdr = mpdu->GetHeader();
1304 NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp());
1305
1306 if (m_state != WAIT_ASSOC_RESP)
1307 {
1308 return;
1309 }
1310
1311 std::optional<Mac48Address> apMldAddress;
1312 MgtAssocResponseHeader assocResp;
1313 mpdu->GetPacket()->PeekHeader(assocResp);
1315 {
1317 }
1318 if (assocResp.GetStatusCode().IsSuccess())
1319 {
1320 m_aid = assocResp.GetAssociationId();
1321 NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed"));
1322 UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1323 NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
1324 SetBssid(hdr.GetAddr3(), linkId);
1326 if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
1327 {
1328 // this is an ML setup, trace the setup link
1329 m_setupCompleted(linkId, hdr.GetAddr3());
1330 apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
1331 NS_ASSERT(apMldAddress);
1332
1333 if (const auto& mldCapabilities =
1334 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
1335 mldCapabilities && static_cast<WifiTidToLinkMappingNegSupport>(
1336 mldCapabilities->get().tidToLinkMappingSupport) >
1338 {
1339 // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
1340 // TID-to-Link Mapping element(s) in the Association Request.
1341 if (assocResp.Get<TidToLinkMapping>().empty())
1342 {
1343 // The AP MLD did not include a TID-to-Link Mapping element in the Association
1344 // Response, hence it accepted the mapping, which we can now store.
1345 UpdateTidToLinkMapping(*apMldAddress,
1348 UpdateTidToLinkMapping(*apMldAddress,
1351
1352 // Apply the negotiated TID-to-Link Mapping (if any) for UL direction
1354 }
1355 }
1356 }
1357 else
1358 {
1359 m_assocLogger(hdr.GetAddr3());
1360 }
1361 if (!m_linkUp.IsNull())
1362 {
1363 m_linkUp();
1364 }
1365 }
1366 else
1367 {
1368 // If the link on which the (Re)Association Request frame was received cannot be
1369 // accepted by the AP MLD, the AP MLD shall treat the multi-link (re)setup as a
1370 // failure and shall not accept any requested links. If the link on which the
1371 // (Re)Association Request frame was received is accepted by the AP MLD, the
1372 // multi-link (re)setup is successful. (Sec. 35.3.5.1 of 802.11be D3.1)
1373 NS_LOG_DEBUG("association refused");
1375 StartScanning();
1376 return;
1377 }
1378
1379 // if this is an MLD, check if we can setup (other) links
1380 if (GetNLinks() > 1)
1381 {
1382 // create a list of all local Link IDs. IDs are removed as we find a corresponding
1383 // Per-STA Profile Subelements indicating successful association. Links with
1384 // remaining IDs are not setup
1385 std::list<uint8_t> setupLinks;
1386 for (const auto& [id, link] : GetLinks())
1387 {
1388 setupLinks.push_back(id);
1389 }
1390 if (assocResp.GetStatusCode().IsSuccess())
1391 {
1392 setupLinks.remove(linkId);
1393 }
1394
1395 // if a Multi-Link Element is present, check its content
1396 if (const auto& mle = assocResp.Get<MultiLinkElement>())
1397 {
1398 NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
1399 "The link on which the Association Response was received "
1400 "is not a link we requested to setup");
1401 NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
1402 "The link ID of the AP that transmitted the Association "
1403 "Response does not match the stored link ID");
1405 mle->GetMldMacAddress(),
1406 "The AP MLD MAC address in the received Multi-Link Element does not "
1407 "match the address stored in the station manager for link "
1408 << +linkId);
1409 // process the Per-STA Profile Subelements in the Multi-Link Element
1410 for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
1411 {
1412 auto& perStaProfile = mle->GetPerStaProfile(elem);
1413 uint8_t apLinkId = perStaProfile.GetLinkId();
1414 auto it = GetLinks().find(apLinkId);
1415 uint8_t staLinkid = 0;
1416 std::optional<Mac48Address> bssid;
1417 NS_ABORT_MSG_IF(it == GetLinks().cend() ||
1418 !(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
1419 "Setup for AP link ID " << apLinkId << " was not requested");
1420 NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
1421 "The BSSID in the Per-STA Profile for link ID "
1422 << +staLinkid << " does not match the stored BSSID");
1425 perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
1426 "The AP MLD MAC address in the received Multi-Link Element does not "
1427 "match the address stored in the station manager for link "
1428 << +staLinkid);
1429 // process the Association Response contained in this Per-STA Profile
1430 MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
1431 if (assoc.GetStatusCode().IsSuccess())
1432 {
1433 NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
1434 "AID should be the same for all the links");
1435 m_aid = assoc.GetAssociationId();
1436 NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
1437 UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
1438 SetBssid(*bssid, staLinkid);
1439 m_setupCompleted(staLinkid, *bssid);
1441 apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
1442 if (!m_linkUp.IsNull())
1443 {
1444 m_linkUp();
1445 }
1446 }
1447 // remove the ID of the link we setup
1448 setupLinks.remove(staLinkid);
1449 }
1450 }
1451 // remaining links in setupLinks are not setup and hence must be disabled
1452 for (const auto& id : setupLinks)
1453 {
1454 GetLink(id).bssid = std::nullopt;
1455 GetLink(id).phy->SetOffMode();
1456 }
1457 if (apMldAddress)
1458 {
1459 // this is an ML setup, trace the MLD address of the AP (only once)
1460 m_assocLogger(*apMldAddress);
1461 }
1462 }
1463
1464 // the station that associated with the AP may have dissociated and then associated again.
1465 // In this case, the station may store packets from the previous period in which it was
1466 // associated. Have the station restart access if it has packets queued.
1467 for (const auto& [id, link] : GetLinks())
1468 {
1469 if (GetStaLink(link).bssid)
1470 {
1471 if (const auto txop = GetTxop())
1472 {
1473 txop->StartAccessAfterEvent(id,
1476 }
1477 for (const auto& [acIndex, ac] : wifiAcList)
1478 {
1479 if (const auto edca = GetQosTxop(acIndex))
1480 {
1481 edca->StartAccessAfterEvent(id,
1484 }
1485 }
1486 }
1487 }
1488
1490}
1491
1492void
1494{
1495 NS_LOG_FUNCTION(this << linkId);
1496
1497 // STAs operating on setup links may need to transition to a new PM mode after the
1498 // acknowledgement of the Association Response. For this purpose, we connect a callback to
1499 // the PHY TX begin trace to catch the Ack transmitted after the Association Response.
1501 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, double /* txPowerW */) {
1502 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
1503 psduMap.begin()->second->GetHeader(0).IsAck(),
1504 "Expected a Normal Ack after Association Response frame");
1505
1506 auto ackDuration =
1507 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
1508
1509 for (const auto& [id, lnk] : GetLinks())
1510 {
1511 auto& link = GetStaLink(lnk);
1512
1513 if (!link.bssid)
1514 {
1515 // link has not been setup
1516 continue;
1517 }
1518
1519 if (id == linkId)
1520 {
1521 /**
1522 * When a link becomes enabled for a non-AP STA that is affiliated with a
1523 * non-AP MLD after successful association with an AP MLD with (Re)Association
1524 * Request/Response frames transmitted on that link [..], the power management
1525 * mode of the non-AP STA, immediately after the acknowledgement of the
1526 * (Re)Association Response frame [..], is active mode.
1527 * (Sec. 35.3.7.1.4 of 802.11be D3.0)
1528 */
1529 // if the user requested this link to be in powersave mode, we have to
1530 // switch PM mode
1531 if (link.pmMode == WIFI_PM_POWERSAVE)
1532 {
1533 Simulator::Schedule(ackDuration,
1535 this,
1536 std::pair<bool, uint8_t>{true, id});
1537 }
1538 link.pmMode = WIFI_PM_ACTIVE;
1539 }
1540 else
1541 {
1542 /**
1543 * When a link becomes enabled for a non-AP STA that is affiliated with a
1544 * non-AP MLD after successful association with an AP MLD with (Re)Association
1545 * Request/Response frames transmitted on another link [..], the power
1546 * management mode of the non-AP STA, immediately after the acknowledgement of
1547 * the (Re)Association Response frame [..], is power save mode, and its power
1548 * state is doze. (Sec. 35.3.7.1.4 of 802.11be D3.0)
1549 */
1550 // if the user requested this link to be in active mode, we have to
1551 // switch PM mode
1552 if (link.pmMode == WIFI_PM_ACTIVE)
1553 {
1554 Simulator::Schedule(ackDuration,
1556 this,
1557 std::pair<bool, uint8_t>{false, id});
1558 }
1559 link.pmMode = WIFI_PM_POWERSAVE;
1560 }
1561 }
1562 });
1563
1564 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
1565 // after its transmission begins
1566 auto phy = GetLink(linkId).phy;
1567 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
1568 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
1569 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
1570}
1571
1572bool
1573StaWifiMac::CheckSupportedRates(std::variant<MgtBeaconHeader, MgtProbeResponseHeader> frame,
1574 uint8_t linkId)
1575{
1576 NS_LOG_FUNCTION(this << +linkId);
1577
1578 // lambda to invoke on the current frame variant
1579 auto check = [&](auto&& mgtFrame) -> bool {
1580 // check supported rates
1581 NS_ASSERT(mgtFrame.template Get<SupportedRates>());
1582 const auto rates = AllSupportedRates{*mgtFrame.template Get<SupportedRates>(),
1583 mgtFrame.template Get<ExtendedSupportedRatesIE>()};
1584 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1585 {
1586 if (!rates.IsBssMembershipSelectorRate(selector))
1587 {
1588 NS_LOG_DEBUG("Supported rates do not fit with the BSS membership selector");
1589 return false;
1590 }
1591 }
1592
1593 return true;
1594 };
1595
1596 return std::visit(check, frame);
1597}
1598
1599void
1601 const Mac48Address& apAddr,
1602 const Mac48Address& bssid,
1603 uint8_t linkId)
1604{
1605 NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId);
1606
1607 // ERP Information is not present in Association Response frames
1608 const std::optional<ErpInformation>* erpInformation = nullptr;
1609
1610 if (const auto* beacon = std::get_if<MgtBeaconHeader>(&frame))
1611 {
1612 erpInformation = &beacon->Get<ErpInformation>();
1613 }
1614 else if (const auto* probe = std::get_if<MgtProbeResponseHeader>(&frame))
1615 {
1616 erpInformation = &probe->Get<ErpInformation>();
1617 }
1618
1619 // lambda processing Information Elements included in all frame types
1620 auto commonOps = [&](auto&& frame) {
1621 const auto& capabilities = frame.Capabilities();
1622 NS_ASSERT(frame.template Get<SupportedRates>());
1623 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1624 frame.template Get<ExtendedSupportedRatesIE>()};
1625 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1626 {
1627 if (rates.IsSupportedRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1628 {
1629 GetWifiRemoteStationManager(linkId)->AddSupportedMode(apAddr, mode);
1630 if (rates.IsBasicRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1631 {
1632 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
1633 }
1634 }
1635 }
1636
1637 bool isShortPreambleEnabled = capabilities.IsShortPreamble();
1638 if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId))
1639 {
1640 isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode();
1641 if ((*erpInformation)->GetUseProtection() != 0)
1642 {
1643 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(true);
1644 }
1645 else
1646 {
1647 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(false);
1648 }
1649 if (capabilities.IsShortSlotTime() == true)
1650 {
1651 // enable short slot time
1652 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1653 }
1654 else
1655 {
1656 // disable short slot time
1657 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1658 }
1659 }
1660 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled);
1661 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1662 capabilities.IsShortSlotTime());
1663
1664 if (!GetQosSupported())
1665 {
1666 return;
1667 }
1668 /* QoS station */
1669 bool qosSupported = false;
1670 const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
1671 if (edcaParameters.has_value())
1672 {
1673 qosSupported = true;
1674 // The value of the TXOP Limit field is specified as an unsigned integer, with the least
1675 // significant octet transmitted first, in units of 32 μs.
1677 edcaParameters->GetBeCWmin(),
1678 edcaParameters->GetBeCWmax(),
1679 edcaParameters->GetBeAifsn(),
1680 32 * MicroSeconds(edcaParameters->GetBeTxopLimit())},
1681 linkId);
1683 edcaParameters->GetBkCWmin(),
1684 edcaParameters->GetBkCWmax(),
1685 edcaParameters->GetBkAifsn(),
1686 32 * MicroSeconds(edcaParameters->GetBkTxopLimit())},
1687 linkId);
1689 edcaParameters->GetViCWmin(),
1690 edcaParameters->GetViCWmax(),
1691 edcaParameters->GetViAifsn(),
1692 32 * MicroSeconds(edcaParameters->GetViTxopLimit())},
1693 linkId);
1695 edcaParameters->GetVoCWmin(),
1696 edcaParameters->GetVoCWmax(),
1697 edcaParameters->GetVoAifsn(),
1698 32 * MicroSeconds(edcaParameters->GetVoTxopLimit())},
1699 linkId);
1700 }
1701 GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
1702
1703 if (!GetHtSupported())
1704 {
1705 return;
1706 }
1707 /* HT station */
1708 if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
1709 htCapabilities.has_value())
1710 {
1711 if (!htCapabilities->IsSupportedMcs(0))
1712 {
1713 GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
1714 }
1715 else
1716 {
1717 GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
1718 *htCapabilities);
1719 }
1720 }
1721 // TODO: process ExtendedCapabilities
1722 // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
1723
1724 // we do not return if VHT is not supported because HE STAs operating in
1725 // the 2.4 GHz band do not support VHT
1726 if (GetVhtSupported(linkId))
1727 {
1728 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1729 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1730 // to check whether it supports VHT
1731 if (vhtCapabilities.has_value() &&
1732 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1733 {
1734 GetWifiRemoteStationManager(linkId)->AddStationVhtCapabilities(apAddr,
1735 *vhtCapabilities);
1736 // const auto& vhtOperation = frame.GetVhtOperation ();
1737 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_VHT))
1738 {
1739 if (vhtCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1740 {
1741 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1742 }
1743 }
1744 }
1745 }
1746
1747 if (!GetHeSupported())
1748 {
1749 return;
1750 }
1751 /* HE station */
1752 const auto& heCapabilities = frame.template Get<HeCapabilities>();
1753 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1754 {
1755 GetWifiRemoteStationManager(linkId)->AddStationHeCapabilities(apAddr, *heCapabilities);
1756 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_HE))
1757 {
1758 if (heCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1759 {
1760 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1761 }
1762 }
1763 if (const auto& heOperation = frame.template Get<HeOperation>();
1764 heOperation.has_value())
1765 {
1766 GetHeConfiguration()->SetAttribute("BssColor",
1767 UintegerValue(heOperation->GetBssColor()));
1768 }
1769 }
1770
1771 const auto& muEdcaParameters = frame.template Get<MuEdcaParameterSet>();
1772 if (muEdcaParameters.has_value())
1773 {
1775 muEdcaParameters->GetMuCwMin(AC_BE),
1776 muEdcaParameters->GetMuCwMax(AC_BE),
1777 muEdcaParameters->GetMuAifsn(AC_BE),
1778 muEdcaParameters->GetMuEdcaTimer(AC_BE)},
1779 linkId);
1781 muEdcaParameters->GetMuCwMin(AC_BK),
1782 muEdcaParameters->GetMuCwMax(AC_BK),
1783 muEdcaParameters->GetMuAifsn(AC_BK),
1784 muEdcaParameters->GetMuEdcaTimer(AC_BK)},
1785 linkId);
1787 muEdcaParameters->GetMuCwMin(AC_VI),
1788 muEdcaParameters->GetMuCwMax(AC_VI),
1789 muEdcaParameters->GetMuAifsn(AC_VI),
1790 muEdcaParameters->GetMuEdcaTimer(AC_VI)},
1791 linkId);
1793 muEdcaParameters->GetMuCwMin(AC_VO),
1794 muEdcaParameters->GetMuCwMax(AC_VO),
1795 muEdcaParameters->GetMuAifsn(AC_VO),
1796 muEdcaParameters->GetMuEdcaTimer(AC_VO)},
1797 linkId);
1798 }
1799
1800 if (!GetEhtSupported())
1801 {
1802 return;
1803 }
1804 /* EHT station */
1805 const auto& ehtCapabilities = frame.template Get<EhtCapabilities>();
1806 // TODO: once we support non constant rate managers, we should add checks here whether EHT
1807 // is supported by the peer
1808 GetWifiRemoteStationManager(linkId)->AddStationEhtCapabilities(apAddr, *ehtCapabilities);
1809
1810 if (const auto& mle = frame.template Get<MultiLinkElement>(); mle && m_emlsrManager)
1811 {
1812 if (mle->HasEmlCapabilities())
1813 {
1814 m_emlsrManager->SetTransitionTimeout(mle->GetTransitionTimeout());
1815 }
1816 if (const auto& common = mle->GetCommonInfoBasic(); common.m_mediumSyncDelayInfo)
1817 {
1818 m_emlsrManager->SetMediumSyncDuration(common.GetMediumSyncDelayTimer());
1819 m_emlsrManager->SetMediumSyncOfdmEdThreshold(common.GetMediumSyncOfdmEdThreshold());
1820 m_emlsrManager->SetMediumSyncMaxNTxops(common.GetMediumSyncMaxNTxops());
1821 }
1822 }
1823 };
1824
1825 // process Information Elements included in the current frame variant
1826 std::visit(commonOps, frame);
1827}
1828
1829void
1830StaWifiMac::SetPowerSaveMode(const std::pair<bool, uint8_t>& enableLinkIdPair)
1831{
1832 const auto [enable, linkId] = enableLinkIdPair;
1833 NS_LOG_FUNCTION(this << enable << linkId);
1834
1835 auto& link = GetLink(linkId);
1836
1837 if (!IsAssociated())
1838 {
1839 NS_LOG_DEBUG("Not associated yet, record the PM mode to switch to upon association");
1840 link.pmMode = enable ? WIFI_PM_POWERSAVE : WIFI_PM_ACTIVE;
1841 return;
1842 }
1843
1844 if (!link.bssid)
1845 {
1846 NS_LOG_DEBUG("Link " << +linkId << " has not been setup, ignore request");
1847 return;
1848 }
1849
1850 if ((enable && link.pmMode == WIFI_PM_POWERSAVE) || (!enable && link.pmMode == WIFI_PM_ACTIVE))
1851 {
1852 NS_LOG_DEBUG("No PM mode change needed");
1853 return;
1854 }
1855
1857
1858 // reschedule a call to this function to make sure that the PM mode switch
1859 // is eventually completed
1862 this,
1863 enableLinkIdPair);
1864
1865 if (HasFramesToTransmit(linkId))
1866 {
1867 NS_LOG_DEBUG("Next transmitted frame will be sent with PM=" << enable);
1868 return;
1869 }
1870
1871 // No queued frames. Enqueue a Data Null frame to inform the AP of the PM mode change
1873
1874 hdr.SetAddr1(GetBssid(linkId));
1876 hdr.SetAddr3(GetBssid(linkId));
1877 hdr.SetDsNotFrom();
1878 hdr.SetDsTo();
1879 enable ? hdr.SetPowerManagement() : hdr.SetNoPowerManagement();
1880 if (GetQosSupported())
1881 {
1882 GetQosTxop(AC_BE)->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1883 }
1884 else
1885 {
1886 m_txop->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1887 }
1888}
1889
1891StaWifiMac::GetPmMode(uint8_t linkId) const
1892{
1893 return GetLink(linkId).pmMode;
1894}
1895
1896void
1898{
1899 NS_LOG_FUNCTION(this << *mpdu);
1900
1901 auto linkId = GetLinkIdByAddress(mpdu->GetHeader().GetAddr2());
1902
1903 if (!linkId)
1904 {
1905 // the given MPDU may be the original copy containing MLD addresses and not carrying
1906 // a valid PM bit (which is set on the aliases).
1907 auto linkIds = mpdu->GetInFlightLinkIds();
1908 NS_ASSERT_MSG(!linkIds.empty(),
1909 "The TA of the acked MPDU (" << *mpdu
1910 << ") is not a link "
1911 "address and the MPDU is not inflight");
1912 // in case the ack'ed MPDU is inflight on multiple links, we cannot really know if
1913 // it was received by the AP on all links or only on some links. Hence, we only
1914 // consider the first link ID in the set, given that in the most common case of MPDUs
1915 // that cannot be sent concurrently on multiple links, there will be only one link ID
1916 linkId = *linkIds.begin();
1917 mpdu = GetTxopQueue(mpdu->GetQueueAc())->GetAlias(mpdu, *linkId);
1918 }
1919
1920 auto& link = GetLink(*linkId);
1921 const WifiMacHeader& hdr = mpdu->GetHeader();
1922
1923 // we received an acknowledgment while switching PM mode; the PM mode change is effective now
1924 if (hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_PS)
1925 {
1926 link.pmMode = WIFI_PM_POWERSAVE;
1927 }
1928 else if (!hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_ACTIVE)
1929 {
1930 link.pmMode = WIFI_PM_ACTIVE;
1931 }
1932}
1933
1936{
1937 AllSupportedRates rates;
1938 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1939 {
1940 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
1941 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
1942 rates.AddSupportedRate(modeDataRate);
1943 }
1944 if (GetHtSupported())
1945 {
1946 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1947 {
1948 rates.AddBssMembershipSelectorRate(selector);
1949 }
1950 }
1951 return rates;
1952}
1953
1955StaWifiMac::GetCapabilities(uint8_t linkId) const
1956{
1957 CapabilityInformation capabilities;
1958 capabilities.SetShortPreamble(GetWifiPhy(linkId)->GetShortPhyPreambleSupported() ||
1959 GetErpSupported(linkId));
1961 return capabilities;
1962}
1963
1964void
1966{
1967 m_state = value;
1968}
1969
1970void
1971StaWifiMac::SetEdcaParameters(const EdcaParams& params, uint8_t linkId)
1972{
1973 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1974 edca->SetMinCw(params.cwMin, linkId);
1975 edca->SetMaxCw(params.cwMax, linkId);
1976 edca->SetAifsn(params.aifsn, linkId);
1977 edca->SetTxopLimit(params.txopLimit, linkId);
1978}
1979
1980void
1981StaWifiMac::SetMuEdcaParameters(const MuEdcaParams& params, uint8_t linkId)
1982{
1983 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1984 edca->SetMuCwMin(params.cwMin, linkId);
1985 edca->SetMuCwMax(params.cwMax, linkId);
1986 edca->SetMuAifsn(params.aifsn, linkId);
1987 edca->SetMuEdcaTimer(params.muEdcaTimer, linkId);
1988}
1989
1990void
1992{
1993 NS_LOG_FUNCTION(this);
1994 if (IsAssociated())
1995 {
1996 NS_LOG_DEBUG("PHY capabilities changed: send reassociation request");
1999 }
2000}
2001
2002/**
2003 * Initial configuration:
2004 *
2005 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2006 * Link A │FEM│RSM│CAM│◄──────►│Main├──────►│Channel│
2007 * │ │ │ │ │PHY │ │ A │
2008 * └───┴───┴───┘ └────┘ └───────┘
2009 *
2010 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2011 * Link B │FEM│RSM│CAM│ │Aux │ │Channel│
2012 * │ │ │ │◄──────►│PHY ├──────►│ B │
2013 * └───┴───┴───┘ └────┘ └───────┘
2014 *
2015 * A link switching/swapping is notified by the EMLSR Manager and the Channel Access Manager
2016 * (CAM) notifies us that a first PHY (i.e., the Main PHY) switches to Channel B. We connect
2017 * the Main PHY to the MAC stack B:
2018 *
2019 *
2020 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2021 * Link A │FEM│RSM│CAM│ ┌───►│Main├───┐ │Channel│
2022 * │ │ │ │ │ │PHY │ │ │ A │
2023 * └───┴───┴───┘ │ └────┘ │ └───────┘
2024 * │ │
2025 * ┌───┬───┬───┐ │ ┌────┐ │ ┌───────┐
2026 * Link B │FEM│RSM│CAM│◄──┘ │Aux │ └──►│Channel│
2027 * │ │ │ │◄─ ─ ─ ─│PHY ├──────►│ B │
2028 * └───┴───┴───┘INACTIVE└────┘ └───────┘
2029 *
2030 * MAC stack B keeps a PHY listener associated with the Aux PHY, even though it is inactive,
2031 * meaning that the PHY listener will only notify channel switches (no CCA, no RX).
2032 * If the EMLSR Manager requested a link switching, this configuration will be kept until
2033 * further requests. If the EMLSR Manager requested a link swapping, link B's CAM will be
2034 * notified by its (inactive) PHY listener upon the channel switch performed by the Aux PHY.
2035 * In this case, we remove the inactive PHY listener and connect the Aux PHY to MAC stack A:
2036 *
2037 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2038 * Link A │FEM│RSM│CAM│◄─┐ ┌──►│Main├───┐ │Channel│
2039 * │ │ │ │ │ │ │PHY │ ┌─┼──►│ A │
2040 * └───┴───┴───┘ │ │ └────┘ │ │ └───────┘
2041 * │ │ │ │
2042 * ┌───┬───┬───┐ │ │ ┌────┐ │ │ ┌───────┐
2043 * Link B │FEM│RSM│CAM│◄─┼─┘ │Aux │ │ └──►│Channel│
2044 * │ │ │ │ └────►│PHY ├─┘ │ B │
2045 * └───┴───┴───┘ └────┘ └───────┘
2046 */
2047
2048void
2050{
2051 NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
2052
2053 // If the PHY is switching channel to operate on another link, then it is no longer operating
2054 // on the current link. If any link (other than the current link) points to the PHY that is
2055 // switching channel, reset the phy pointer of the link
2056 for (auto& [id, link] : GetLinks())
2057 {
2058 if (link->phy == phy && id != linkId)
2059 {
2060 link->phy = nullptr;
2061 }
2062 }
2063
2064 // lambda to connect the PHY to the new link
2065 auto connectPhy = [=, this]() mutable {
2066 auto& newLink = GetLink(linkId);
2067 // The MAC stack associated with the new link uses the given PHY
2068 newLink.phy = phy;
2069 // Setup a PHY listener for the given PHY on the CAM associated with the new link
2070 newLink.channelAccessManager->SetupPhyListener(phy);
2072 if (m_emlsrManager->GetCamStateReset())
2073 {
2074 newLink.channelAccessManager->ResetState();
2075 }
2076 // Disconnect the FEM on the new link from the current PHY
2077 newLink.feManager->ResetPhy();
2078 // Connect the FEM on the new link to the given PHY
2079 newLink.feManager->SetWifiPhy(phy);
2080 // Connect the station manager on the new link to the given PHY
2081 newLink.stationManager->SetupPhy(phy);
2082 };
2083
2084 // if there is no PHY operating on the new link, connect the PHY to the new link now.
2085 // Otherwise, wait until the channel switch is completed, so that the PHY operating on the new
2086 // link can possibly continue receiving frames in the meantime.
2087 if (!GetLink(linkId).phy)
2088 {
2089 connectPhy();
2090 }
2091 else
2092 {
2093 Simulator::Schedule(delay, connectPhy);
2094 }
2095}
2096
2097void
2099{
2100 NS_LOG_FUNCTION(this << +linkId);
2101
2103
2104 if (IsInitialized() && IsAssociated())
2105 {
2106 Disassociated();
2107 }
2108
2109 // notify association manager
2110 m_assocManager->NotifyChannelSwitched(linkId);
2111}
2112
2113std::ostream&
2114operator<<(std::ostream& os, const StaWifiMac::ApInfo& apInfo)
2115{
2116 os << "BSSID=" << apInfo.m_bssid << ", AP addr=" << apInfo.m_apAddr << ", SNR=" << apInfo.m_snr
2117 << ", Channel={" << apInfo.m_channel.number << "," << apInfo.m_channel.band
2118 << "}, Link ID=" << +apInfo.m_linkId << ", Frame=[";
2119 std::visit([&os](auto&& frame) { frame.Print(os); }, apInfo.m_frame);
2120 os << "]";
2121 return os;
2122}
2123
2124} // namespace ns3
A container for one type of attribute.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Base class for Callback class.
Definition: callback.h:360
Callback template class.
Definition: callback.h:438
bool IsNull() const
Check for null implementation.
Definition: callback.h:571
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:62
T Get() const
Definition: enum.h:97
The ErpInformation Information Element.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:69
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
The IEEE 802.11ax HE Capabilities.
The HT Capabilities Information Element.
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address GetBroadcast()
Implement the header for management frames of type association request.
Definition: mgt-headers.h:157
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:334
StatusCode GetStatusCode()
Return the status code.
Definition: mgt-headers.cc:456
uint16_t GetAssociationId() const
Return the association ID.
Definition: mgt-headers.cc:486
Implement the header for management frames of type beacon.
Definition: mgt-headers.h:512
Implement the header for management frames of type probe request.
Definition: mgt-headers.h:432
Implement the header for management frames of type probe response.
Definition: mgt-headers.h:451
CapabilityInformation & Capabilities()
Definition: mgt-headers.cc:93
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:241
void SetCurrentApAddress(Mac48Address currentApAddr)
Set the address of the current access point.
Definition: mgt-headers.cc:331
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:322
bool IsInitialized() const
Check if the object has been initialized.
Definition: object.cc:251
AttributeValue implementation for Pair.
Definition: pair.h:65
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:217
Introspection did not find any typical Config paths.
Definition: snr-tag.h:35
double Get() const
Return the SNR value.
Definition: snr-tag.cc:90
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
The Wifi MAC high model for a non-AP STA in a BSS.
Definition: sta-wifi-mac.h:143
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
Definition: sta-wifi-mac.h:607
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.
Definition: sta-wifi-mac.h:605
bool m_activeProbing
active probing
Definition: sta-wifi-mac.h:614
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
Definition: sta-wifi-mac.h:613
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
Definition: sta-wifi-mac.h:626
MacState
The current MAC state of the STA.
Definition: sta-wifi-mac.h:373
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
Definition: sta-wifi-mac.h:612
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.
Definition: sta-wifi-mac.cc:60
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.
StaLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
uint32_t m_maxMissedBeacons
maximum missed beacons
Definition: sta-wifi-mac.h:611
TracedCallback< uint8_t, Mac48Address > m_setupCompleted
link setup completed logger
Definition: sta-wifi-mac.h:625
TracedCallback< Mac48Address > m_assocLogger
association logger
Definition: sta-wifi-mac.h:624
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
Definition: sta-wifi-mac.h:627
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.
Time m_pmModeSwitchTimeout
PM mode switch timeout.
Definition: sta-wifi-mac.h:617
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
Definition: sta-wifi-mac.h:622
WifiPowerManagementMode GetPmMode(uint8_t linkId) const
Ptr< RandomVariableStream > m_probeDelay
RandomVariable used to randomize the time of the first Probe Response on each channel.
Definition: sta-wifi-mac.h:615
TracedCallback< ApInfo > m_beaconInfo
beacon info logger
Definition: sta-wifi-mac.h:629
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.
Definition: sta-wifi-mac.h:604
MacState m_state
MAC state.
Definition: sta-wifi-mac.h:603
bool IsEmlsrLink(uint8_t linkId) const
void Enqueue(Ptr< Packet > packet, Mac48Address to) override
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
Definition: sta-wifi-mac.h:628
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.
Ptr< EmlsrManager > m_emlsrManager
EMLSR Manager.
Definition: sta-wifi-mac.h:606
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
Definition: sta-wifi-mac.h:609
void ReceiveBeacon(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Beacon frame received on the given link.
Time m_probeRequestTimeout
probe request timeout
Definition: sta-wifi-mac.h:608
void SetActiveProbing(bool enable)
Enable or disable active probing.
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
std::variant< MgtBeaconHeader, MgtProbeResponseHeader, MgtAssocResponseHeader > MgtFrameType
type of the management frames used to get info about APs
Definition: sta-wifi-mac.h:152
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
Definition: sta-wifi-mac.h:610
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
Definition: sta-wifi-mac.h:620
bool IsSuccess() const
Return whether the status code is success.
Definition: status-code.cc:42
Hold variables of type string.
Definition: string.h:56
The Supported Rates Information Element.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
@ US
microsecond
Definition: nstime.h:118
AttributeValue implementation for Time.
Definition: nstime.h:1406
Time Get() const
Definition: time.cc:530
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition: txop.h:424
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
Definition: txop.h:426
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:522
a unique identifier for an interface.
Definition: type-id.h:59
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:64
@ ATTR_SET
The attribute can be written.
Definition: type-id.h:65
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
@ OBSOLETE
Attribute or trace source is not used anymore; simulation fails.
Definition: type-id.h:76
Hold an unsigned integer type.
Definition: uinteger.h:45
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.
void SetQosAckPolicy(QosAckPolicy policy)
Set the QoS Ack policy in the QoS control field.
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.
void SetQosTxopLimit(uint8_t txop)
Set TXOP limit in the QoS control field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
bool IsCtl() const
Return true if the Type is Control.
void SetNoOrder()
Unset order bit in the frame control field.
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.
void SetQosNoAmsdu()
Set that A-MSDU is not present.
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.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
bool IsData() const
Return true if the Type is DATA.
void SetQosNoEosp()
Un-set the end of service period (EOSP) bit in the QoS control field.
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:99
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:878
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition: wifi-mac.cc:547
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition: wifi-mac.cc:596
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1663
Mac48Address GetBssid(uint8_t linkId) const
Definition: wifi-mac.cc:492
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1780
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition: wifi-mac.cc:932
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition: wifi-mac.cc:507
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2049
Callback< void > m_linkDown
Callback when a link is down.
Definition: wifi-mac.h:912
bool GetQosSupported() const
Return whether the device supports QoS.
Definition: wifi-mac.cc:1236
Ptr< Txop > m_txop
TXOP used for transmission of frames to non-QoS peers.
Definition: wifi-mac.h:908
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:590
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:947
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:1009
void DoInitialize() override
Initialize() implementation.
Definition: wifi-mac.cc:363
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:1447
Ssid GetSsid() const
Definition: wifi-mac.cc:479
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition: wifi-mac.cc:1242
bool GetHtSupported() const
Return whether the device supports HT.
Definition: wifi-mac.cc:1792
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition: wifi-mac.cc:535
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition: wifi-mac.cc:429
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1185
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:1401
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition: wifi-mac.cc:1811
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1805
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition: wifi-mac.cc:1990
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:975
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the MAC has frames to transmit over the given link.
Definition: wifi-mac.cc:566
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:1319
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition: wifi-mac.cc:1786
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition: wifi-mac.cc:1798
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:351
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:1651
void SetBssid(Mac48Address bssid, uint8_t linkId)
Definition: wifi-mac.cc:485
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:453
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:1080
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition: wifi-mac.cc:1979
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:559
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:988
bool GetShortSlotTimeSupported() const
Definition: wifi-mac.cc:1286
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:633
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:920
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition: wifi-mac.cc:1521
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:1528
Mac48Address GetAddress() const
Definition: wifi-mac.cc:466
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2189
Callback< void > m_linkUp
Callback when a link is up.
Definition: wifi-mac.h:911
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: wifi-mac.cc:938
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition: wifi-mac.cc:2131
virtual void SetWifiPhys(const std::vector< Ptr< WifiPhy > > &phys)
Definition: wifi-mac.cc:1160
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:513
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:615
void DoDispose() override
Destructor implementation.
Definition: wifi-mac.cc:387
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1529
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition: wifi-phy.cc:809
void SetOffMode()
Put in off mode.
Definition: wifi-phy.cc:1405
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:66
#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:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:259
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1355
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiPowerManagementMode
Enumeration for power management modes.
Definition: sta-wifi-mac.h:91
uint8_t QosUtilsGetTidForPacket(Ptr< const Packet > packet)
If a QoS tag is attached to the packet, returns a value < 8.
Definition: qos-utils.cc:156
WifiQueueBlockedReason
Enumeration of the reasons to block container queues.
@ STA
Definition: wifi-mac.h:68
@ WIFI_PM_SWITCHING_TO_ACTIVE
Definition: sta-wifi-mac.h:95
@ WIFI_PM_POWERSAVE
Definition: sta-wifi-mac.h:94
@ WIFI_PM_SWITCHING_TO_PS
Definition: sta-wifi-mac.h:93
@ WIFI_PM_ACTIVE
Definition: sta-wifi-mac.h:92
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
Definition: wifi-phy-band.h:43
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
@ AC_VI
Video.
Definition: qos-utils.h:79
@ AC_BK
Background.
Definition: qos-utils.h:77
-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:706
WifiTidToLinkMappingNegSupport
TID-to-Link Mapping Negotiation Support.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
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:126
@ 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_DATA
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
@ WIFI_MAC_QOSDATA
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping &dlLinkMapping, const WifiTidLinkMapping &ulLinkMapping)
Check if the given TID-to-Link Mappings are valid for a negotiation type of 1.
Definition: wifi-utils.cc:148
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition: log.h:106
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.
Definition: sta-wifi-mac.h:159
MgtFrameType m_frame
The body of the management frame used to update AP info.
Definition: sta-wifi-mac.h:173
WifiScanParams::Channel m_channel
The channel the management frame was received on.
Definition: sta-wifi-mac.h:174
Mac48Address m_apAddr
AP MAC address.
Definition: sta-wifi-mac.h:171
uint8_t m_linkId
ID of the link used to communicate with the AP.
Definition: sta-wifi-mac.h:175
Mac48Address m_bssid
BSSID.
Definition: sta-wifi-mac.h:170
double m_snr
SNR in linear scale.
Definition: sta-wifi-mac.h:172
Struct identifying a channel to scan.
Definition: sta-wifi-mac.h:69
WifiPhyBand band
PHY band.
Definition: sta-wifi-mac.h:71
uint16_t number
channel number
Definition: sta-wifi-mac.h:70
Structure holding scan parameters.
Definition: sta-wifi-mac.h:61
std::list< Channel > ChannelList
typedef for a list of channels
Definition: sta-wifi-mac.h:75
std::vector< ChannelList > channelList
list of channels to scan, for each link
Definition: sta-wifi-mac.h:79
Time probeDelay
delay prior to transmitting a Probe Request
Definition: sta-wifi-mac.h:80
WifiScanType type
indicates either active or passive scanning
Definition: sta-wifi-mac.h:77
Time maxChannelTime
maximum time to spend on each channel
Definition: sta-wifi-mac.h:82
Ssid ssid
desired SSID or wildcard SSID
Definition: sta-wifi-mac.h:78
Time minChannelTime
minimum time to spend on each channel
Definition: sta-wifi-mac.h:81