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
212void
214{
215 NS_LOG_FUNCTION(this);
216}
217
219{
221}
222
223std::unique_ptr<WifiMac::LinkEntity>
225{
226 return std::make_unique<StaLinkEntity>();
227}
228
230StaWifiMac::GetLink(uint8_t linkId) const
231{
232 return static_cast<StaLinkEntity&>(WifiMac::GetLink(linkId));
233}
234
236StaWifiMac::GetStaLink(const std::unique_ptr<WifiMac::LinkEntity>& link) const
237{
238 return static_cast<StaLinkEntity&>(*link);
239}
240
241int64_t
243{
244 NS_LOG_FUNCTION(this << stream);
245 m_probeDelay->SetStream(stream);
246 auto currentStream = stream + 1;
247 currentStream += WifiMac::AssignStreams(currentStream);
248 return (currentStream - stream);
249}
250
251void
253{
254 NS_LOG_FUNCTION(this << assocManager);
255 m_assocManager = assocManager;
256 m_assocManager->SetStaWifiMac(this);
257}
258
259void
261{
262 NS_LOG_FUNCTION(this << emlsrManager);
263 m_emlsrManager = emlsrManager;
264 m_emlsrManager->SetWifiMac(this);
265}
266
269{
270 return m_emlsrManager;
271}
272
273uint16_t
275{
276 NS_ASSERT_MSG(IsAssociated(), "This station is not associated to any AP");
277 return m_aid;
278}
279
280void
282{
283 NS_LOG_FUNCTION(this << enable);
284 m_activeProbing = enable;
285 if (m_state == SCANNING)
286 {
287 NS_LOG_DEBUG("STA is still scanning, reset scanning process");
289 }
290}
291
292bool
294{
295 return m_activeProbing;
296}
297
298void
299StaWifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
300{
301 NS_LOG_FUNCTION(this);
303 for (auto& phy : phys)
304 {
305 phy->SetCapabilitiesChangedCallback(
307 }
308}
309
311StaWifiMac::GetCurrentChannel(uint8_t linkId) const
312{
313 auto phy = GetWifiPhy(linkId);
314 uint16_t width = phy->GetOperatingChannel().IsOfdm() ? 20 : phy->GetChannelWidth();
315 uint8_t ch = phy->GetOperatingChannel().GetPrimaryChannelNumber(width, phy->GetStandard());
316 return {ch, phy->GetPhyBand()};
317}
318
319void
320StaWifiMac::NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds)
321{
322 std::stringstream ss;
323 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
324 {
325 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
326 }
327 NS_LOG_FUNCTION(this << ss.str());
328
329 for (const auto& [linkId, lnk] : GetLinks())
330 {
331 auto& link = GetStaLink(lnk);
332
333 if (linkIds.contains(linkId))
334 {
335 // EMLSR mode enabled
336 link.emlsrEnabled = true;
337 link.pmMode = WIFI_PM_ACTIVE;
338 }
339 else
340 {
341 // EMLSR mode disabled
342 if (link.emlsrEnabled)
343 {
344 link.pmMode = WIFI_PM_POWERSAVE;
345 }
346 link.emlsrEnabled = false;
347 }
348 }
349}
350
351bool
352StaWifiMac::IsEmlsrLink(uint8_t linkId) const
353{
354 return GetLink(linkId).emlsrEnabled;
355}
356
357void
359{
360 NS_LOG_FUNCTION(this << linkId);
361 WifiMacHeader hdr;
366 hdr.SetDsNotFrom();
367 hdr.SetDsNotTo();
368 Ptr<Packet> packet = Create<Packet>();
370 probe.Get<Ssid>() = GetSsid();
371 auto supportedRates = GetSupportedRates(linkId);
372 probe.Get<SupportedRates>() = supportedRates.rates;
373 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
374 if (GetHtSupported(linkId))
375 {
377 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
378 }
379 if (GetVhtSupported(linkId))
380 {
381 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
382 }
383 if (GetHeSupported())
384 {
385 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
386 if (Is6GhzBand(linkId))
387 {
389 }
390 }
391 if (GetEhtSupported())
392 {
393 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
394 }
395 packet->AddHeader(probe);
396
397 if (!GetQosSupported())
398 {
399 GetTxop()->Queue(packet, hdr);
400 }
401 // "A QoS STA that transmits a Management frame determines access category used
402 // for medium access in transmission of the Management frame as follows
403 // (If dot11QMFActivated is false or not present)
404 // — If the Management frame is individually addressed to a non-QoS STA, category
405 // AC_BE should be selected.
406 // — If category AC_BE was not selected by the previous step, category AC_VO
407 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
408 else
409 {
410 GetVOQueue()->Queue(packet, hdr);
411 }
412}
413
414std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>
415StaWifiMac::GetAssociationRequest(bool isReassoc, uint8_t linkId) const
416{
417 NS_LOG_FUNCTION(this << isReassoc << +linkId);
418
419 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader> mgtFrame;
420
421 if (isReassoc)
422 {
424 reassoc.SetCurrentApAddress(GetBssid(linkId));
425 mgtFrame = std::move(reassoc);
426 }
427 else
428 {
429 mgtFrame = MgtAssocRequestHeader();
430 }
431
432 // lambda to set the fields of the (Re)Association Request
433 auto fill = [&](auto&& frame) {
434 frame.template Get<Ssid>() = GetSsid();
435 auto supportedRates = GetSupportedRates(linkId);
436 frame.template Get<SupportedRates>() = supportedRates.rates;
437 frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
438 frame.Capabilities() = GetCapabilities(linkId);
439 frame.SetListenInterval(0);
440 if (GetHtSupported(linkId))
441 {
442 frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
443 frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
444 }
445 if (GetVhtSupported(linkId))
446 {
447 frame.template Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
448 }
449 if (GetHeSupported())
450 {
451 frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
452 if (Is6GhzBand(linkId))
453 {
454 frame.template Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
455 }
456 }
457 if (GetEhtSupported())
458 {
459 frame.template Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
460 }
461 };
462
463 std::visit(fill, mgtFrame);
464 return mgtFrame;
465}
466
468StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
469{
470 NS_LOG_FUNCTION(this << isReassoc << +linkId);
471
473 // The Common info field of the Basic Multi-Link element carried in the (Re)Association
474 // Request frame shall include the MLD MAC address, the MLD Capabilities and Operations,
475 // and the EML Capabilities subfields, and shall not include the Link ID Info, the BSS
476 // Parameters Change Count, and the Medium Synchronization Delay Information subfields
477 // (Sec. 35.3.5.4 of 802.11be D2.0)
478 // TODO Add the MLD Capabilities and Operations subfield
479 multiLinkElement.SetMldMacAddress(GetAddress());
480
481 if (m_emlsrManager) // EMLSR Manager is only installed if EMLSR is activated
482 {
483 multiLinkElement.SetEmlsrSupported(true);
484 TimeValue time;
485 m_emlsrManager->GetAttribute("EmlsrPaddingDelay", time);
486 multiLinkElement.SetEmlsrPaddingDelay(time.Get());
487 m_emlsrManager->GetAttribute("EmlsrTransitionDelay", time);
488 multiLinkElement.SetEmlsrTransitionDelay(time.Get());
489 // When the Transition Timeout subfield is included in a frame sent by a non-AP STA
490 // affiliated with a non-AP MLD, the Transition Timeout subfield is reserved
491 // (Section 9.4.2.312.2.3 of 802.11be D2.3)
492 // The Medium Synchronization Delay Information subfield in the Common Info subfield is
493 // not present if the Basic Multi-Link element is sent by a non-AP STA. (Section
494 // 9.4.2.312.2.3 of 802.11be D3.1)
495 }
496
497 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
498 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
499 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
500 auto& mldCapabilities = multiLinkElement.GetCommonInfoBasic().m_mldCapabilities;
501 mldCapabilities.emplace();
502 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
503 mldCapabilities->srsSupport = 0;
504
505 auto ehtConfiguration = GetEhtConfiguration();
506 NS_ASSERT(ehtConfiguration);
508 ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
509
510 mldCapabilities->tidToLinkMappingSupport = static_cast<uint8_t>(negSupport.Get());
511 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
512 mldCapabilities->aarSupport = 0; // not supported yet
513
514 // For each requested link in addition to the link on which the (Re)Association Request
515 // frame is transmitted, the Link Info field of the Basic Multi-Link element carried
516 // in the (Re)Association Request frame shall contain the corresponding Per-STA Profile
517 // subelement(s).
518 for (const auto& [index, link] : GetLinks())
519 {
520 const auto& staLink = GetStaLink(link);
521
522 if (index != linkId && staLink.bssid.has_value())
523 {
524 multiLinkElement.AddPerStaProfileSubelement();
525 auto& perStaProfile = multiLinkElement.GetPerStaProfile(
526 multiLinkElement.GetNPerStaProfileSubelements() - 1);
527 // The Link ID subfield of the STA Control field of the Per-STA Profile subelement
528 // for the corresponding non-AP STA that requests a link for multi-link (re)setup
529 // with the AP MLD is set to the link ID of the AP affiliated with the AP MLD that
530 // is operating on that link. The link ID is obtained during multi-link discovery
531 perStaProfile.SetLinkId(index);
532 // For each Per-STA Profile subelement included in the Link Info field, the
533 // Complete Profile subfield of the STA Control field shall be set to 1
534 perStaProfile.SetCompleteProfile();
535 // The MAC Address Present subfield indicates the presence of the STA MAC Address
536 // subfield in the STA Info field and is set to 1 if the STA MAC Address subfield
537 // is present in the STA Info field; otherwise set to 0. An STA sets this subfield
538 // to 1 when the element carries complete profile.
539 perStaProfile.SetStaMacAddress(staLink.feManager->GetAddress());
540 perStaProfile.SetAssocRequest(GetAssociationRequest(isReassoc, index));
541 }
542 }
543
544 return multiLinkElement;
545}
546
547std::vector<TidToLinkMapping>
549{
550 NS_LOG_FUNCTION(this << apNegSupport);
551
552 auto ehtConfig = GetEhtConfiguration();
553 NS_ASSERT(ehtConfig);
554
556 ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
557
559 "Cannot request TID-to-Link Mapping if negotiation is not supported");
560
561 // store the mappings, so that we can enforce them when the AP MLD accepts them
562 m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
563 m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
564
569 !mappingValidForNegType1,
570 "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
571
572 if (apNegSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET && !mappingValidForNegType1)
573 {
574 // If the TID-to-link Mapping Negotiation Support subfield value received from a peer
575 // MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
576 // peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
577 // the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
578 // this requirement.
579 NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
582 }
583
584 std::vector<TidToLinkMapping> ret(1);
585
586 ret.back().m_control.direction = WifiDirection::DOWNLINK;
587
588 // lambda to fill the last TID-to-Link Mapping IE in the vector to return
589 auto fillIe = [&ret](const auto& mapping) {
590 ret.back().m_control.defaultMapping = mapping.empty();
591
592 for (const auto& [tid, linkSet] : mapping)
593 {
594 // At any point in time, a TID shall always be mapped to at least one setup link both
595 // in DL and UL, which means that a TID-to-link mapping change is only valid and
596 // successful if it will not result in having any TID for which the link set for DL
597 // or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
598 NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
599 ret.back().SetLinkMappingOfTid(tid, linkSet);
600 }
601 };
602
604
606 {
607 ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
608 return ret;
609 }
610
611 ret.emplace_back();
612 ret.back().m_control.direction = WifiDirection::UPLINK;
614
615 return ret;
616}
617
618void
620{
621 // find the link where the (Re)Association Request has to be sent
622 auto it = GetLinks().cbegin();
623 while (it != GetLinks().cend())
624 {
625 if (GetStaLink(it->second).sendAssocReq)
626 {
627 break;
628 }
629 it++;
630 }
631 NS_ABORT_MSG_IF(it == GetLinks().cend(),
632 "No link selected to send the (Re)Association Request");
633 uint8_t linkId = it->first;
634 auto& link = GetLink(linkId);
635 NS_ABORT_MSG_IF(!link.bssid.has_value(),
636 "No BSSID set for the link on which the (Re)Association Request is to be sent");
637
638 NS_LOG_FUNCTION(this << *link.bssid << isReassoc);
639 WifiMacHeader hdr;
641 hdr.SetAddr1(*link.bssid);
642 hdr.SetAddr2(link.feManager->GetAddress());
643 hdr.SetAddr3(*link.bssid);
644 hdr.SetDsNotFrom();
645 hdr.SetDsNotTo();
646 Ptr<Packet> packet = Create<Packet>();
647
648 auto frame = GetAssociationRequest(isReassoc, linkId);
649
650 // include a Multi-Link Element if this device has multiple links (independently
651 // of how many links will be setup) and the AP is a multi-link device;
652 // if the AP MLD has indicated a support of TID-to-link mapping negotiation, also
653 // include the TID-to-link Mapping element(s)
654 if (GetNLinks() > 1 &&
655 GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
656 {
657 auto addMle = [&](auto&& frame) {
658 frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
659 };
660 std::visit(addMle, frame);
661
663 if (const auto& mldCapabilities =
664 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
665 mldCapabilities && (negSupport = static_cast<WifiTidToLinkMappingNegSupport>(
666 mldCapabilities->get().tidToLinkMappingSupport)) >
668 {
669 auto addTlm = [&](auto&& frame) {
670 frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
671 };
672 std::visit(addTlm, frame);
673 }
674 }
675
676 if (!isReassoc)
677 {
678 packet->AddHeader(std::get<MgtAssocRequestHeader>(frame));
679 }
680 else
681 {
682 packet->AddHeader(std::get<MgtReassocRequestHeader>(frame));
683 }
684
685 if (!GetQosSupported())
686 {
687 GetTxop()->Queue(packet, hdr);
688 }
689 // "A QoS STA that transmits a Management frame determines access category used
690 // for medium access in transmission of the Management frame as follows
691 // (If dot11QMFActivated is false or not present)
692 // — If the Management frame is individually addressed to a non-QoS STA, category
693 // AC_BE should be selected.
694 // — If category AC_BE was not selected by the previous step, category AC_VO
695 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
696 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(*link.bssid))
697 {
698 GetBEQueue()->Queue(packet, hdr);
699 }
700 else
701 {
702 GetVOQueue()->Queue(packet, hdr);
703 }
704
706 {
708 }
711}
712
713void
715{
716 NS_LOG_FUNCTION(this);
717 switch (m_state)
718 {
719 case ASSOCIATED:
720 return;
721 case SCANNING:
722 /* we have initiated active or passive scanning, continue to wait
723 and gather beacons or probe responses until the scanning timeout
724 */
725 break;
726 case UNASSOCIATED:
727 /* we were associated but we missed a bunch of beacons
728 * so we should assume we are not associated anymore.
729 * We try to initiate a scan now.
730 */
731 m_linkDown();
733 break;
734 case WAIT_ASSOC_RESP:
735 /* we have sent an association request so we do not need to
736 re-send an association request right now. We just need to
737 wait until either assoc-request-timeout or until
738 we get an association response.
739 */
740 case REFUSED:
741 /* we have sent an association request and received a negative
742 association response. We wait until someone restarts an
743 association with a given SSID.
744 */
745 break;
746 }
747}
748
749void
751{
752 NS_LOG_FUNCTION(this);
755
756 WifiScanParams scanParams;
757 scanParams.ssid = GetSsid();
758 for (const auto& [id, link] : GetLinks())
759 {
761 (link->phy->HasFixedPhyBand()) ? WifiScanParams::Channel{0, link->phy->GetPhyBand()}
763
764 scanParams.channelList.push_back(channel);
765 }
766 if (m_activeProbing)
767 {
768 scanParams.type = WifiScanType::ACTIVE;
770 scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
771 }
772 else
773 {
774 scanParams.type = WifiScanType::PASSIVE;
776 }
777
778 m_assocManager->StartScanning(std::move(scanParams));
779}
780
781void
782StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& bestAp)
783{
784 NS_LOG_FUNCTION(this);
785
786 if (!bestAp.has_value())
787 {
788 NS_LOG_DEBUG("Exhausted list of candidate AP; restart scanning");
790 return;
791 }
792
793 NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
794 UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
795 // reset info on links to setup
796 for (auto& [id, link] : GetLinks())
797 {
798 auto& staLink = GetStaLink(link);
799 staLink.sendAssocReq = false;
800 staLink.bssid = std::nullopt;
801 }
802 // send Association Request on the link where the Beacon/Probe Response was received
803 GetLink(bestAp->m_linkId).sendAssocReq = true;
804 GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
805 std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
806 // update info on links to setup (11be MLDs only)
807 const auto& mle =
808 std::visit([](auto&& frame) { return frame.template Get<MultiLinkElement>(); },
809 bestAp->m_frame);
810 std::map<uint8_t, uint8_t> swapInfo;
811 for (const auto& [localLinkId, apLinkId, bssid] : bestAp->m_setupLinks)
812 {
813 NS_ASSERT_MSG(mle, "We get here only for ML setup");
814 NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
815 << ")");
816 GetLink(localLinkId).bssid = bssid;
817 if (!mleCommonInfo)
818 {
819 mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
820 }
821 GetWifiRemoteStationManager(localLinkId)->AddStationMleCommonInfo(bssid, mleCommonInfo);
822 swapInfo.emplace(localLinkId, apLinkId);
823 }
824
825 SwapLinks(swapInfo);
826
827 // lambda to get beacon interval from Beacon or Probe Response
828 auto getBeaconInterval = [](auto&& frame) {
829 using T = std::decay_t<decltype(frame)>;
830 if constexpr (std::is_same_v<T, MgtBeaconHeader> ||
831 std::is_same_v<T, MgtProbeResponseHeader>)
832 {
833 return MicroSeconds(frame.GetBeaconIntervalUs());
834 }
835 else
836 {
837 NS_ABORT_MSG("Unexpected frame type");
838 return Seconds(0);
839 }
840 };
841 Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
842 Time delay = beaconInterval * m_maxMissedBeacons;
843 // restart beacon watchdog
845
848}
849
850void
852{
853 NS_LOG_FUNCTION(this);
856}
857
858void
860{
861 NS_LOG_FUNCTION(this);
862
864 {
866 {
868 }
871 this);
872 return;
873 }
874 NS_LOG_DEBUG("beacon missed");
875 // We need to switch to the UNASSOCIATED state. However, if we are receiving a frame, wait
876 // until the RX is completed (otherwise, crashes may occur if we are receiving a MU frame
877 // because its reception requires the STA-ID). We need to check that a PHY is operating on
878 // the given link, because this may (temporarily) not be the case for EMLSR clients.
879 Time delay = Seconds(0);
880 for (const auto& [id, link] : GetLinks())
881 {
882 if (link->phy && link->phy->IsStateRx())
883 {
884 delay = std::max(delay, link->phy->GetDelayUntilIdle());
885 }
886 }
888}
889
890void
892{
893 NS_LOG_FUNCTION(this);
894
895 Mac48Address apAddr; // the AP address to trace (MLD address in case of ML setup)
896
897 for (const auto& [id, link] : GetLinks())
898 {
899 auto& bssid = GetStaLink(link).bssid;
900 if (bssid)
901 {
902 apAddr = GetWifiRemoteStationManager(id)->GetMldAddress(*bssid).value_or(*bssid);
903 }
904 bssid = std::nullopt; // link is no longer setup
905 }
906
907 NS_LOG_DEBUG("Set state to UNASSOCIATED and start scanning");
909 // cancel the association request timer (see issue #862)
911 m_deAssocLogger(apAddr);
912 m_aid = 0; // reset AID
914}
915
916void
918{
919 NS_LOG_FUNCTION(this << delay);
920
923 {
924 NS_LOG_DEBUG("really restart watchdog.");
926 }
927}
928
929bool
931{
932 return m_state == ASSOCIATED;
933}
934
935bool
937{
938 return m_state == WAIT_ASSOC_RESP;
939}
940
941std::set<uint8_t>
943{
944 if (!IsAssociated())
945 {
946 return {};
947 }
948
949 std::set<uint8_t> linkIds;
950 for (const auto& [id, link] : GetLinks())
951 {
952 if (GetStaLink(link).bssid)
953 {
954 linkIds.insert(id);
955 }
956 }
957 return linkIds;
958}
959
962{
963 auto linkIds = GetSetupLinkIds();
964 NS_ASSERT_MSG(!linkIds.empty(), "Not associated");
965 uint8_t linkId = *linkIds.begin();
966 return GetFrameExchangeManager(linkId)->GetAddress();
967}
968
969bool
971{
972 return IsAssociated();
973}
974
975void
977{
978 NS_LOG_FUNCTION(this << packet << to);
979 if (!CanForwardPacketsTo(to))
980 {
981 NotifyTxDrop(packet);
983 return;
984 }
985 WifiMacHeader hdr;
986
987 // If we are not a QoS AP then we definitely want to use AC_BE to
988 // transmit the packet. A TID of zero will map to AC_BE (through \c
989 // QosUtilsMapTidToAc()), so we use that as our default here.
990 uint8_t tid = 0;
991
992 // For now, an AP that supports QoS does not support non-QoS
993 // associations, and vice versa. In future the AP model should
994 // support simultaneously associated QoS and non-QoS STAs, at which
995 // point there will need to be per-association QoS state maintained
996 // by the association state machine, and consulted here.
997 if (GetQosSupported())
998 {
1001 hdr.SetQosNoEosp();
1002 hdr.SetQosNoAmsdu();
1003 // Transmission of multiple frames in the same TXOP is not
1004 // supported for now
1005 hdr.SetQosTxopLimit(0);
1006
1007 // Fill in the QoS control field in the MAC header
1008 tid = QosUtilsGetTidForPacket(packet);
1009 // Any value greater than 7 is invalid and likely indicates that
1010 // the packet had no QoS tag, so we revert to zero, which'll
1011 // mean that AC_BE is used.
1012 if (tid > 7)
1013 {
1014 tid = 0;
1015 }
1016 hdr.SetQosTid(tid);
1017 }
1018 else
1019 {
1021 }
1022 if (GetQosSupported())
1023 {
1024 hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
1025 // yet implemented (set it to 1 when implemented)
1026 }
1027
1028 // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for
1029 // non-broadcast data frames exchanged between two MLDs
1030 auto linkIds = GetSetupLinkIds();
1031 NS_ASSERT(!linkIds.empty());
1032 uint8_t linkId = *linkIds.begin();
1033 if (const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId)))
1034 {
1035 hdr.SetAddr1(*apMldAddr);
1036 hdr.SetAddr2(GetAddress());
1037 }
1038 else
1039 {
1040 hdr.SetAddr1(GetBssid(linkId));
1042 }
1043
1044 hdr.SetAddr3(to);
1045 hdr.SetDsNotFrom();
1046 hdr.SetDsTo();
1047
1048 if (GetQosSupported())
1049 {
1050 // Sanity check that the TID is valid
1051 NS_ASSERT(tid < 8);
1052 GetQosTxop(tid)->Queue(packet, hdr);
1053 }
1054 else
1055 {
1056 GetTxop()->Queue(packet, hdr);
1057 }
1058}
1059
1060void
1062{
1063 NS_LOG_FUNCTION(this << linkId << reason);
1064
1065 auto bssid = GetBssid(linkId);
1066 auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1067
1068 BlockUnicastTxOnLinks(reason, apAddress, {linkId});
1069 // the only type of broadcast frames that a non-AP STA can send are management frames
1070 for (const auto& [acIndex, ac] : wifiAcList)
1071 {
1072 GetMacQueueScheduler()->BlockQueues(reason,
1073 acIndex,
1076 GetFrameExchangeManager(linkId)->GetAddress(),
1077 {},
1078 {linkId});
1079 }
1080}
1081
1082void
1083StaWifiMac::UnblockTxOnLink(std::set<uint8_t> linkIds, WifiQueueBlockedReason reason)
1084{
1085 std::stringstream ss;
1086 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
1087 NS_LOG_FUNCTION(this << ss.str() << reason);
1088
1089 const auto linkId = *linkIds.cbegin();
1090 const auto bssid = GetBssid(linkId);
1091 const auto apAddress =
1092 GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1093
1094 UnblockUnicastTxOnLinks(reason, apAddress, linkIds);
1095 // the only type of broadcast frames that a non-AP STA can send are management frames
1096 for (const auto& [acIndex, ac] : wifiAcList)
1097 {
1098 GetMacQueueScheduler()->UnblockQueues(reason,
1099 acIndex,
1102 GetFrameExchangeManager(linkId)->GetAddress(),
1103 {},
1104 linkIds);
1105 }
1106}
1107
1108void
1110{
1111 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1112 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1113 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1114 Ptr<const Packet> packet = mpdu->GetPacket();
1115 NS_ASSERT(!hdr->IsCtl());
1117 : GetFrameExchangeManager(linkId)->GetAddress();
1118 if (hdr->GetAddr3() == myAddr)
1119 {
1120 NS_LOG_LOGIC("packet sent by us.");
1121 return;
1122 }
1123 if (hdr->GetAddr1() != myAddr && !hdr->GetAddr1().IsGroup())
1124 {
1125 NS_LOG_LOGIC("packet is not for us");
1126 NotifyRxDrop(packet);
1127 return;
1128 }
1129 if (hdr->IsData())
1130 {
1131 if (!IsAssociated())
1132 {
1133 NS_LOG_LOGIC("Received data frame while not associated: ignore");
1134 NotifyRxDrop(packet);
1135 return;
1136 }
1137 if (!(hdr->IsFromDs() && !hdr->IsToDs()))
1138 {
1139 NS_LOG_LOGIC("Received data frame not from the DS: ignore");
1140 NotifyRxDrop(packet);
1141 return;
1142 }
1143 std::set<Mac48Address> apAddresses; // link addresses of AP
1144 for (auto id : GetSetupLinkIds())
1145 {
1146 apAddresses.insert(GetBssid(id));
1147 }
1148 if (!apAddresses.contains(mpdu->GetHeader().GetAddr2()))
1149 {
1150 NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
1151 NotifyRxDrop(packet);
1152 return;
1153 }
1154 if (!hdr->HasData())
1155 {
1156 NS_LOG_LOGIC("Received (QoS) Null Data frame: ignore");
1157 NotifyRxDrop(packet);
1158 return;
1159 }
1160 if (hdr->IsQosData())
1161 {
1162 if (hdr->IsQosAmsdu())
1163 {
1164 NS_ASSERT(apAddresses.contains(mpdu->GetHeader().GetAddr3()));
1166 packet = nullptr;
1167 }
1168 else
1169 {
1170 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1171 }
1172 }
1173 else
1174 {
1175 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1176 }
1177 return;
1178 }
1179
1180 switch (hdr->GetType())
1181 {
1185 // This is a frame aimed at an AP, so we can safely ignore it.
1186 NotifyRxDrop(packet);
1187 break;
1188
1190 ReceiveBeacon(mpdu, linkId);
1191 break;
1192
1194 ReceiveProbeResp(mpdu, linkId);
1195 break;
1196
1199 ReceiveAssocResp(mpdu, linkId);
1200 break;
1201
1203 if (auto [category, action] = WifiActionHeader::Peek(packet);
1204 category == WifiActionHeader::PROTECTED_EHT &&
1205 action.protectedEhtAction ==
1207 {
1208 // this is handled by the EMLSR Manager
1209 break;
1210 }
1211
1212 default:
1213 // Invoke the receive handler of our parent class to deal with any
1214 // other frames. Specifically, this will handle Block Ack-related
1215 // Management Action frames.
1216 WifiMac::Receive(mpdu, linkId);
1217 }
1218
1219 if (m_emlsrManager)
1220 {
1221 m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
1222 }
1223}
1224
1225void
1227{
1228 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1229 const WifiMacHeader& hdr = mpdu->GetHeader();
1230 NS_ASSERT(hdr.IsBeacon());
1231
1232 NS_LOG_DEBUG("Beacon received");
1233 MgtBeaconHeader beacon;
1234 mpdu->GetPacket()->PeekHeader(beacon);
1235 const auto& capabilities = beacon.Capabilities();
1236 NS_ASSERT(capabilities.IsEss());
1237 bool goodBeacon;
1238 if (IsWaitAssocResp() || IsAssociated())
1239 {
1240 // we have to process this Beacon only if sent by the AP we are associated
1241 // with or from which we are waiting an Association Response frame
1242 auto bssid = GetLink(linkId).bssid;
1243 goodBeacon = bssid.has_value() && (hdr.GetAddr3() == *bssid);
1244 }
1245 else
1246 {
1247 // we retain this Beacon as candidate AP if the supported rates fit the
1248 // configured BSS membership selector
1249 goodBeacon = CheckSupportedRates(beacon, linkId);
1250 }
1251
1252 SnrTag snrTag;
1253 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1254 NS_ASSERT(found);
1255 ApInfo apInfo = {.m_bssid = hdr.GetAddr3(),
1256 .m_apAddr = hdr.GetAddr2(),
1257 .m_snr = snrTag.Get(),
1258 .m_frame = std::move(beacon),
1259 .m_channel = {GetCurrentChannel(linkId)},
1260 .m_linkId = linkId};
1261
1262 if (!m_beaconInfo.IsEmpty())
1263 {
1264 m_beaconInfo(apInfo);
1265 }
1266
1267 if (!goodBeacon)
1268 {
1269 NS_LOG_LOGIC("Beacon is not for us");
1270 return;
1271 }
1272 if (m_state == ASSOCIATED)
1273 {
1275 Time delay = MicroSeconds(std::get<MgtBeaconHeader>(apInfo.m_frame).GetBeaconIntervalUs() *
1277 RestartBeaconWatchdog(delay);
1278 UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1279 }
1280 else
1281 {
1282 NS_LOG_DEBUG("Beacon received from " << hdr.GetAddr2());
1283 m_assocManager->NotifyApInfo(std::move(apInfo));
1284 }
1285}
1286
1287void
1289{
1290 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1291 const WifiMacHeader& hdr = mpdu->GetHeader();
1292 NS_ASSERT(hdr.IsProbeResp());
1293
1294 NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2());
1295 MgtProbeResponseHeader probeResp;
1296 mpdu->GetPacket()->PeekHeader(probeResp);
1297 if (!CheckSupportedRates(probeResp, linkId))
1298 {
1299 return;
1300 }
1301 SnrTag snrTag;
1302 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1303 NS_ASSERT(found);
1304 m_assocManager->NotifyApInfo(ApInfo{.m_bssid = hdr.GetAddr3(),
1305 .m_apAddr = hdr.GetAddr2(),
1306 .m_snr = snrTag.Get(),
1307 .m_frame = std::move(probeResp),
1308 .m_channel = {GetCurrentChannel(linkId)},
1309 .m_linkId = linkId});
1310}
1311
1312void
1314{
1315 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1316 const WifiMacHeader& hdr = mpdu->GetHeader();
1317 NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp());
1318
1319 if (m_state != WAIT_ASSOC_RESP)
1320 {
1321 return;
1322 }
1323
1324 std::optional<Mac48Address> apMldAddress;
1325 MgtAssocResponseHeader assocResp;
1326 mpdu->GetPacket()->PeekHeader(assocResp);
1328 {
1330 }
1331 if (assocResp.GetStatusCode().IsSuccess())
1332 {
1333 m_aid = assocResp.GetAssociationId();
1334 NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed"));
1335 UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1336 NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
1337 SetBssid(hdr.GetAddr3(), linkId);
1339 if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
1340 {
1341 // this is an ML setup, trace the setup link
1342 m_setupCompleted(linkId, hdr.GetAddr3());
1343 apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
1344 NS_ASSERT(apMldAddress);
1345
1346 if (const auto& mldCapabilities =
1347 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
1348 mldCapabilities && static_cast<WifiTidToLinkMappingNegSupport>(
1349 mldCapabilities->get().tidToLinkMappingSupport) >
1351 {
1352 // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
1353 // TID-to-Link Mapping element(s) in the Association Request.
1354 if (assocResp.Get<TidToLinkMapping>().empty())
1355 {
1356 // The AP MLD did not include a TID-to-Link Mapping element in the Association
1357 // Response, hence it accepted the mapping, which we can now store.
1358 UpdateTidToLinkMapping(*apMldAddress,
1361 UpdateTidToLinkMapping(*apMldAddress,
1364
1365 // Apply the negotiated TID-to-Link Mapping (if any) for UL direction
1367 }
1368 }
1369 }
1370 else
1371 {
1372 m_assocLogger(hdr.GetAddr3());
1373 }
1374 if (!m_linkUp.IsNull())
1375 {
1376 m_linkUp();
1377 }
1378 }
1379 else
1380 {
1381 // If the link on which the (Re)Association Request frame was received cannot be
1382 // accepted by the AP MLD, the AP MLD shall treat the multi-link (re)setup as a
1383 // failure and shall not accept any requested links. If the link on which the
1384 // (Re)Association Request frame was received is accepted by the AP MLD, the
1385 // multi-link (re)setup is successful. (Sec. 35.3.5.1 of 802.11be D3.1)
1386 NS_LOG_DEBUG("association refused");
1388 StartScanning();
1389 return;
1390 }
1391
1392 // if this is an MLD, check if we can setup (other) links
1393 if (GetNLinks() > 1)
1394 {
1395 // create a list of all local Link IDs. IDs are removed as we find a corresponding
1396 // Per-STA Profile Subelements indicating successful association. Links with
1397 // remaining IDs are not setup
1398 std::list<uint8_t> setupLinks;
1399 for (const auto& [id, link] : GetLinks())
1400 {
1401 setupLinks.push_back(id);
1402 }
1403 if (assocResp.GetStatusCode().IsSuccess())
1404 {
1405 setupLinks.remove(linkId);
1406 }
1407
1408 // if a Multi-Link Element is present, check its content
1409 if (const auto& mle = assocResp.Get<MultiLinkElement>())
1410 {
1411 NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
1412 "The link on which the Association Response was received "
1413 "is not a link we requested to setup");
1414 NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
1415 "The link ID of the AP that transmitted the Association "
1416 "Response does not match the stored link ID");
1418 mle->GetMldMacAddress(),
1419 "The AP MLD MAC address in the received Multi-Link Element does not "
1420 "match the address stored in the station manager for link "
1421 << +linkId);
1422 // process the Per-STA Profile Subelements in the Multi-Link Element
1423 for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
1424 {
1425 auto& perStaProfile = mle->GetPerStaProfile(elem);
1426 uint8_t apLinkId = perStaProfile.GetLinkId();
1427 auto it = GetLinks().find(apLinkId);
1428 uint8_t staLinkid = 0;
1429 std::optional<Mac48Address> bssid;
1430 NS_ABORT_MSG_IF(it == GetLinks().cend() ||
1431 !(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
1432 "Setup for AP link ID " << apLinkId << " was not requested");
1433 NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
1434 "The BSSID in the Per-STA Profile for link ID "
1435 << +staLinkid << " does not match the stored BSSID");
1438 perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
1439 "The AP MLD MAC address in the received Multi-Link Element does not "
1440 "match the address stored in the station manager for link "
1441 << +staLinkid);
1442 // process the Association Response contained in this Per-STA Profile
1443 MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
1444 if (assoc.GetStatusCode().IsSuccess())
1445 {
1446 NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
1447 "AID should be the same for all the links");
1448 m_aid = assoc.GetAssociationId();
1449 NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
1450 UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
1451 SetBssid(*bssid, staLinkid);
1452 m_setupCompleted(staLinkid, *bssid);
1454 apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
1455 if (!m_linkUp.IsNull())
1456 {
1457 m_linkUp();
1458 }
1459 }
1460 // remove the ID of the link we setup
1461 setupLinks.remove(staLinkid);
1462 }
1463 }
1464 // remaining links in setupLinks are not setup and hence must be disabled
1465 for (const auto& id : setupLinks)
1466 {
1467 GetLink(id).bssid = std::nullopt;
1468 GetLink(id).phy->SetOffMode();
1469 }
1470 if (apMldAddress)
1471 {
1472 // this is an ML setup, trace the MLD address of the AP (only once)
1473 m_assocLogger(*apMldAddress);
1474 }
1475 }
1476
1477 // the station that associated with the AP may have dissociated and then associated again.
1478 // In this case, the station may store packets from the previous period in which it was
1479 // associated. Have the station restart access if it has packets queued.
1480 for (const auto& [id, link] : GetLinks())
1481 {
1482 if (GetStaLink(link).bssid)
1483 {
1484 if (const auto txop = GetTxop())
1485 {
1486 txop->StartAccessAfterEvent(id,
1489 }
1490 for (const auto& [acIndex, ac] : wifiAcList)
1491 {
1492 if (const auto edca = GetQosTxop(acIndex))
1493 {
1494 edca->StartAccessAfterEvent(id,
1497 }
1498 }
1499 }
1500 }
1501
1503}
1504
1505void
1507{
1508 NS_LOG_FUNCTION(this << linkId);
1509
1510 // STAs operating on setup links may need to transition to a new PM mode after the
1511 // acknowledgement of the Association Response. For this purpose, we connect a callback to
1512 // the PHY TX begin trace to catch the Ack transmitted after the Association Response.
1514 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, double /* txPowerW */) {
1515 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
1516 psduMap.begin()->second->GetHeader(0).IsAck(),
1517 "Expected a Normal Ack after Association Response frame");
1518
1519 auto ackDuration =
1520 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
1521
1522 for (const auto& [id, lnk] : GetLinks())
1523 {
1524 auto& link = GetStaLink(lnk);
1525
1526 if (!link.bssid)
1527 {
1528 // link has not been setup
1529 continue;
1530 }
1531
1532 if (id == linkId)
1533 {
1534 /**
1535 * When a link becomes enabled for a non-AP STA that is affiliated with a
1536 * non-AP MLD after successful association with an AP MLD with (Re)Association
1537 * Request/Response frames transmitted on that link [..], the power management
1538 * mode of the non-AP STA, immediately after the acknowledgement of the
1539 * (Re)Association Response frame [..], is active mode.
1540 * (Sec. 35.3.7.1.4 of 802.11be D3.0)
1541 */
1542 // if the user requested this link to be in powersave mode, we have to
1543 // switch PM mode
1544 if (link.pmMode == WIFI_PM_POWERSAVE)
1545 {
1546 Simulator::Schedule(ackDuration,
1548 this,
1549 std::pair<bool, uint8_t>{true, id});
1550 }
1551 link.pmMode = WIFI_PM_ACTIVE;
1552 }
1553 else
1554 {
1555 /**
1556 * When a link becomes enabled for a non-AP STA that is affiliated with a
1557 * non-AP MLD after successful association with an AP MLD with (Re)Association
1558 * Request/Response frames transmitted on another link [..], the power
1559 * management mode of the non-AP STA, immediately after the acknowledgement of
1560 * the (Re)Association Response frame [..], is power save mode, and its power
1561 * state is doze. (Sec. 35.3.7.1.4 of 802.11be D3.0)
1562 */
1563 // if the user requested this link to be in active mode, we have to
1564 // switch PM mode
1565 if (link.pmMode == WIFI_PM_ACTIVE)
1566 {
1567 Simulator::Schedule(ackDuration,
1569 this,
1570 std::pair<bool, uint8_t>{false, id});
1571 }
1572 link.pmMode = WIFI_PM_POWERSAVE;
1573 }
1574 }
1575 });
1576
1577 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
1578 // after its transmission begins
1579 auto phy = GetLink(linkId).phy;
1580 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
1581 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
1582 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
1583}
1584
1585bool
1586StaWifiMac::CheckSupportedRates(std::variant<MgtBeaconHeader, MgtProbeResponseHeader> frame,
1587 uint8_t linkId)
1588{
1589 NS_LOG_FUNCTION(this << +linkId);
1590
1591 // lambda to invoke on the current frame variant
1592 auto check = [&](auto&& mgtFrame) -> bool {
1593 // check supported rates
1594 NS_ASSERT(mgtFrame.template Get<SupportedRates>());
1595 const auto rates = AllSupportedRates{*mgtFrame.template Get<SupportedRates>(),
1596 mgtFrame.template Get<ExtendedSupportedRatesIE>()};
1597 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1598 {
1599 if (!rates.IsBssMembershipSelectorRate(selector))
1600 {
1601 NS_LOG_DEBUG("Supported rates do not fit with the BSS membership selector");
1602 return false;
1603 }
1604 }
1605
1606 return true;
1607 };
1608
1609 return std::visit(check, frame);
1610}
1611
1612void
1614 const Mac48Address& apAddr,
1615 const Mac48Address& bssid,
1616 uint8_t linkId)
1617{
1618 NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId);
1619
1620 // ERP Information is not present in Association Response frames
1621 const std::optional<ErpInformation>* erpInformation = nullptr;
1622
1623 if (const auto* beacon = std::get_if<MgtBeaconHeader>(&frame))
1624 {
1625 erpInformation = &beacon->Get<ErpInformation>();
1626 }
1627 else if (const auto* probe = std::get_if<MgtProbeResponseHeader>(&frame))
1628 {
1629 erpInformation = &probe->Get<ErpInformation>();
1630 }
1631
1632 // lambda processing Information Elements included in all frame types
1633 auto commonOps = [&](auto&& frame) {
1634 const auto& capabilities = frame.Capabilities();
1635 NS_ASSERT(frame.template Get<SupportedRates>());
1636 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1637 frame.template Get<ExtendedSupportedRatesIE>()};
1638 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1639 {
1640 if (rates.IsSupportedRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1641 {
1642 GetWifiRemoteStationManager(linkId)->AddSupportedMode(apAddr, mode);
1643 if (rates.IsBasicRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1644 {
1645 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
1646 }
1647 }
1648 }
1649
1650 bool isShortPreambleEnabled = capabilities.IsShortPreamble();
1651 if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId))
1652 {
1653 isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode();
1654 if ((*erpInformation)->GetUseProtection() != 0)
1655 {
1656 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(true);
1657 }
1658 else
1659 {
1660 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(false);
1661 }
1662 if (capabilities.IsShortSlotTime() == true)
1663 {
1664 // enable short slot time
1665 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1666 }
1667 else
1668 {
1669 // disable short slot time
1670 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1671 }
1672 }
1673 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled);
1674 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1675 capabilities.IsShortSlotTime());
1676
1677 if (!GetQosSupported())
1678 {
1679 return;
1680 }
1681 /* QoS station */
1682 bool qosSupported = false;
1683 const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
1684 if (edcaParameters.has_value())
1685 {
1686 qosSupported = true;
1687 // The value of the TXOP Limit field is specified as an unsigned integer, with the least
1688 // significant octet transmitted first, in units of 32 μs.
1690 edcaParameters->GetBeCWmin(),
1691 edcaParameters->GetBeCWmax(),
1692 edcaParameters->GetBeAifsn(),
1693 32 * MicroSeconds(edcaParameters->GetBeTxopLimit())},
1694 linkId);
1696 edcaParameters->GetBkCWmin(),
1697 edcaParameters->GetBkCWmax(),
1698 edcaParameters->GetBkAifsn(),
1699 32 * MicroSeconds(edcaParameters->GetBkTxopLimit())},
1700 linkId);
1702 edcaParameters->GetViCWmin(),
1703 edcaParameters->GetViCWmax(),
1704 edcaParameters->GetViAifsn(),
1705 32 * MicroSeconds(edcaParameters->GetViTxopLimit())},
1706 linkId);
1708 edcaParameters->GetVoCWmin(),
1709 edcaParameters->GetVoCWmax(),
1710 edcaParameters->GetVoAifsn(),
1711 32 * MicroSeconds(edcaParameters->GetVoTxopLimit())},
1712 linkId);
1713 }
1714 GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
1715
1716 if (GetHtSupported(linkId))
1717 {
1718 /* HT station */
1719 if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
1720 htCapabilities.has_value())
1721 {
1722 GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
1723 *htCapabilities);
1724 }
1725 else
1726 {
1727 GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
1728 }
1729 // TODO: process ExtendedCapabilities
1730 // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
1731 }
1732
1733 // we do not return if VHT is not supported because HE STAs operating in
1734 // the 2.4 GHz band do not support VHT
1735 if (GetVhtSupported(linkId))
1736 {
1737 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1738 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1739 // to check whether it supports VHT
1740 if (vhtCapabilities.has_value() &&
1741 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1742 {
1743 GetWifiRemoteStationManager(linkId)->AddStationVhtCapabilities(apAddr,
1744 *vhtCapabilities);
1745 // const auto& vhtOperation = frame.GetVhtOperation ();
1746 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_VHT))
1747 {
1748 if (vhtCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1749 {
1750 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1751 }
1752 }
1753 }
1754 }
1755
1756 if (!GetHeSupported())
1757 {
1758 return;
1759 }
1760 /* HE station */
1761 const auto& heCapabilities = frame.template Get<HeCapabilities>();
1762 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1763 {
1764 GetWifiRemoteStationManager(linkId)->AddStationHeCapabilities(apAddr, *heCapabilities);
1765 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_HE))
1766 {
1767 if (heCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1768 {
1769 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1770 }
1771 }
1772 if (const auto& heOperation = frame.template Get<HeOperation>();
1773 heOperation.has_value())
1774 {
1775 GetHeConfiguration()->SetAttribute(
1776 "BssColor",
1777 UintegerValue(heOperation->m_bssColorInfo.m_bssColor));
1778 }
1779 }
1780
1781 const auto& muEdcaParameters = frame.template Get<MuEdcaParameterSet>();
1782 if (muEdcaParameters.has_value())
1783 {
1785 muEdcaParameters->GetMuCwMin(AC_BE),
1786 muEdcaParameters->GetMuCwMax(AC_BE),
1787 muEdcaParameters->GetMuAifsn(AC_BE),
1788 muEdcaParameters->GetMuEdcaTimer(AC_BE)},
1789 linkId);
1791 muEdcaParameters->GetMuCwMin(AC_BK),
1792 muEdcaParameters->GetMuCwMax(AC_BK),
1793 muEdcaParameters->GetMuAifsn(AC_BK),
1794 muEdcaParameters->GetMuEdcaTimer(AC_BK)},
1795 linkId);
1797 muEdcaParameters->GetMuCwMin(AC_VI),
1798 muEdcaParameters->GetMuCwMax(AC_VI),
1799 muEdcaParameters->GetMuAifsn(AC_VI),
1800 muEdcaParameters->GetMuEdcaTimer(AC_VI)},
1801 linkId);
1803 muEdcaParameters->GetMuCwMin(AC_VO),
1804 muEdcaParameters->GetMuCwMax(AC_VO),
1805 muEdcaParameters->GetMuAifsn(AC_VO),
1806 muEdcaParameters->GetMuEdcaTimer(AC_VO)},
1807 linkId);
1808 }
1809
1810 if (Is6GhzBand(linkId))
1811 {
1812 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
1813 {
1814 GetWifiRemoteStationManager(linkId)->AddStationHe6GhzCapabilities(
1815 apAddr,
1816 *he6GhzCapabilities);
1817 }
1818 }
1819
1820 if (!GetEhtSupported())
1821 {
1822 return;
1823 }
1824 /* EHT station */
1825 const auto& ehtCapabilities = frame.template Get<EhtCapabilities>();
1826 // TODO: once we support non constant rate managers, we should add checks here whether EHT
1827 // is supported by the peer
1828 GetWifiRemoteStationManager(linkId)->AddStationEhtCapabilities(apAddr, *ehtCapabilities);
1829
1830 if (const auto& mle = frame.template Get<MultiLinkElement>(); mle && m_emlsrManager)
1831 {
1832 if (mle->HasEmlCapabilities())
1833 {
1834 m_emlsrManager->SetTransitionTimeout(mle->GetTransitionTimeout());
1835 }
1836 if (const auto& common = mle->GetCommonInfoBasic(); common.m_mediumSyncDelayInfo)
1837 {
1838 m_emlsrManager->SetMediumSyncDuration(common.GetMediumSyncDelayTimer());
1839 m_emlsrManager->SetMediumSyncOfdmEdThreshold(common.GetMediumSyncOfdmEdThreshold());
1840 m_emlsrManager->SetMediumSyncMaxNTxops(common.GetMediumSyncMaxNTxops());
1841 }
1842 }
1843 };
1844
1845 // process Information Elements included in the current frame variant
1846 std::visit(commonOps, frame);
1847}
1848
1849void
1850StaWifiMac::SetPowerSaveMode(const std::pair<bool, uint8_t>& enableLinkIdPair)
1851{
1852 const auto [enable, linkId] = enableLinkIdPair;
1853 NS_LOG_FUNCTION(this << enable << linkId);
1854
1855 auto& link = GetLink(linkId);
1856
1857 if (!IsAssociated())
1858 {
1859 NS_LOG_DEBUG("Not associated yet, record the PM mode to switch to upon association");
1860 link.pmMode = enable ? WIFI_PM_POWERSAVE : WIFI_PM_ACTIVE;
1861 return;
1862 }
1863
1864 if (!link.bssid)
1865 {
1866 NS_LOG_DEBUG("Link " << +linkId << " has not been setup, ignore request");
1867 return;
1868 }
1869
1870 if ((enable && link.pmMode == WIFI_PM_POWERSAVE) || (!enable && link.pmMode == WIFI_PM_ACTIVE))
1871 {
1872 NS_LOG_DEBUG("No PM mode change needed");
1873 return;
1874 }
1875
1877
1878 // reschedule a call to this function to make sure that the PM mode switch
1879 // is eventually completed
1882 this,
1883 enableLinkIdPair);
1884
1885 if (HasFramesToTransmit(linkId))
1886 {
1887 NS_LOG_DEBUG("Next transmitted frame will be sent with PM=" << enable);
1888 return;
1889 }
1890
1891 // No queued frames. Enqueue a Data Null frame to inform the AP of the PM mode change
1893
1894 hdr.SetAddr1(GetBssid(linkId));
1896 hdr.SetAddr3(GetBssid(linkId));
1897 hdr.SetDsNotFrom();
1898 hdr.SetDsTo();
1899 enable ? hdr.SetPowerManagement() : hdr.SetNoPowerManagement();
1900 if (GetQosSupported())
1901 {
1902 GetQosTxop(AC_BE)->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1903 }
1904 else
1905 {
1906 m_txop->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1907 }
1908}
1909
1911StaWifiMac::GetPmMode(uint8_t linkId) const
1912{
1913 return GetLink(linkId).pmMode;
1914}
1915
1916void
1918{
1919 NS_LOG_FUNCTION(this << *mpdu);
1920
1921 auto linkId = GetLinkIdByAddress(mpdu->GetHeader().GetAddr2());
1922
1923 if (!linkId)
1924 {
1925 // the given MPDU may be the original copy containing MLD addresses and not carrying
1926 // a valid PM bit (which is set on the aliases).
1927 auto linkIds = mpdu->GetInFlightLinkIds();
1928 NS_ASSERT_MSG(!linkIds.empty(),
1929 "The TA of the acked MPDU (" << *mpdu
1930 << ") is not a link "
1931 "address and the MPDU is not inflight");
1932 // in case the ack'ed MPDU is inflight on multiple links, we cannot really know if
1933 // it was received by the AP on all links or only on some links. Hence, we only
1934 // consider the first link ID in the set, given that in the most common case of MPDUs
1935 // that cannot be sent concurrently on multiple links, there will be only one link ID
1936 linkId = *linkIds.begin();
1937 mpdu = GetTxopQueue(mpdu->GetQueueAc())->GetAlias(mpdu, *linkId);
1938 }
1939
1940 auto& link = GetLink(*linkId);
1941 const WifiMacHeader& hdr = mpdu->GetHeader();
1942
1943 // we received an acknowledgment while switching PM mode; the PM mode change is effective now
1944 if (hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_PS)
1945 {
1946 link.pmMode = WIFI_PM_POWERSAVE;
1947 }
1948 else if (!hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_ACTIVE)
1949 {
1950 link.pmMode = WIFI_PM_ACTIVE;
1951 }
1952}
1953
1956{
1957 AllSupportedRates rates;
1958 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1959 {
1960 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
1961 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
1962 rates.AddSupportedRate(modeDataRate);
1963 }
1964 if (GetHtSupported(linkId))
1965 {
1966 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1967 {
1968 rates.AddBssMembershipSelectorRate(selector);
1969 }
1970 }
1971 return rates;
1972}
1973
1975StaWifiMac::GetCapabilities(uint8_t linkId) const
1976{
1977 CapabilityInformation capabilities;
1978 capabilities.SetShortPreamble(GetWifiPhy(linkId)->GetShortPhyPreambleSupported() ||
1979 GetErpSupported(linkId));
1981 return capabilities;
1982}
1983
1984void
1986{
1987 m_state = value;
1988}
1989
1990void
1991StaWifiMac::SetEdcaParameters(const EdcaParams& params, uint8_t linkId)
1992{
1993 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1994 edca->SetMinCw(params.cwMin, linkId);
1995 edca->SetMaxCw(params.cwMax, linkId);
1996 edca->SetAifsn(params.aifsn, linkId);
1997 edca->SetTxopLimit(params.txopLimit, linkId);
1998}
1999
2000void
2001StaWifiMac::SetMuEdcaParameters(const MuEdcaParams& params, uint8_t linkId)
2002{
2003 Ptr<QosTxop> edca = GetQosTxop(params.ac);
2004 edca->SetMuCwMin(params.cwMin, linkId);
2005 edca->SetMuCwMax(params.cwMax, linkId);
2006 edca->SetMuAifsn(params.aifsn, linkId);
2007 edca->SetMuEdcaTimer(params.muEdcaTimer, linkId);
2008}
2009
2010void
2012{
2013 NS_LOG_FUNCTION(this);
2014 if (IsAssociated())
2015 {
2016 NS_LOG_DEBUG("PHY capabilities changed: send reassociation request");
2019 }
2020}
2021
2022/**
2023 * Initial configuration:
2024 *
2025 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2026 * Link A │FEM│RSM│CAM│◄──────►│Main├──────►│Channel│
2027 * │ │ │ │ │PHY │ │ A │
2028 * └───┴───┴───┘ └────┘ └───────┘
2029 *
2030 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2031 * Link B │FEM│RSM│CAM│ │Aux │ │Channel│
2032 * │ │ │ │◄──────►│PHY ├──────►│ B │
2033 * └───┴───┴───┘ └────┘ └───────┘
2034 *
2035 * A link switching/swapping is notified by the EMLSR Manager and the Channel Access Manager
2036 * (CAM) notifies us that a first PHY (i.e., the Main PHY) switches to Channel B. We connect
2037 * the Main PHY to the MAC stack B:
2038 *
2039 *
2040 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2041 * Link A │FEM│RSM│CAM│ ┌───►│Main├───┐ │Channel│
2042 * │ │ │ │ │ │PHY │ │ │ A │
2043 * └───┴───┴───┘ │ └────┘ │ └───────┘
2044 * │ │
2045 * ┌───┬───┬───┐ │ ┌────┐ │ ┌───────┐
2046 * Link B │FEM│RSM│CAM│◄──┘ │Aux │ └──►│Channel│
2047 * │ │ │ │◄─ ─ ─ ─│PHY ├──────►│ B │
2048 * └───┴───┴───┘INACTIVE└────┘ └───────┘
2049 *
2050 * MAC stack B keeps a PHY listener associated with the Aux PHY, even though it is inactive,
2051 * meaning that the PHY listener will only notify channel switches (no CCA, no RX).
2052 * If the EMLSR Manager requested a link switching, this configuration will be kept until
2053 * further requests. If the EMLSR Manager requested a link swapping, link B's CAM will be
2054 * notified by its (inactive) PHY listener upon the channel switch performed by the Aux PHY.
2055 * In this case, we remove the inactive PHY listener and connect the Aux PHY to MAC stack A:
2056 *
2057 * ┌───┬───┬───┐ ┌────┐ ┌───────┐
2058 * Link A │FEM│RSM│CAM│◄─┐ ┌──►│Main├───┐ │Channel│
2059 * │ │ │ │ │ │ │PHY │ ┌─┼──►│ A │
2060 * └───┴───┴───┘ │ │ └────┘ │ │ └───────┘
2061 * │ │ │ │
2062 * ┌───┬───┬───┐ │ │ ┌────┐ │ │ ┌───────┐
2063 * Link B │FEM│RSM│CAM│◄─┼─┘ │Aux │ │ └──►│Channel│
2064 * │ │ │ │ └────►│PHY ├─┘ │ B │
2065 * └───┴───┴───┘ └────┘ └───────┘
2066 */
2067
2068void
2070{
2071 NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
2072
2073 // If the PHY is switching channel to operate on another link, then it is no longer operating
2074 // on the current link. If any link (other than the current link) points to the PHY that is
2075 // switching channel, reset the phy pointer of the link
2076 for (auto& [id, link] : GetLinks())
2077 {
2078 if (link->phy == phy && id != linkId)
2079 {
2080 link->phy = nullptr;
2081 }
2082 }
2083
2084 // lambda to connect the PHY to the new link
2085 auto connectPhy = [=, this]() mutable {
2086 auto& newLink = GetLink(linkId);
2087 // The MAC stack associated with the new link uses the given PHY
2088 newLink.phy = phy;
2089 // Setup a PHY listener for the given PHY on the CAM associated with the new link
2090 newLink.channelAccessManager->SetupPhyListener(phy);
2092 if (m_emlsrManager->GetCamStateReset())
2093 {
2094 newLink.channelAccessManager->ResetState();
2095 }
2096 // Disconnect the FEM on the new link from the current PHY
2097 newLink.feManager->ResetPhy();
2098 // Connect the FEM on the new link to the given PHY
2099 newLink.feManager->SetWifiPhy(phy);
2100 // Connect the station manager on the new link to the given PHY
2101 newLink.stationManager->SetupPhy(phy);
2102 };
2103
2104 // if there is no PHY operating on the new link, connect the PHY to the new link now.
2105 // Otherwise, wait until the channel switch is completed, so that the PHY operating on the new
2106 // link can possibly continue receiving frames in the meantime.
2107 if (!GetLink(linkId).phy)
2108 {
2109 connectPhy();
2110 }
2111 else
2112 {
2113 Simulator::Schedule(delay, connectPhy);
2114 }
2115}
2116
2117void
2119{
2120 NS_LOG_FUNCTION(this << +linkId);
2121
2123
2124 if (IsInitialized() && IsAssociated())
2125 {
2126 Disassociated();
2127 }
2128
2129 // notify association manager
2130 m_assocManager->NotifyChannelSwitched(linkId);
2131}
2132
2133std::ostream&
2134operator<<(std::ostream& os, const StaWifiMac::ApInfo& apInfo)
2135{
2136 os << "BSSID=" << apInfo.m_bssid << ", AP addr=" << apInfo.m_apAddr << ", SNR=" << apInfo.m_snr
2137 << ", Channel={" << apInfo.m_channel.number << "," << apInfo.m_channel.band
2138 << "}, Link ID=" << +apInfo.m_linkId << ", Frame=[";
2139 std::visit([&os](auto&& frame) { frame.Print(os); }, apInfo.m_frame);
2140 os << "]";
2141 return os;
2142}
2143
2144} // namespace ns3
A container for one type of attribute.
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 IsPending() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:69
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
The HE 6 GHz Band Capabilities (IEEE 802.11ax-2021 9.4.2.263)
The IEEE 802.11ax HE Capabilities.
The HT Capabilities Information Element.
an EUI-48 address
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:162
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:339
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:517
Implement the header for management frames of type probe request.
Definition: mgt-headers.h:437
Implement the header for management frames of type probe response.
Definition: mgt-headers.h:456
CapabilityInformation & Capabilities()
Definition: mgt-headers.cc:93
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:246
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
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:144
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:610
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:608
void DoCompleteConfig() override
Allow subclasses to complete the configuration of the MAC layer components.
bool m_activeProbing
active probing
Definition: sta-wifi-mac.h:617
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:616
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:629
MacState
The current MAC state of the STA.
Definition: sta-wifi-mac.h:374
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:615
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:614
TracedCallback< uint8_t, Mac48Address > m_setupCompleted
link setup completed logger
Definition: sta-wifi-mac.h:628
TracedCallback< Mac48Address > m_assocLogger
association logger
Definition: sta-wifi-mac.h:627
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:630
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:620
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:625
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:618
TracedCallback< ApInfo > m_beaconInfo
beacon info logger
Definition: sta-wifi-mac.h:632
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:607
MacState m_state
MAC state.
Definition: sta-wifi-mac.h:606
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:631
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:609
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:612
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:611
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:153
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:613
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:623
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
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:623
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:981
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition: wifi-mac.cc:627
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition: wifi-mac.cc:676
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1774
Mac48Address GetBssid(uint8_t linkId) const
Definition: wifi-mac.cc:522
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1891
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition: wifi-mac.cc:1057
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition: wifi-mac.cc:547
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2162
Callback< void > m_linkDown
Callback when a link is down.
Definition: wifi-mac.h:920
bool GetQosSupported() const
Return whether the device supports QoS.
Definition: wifi-mac.cc:1347
Ptr< Txop > m_txop
TXOP used for transmission of frames to non-QoS peers.
Definition: wifi-mac.h:916
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:670
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:1072
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:1134
void DoInitialize() override
Initialize() implementation.
Definition: wifi-mac.cc:393
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:1558
Ssid GetSsid() const
Definition: wifi-mac.cc:509
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition: wifi-mac.cc:1353
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition: wifi-mac.cc:615
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition: wifi-mac.cc:459
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1315
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:1512
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition: wifi-mac.cc:1924
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1918
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition: wifi-mac.cc:2103
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:1100
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the MAC has frames to transmit over the given link.
Definition: wifi-mac.cc:646
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:1430
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition: wifi-mac.cc:1897
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition: wifi-mac.cc:1910
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:364
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:1762
void SetBssid(Mac48Address bssid, uint8_t linkId)
Definition: wifi-mac.cc:515
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:483
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:1213
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition: wifi-mac.cc:2092
He6GhzBandCapabilities GetHe6GhzBandCapabilities(uint8_t linkId) const
Return the HE 6GHz band capabilities of the device for the given 6 GHz link.
Definition: wifi-mac.cc:2302
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:639
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:1113
bool GetShortSlotTimeSupported() const
Definition: wifi-mac.cc:1397
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:713
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:1045
bool GetHtSupported(uint8_t linkId) const
Return whether the device supports HT on the given link.
Definition: wifi-mac.cc:1903
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition: wifi-mac.cc:1632
bool Is6GhzBand(uint8_t linkId) const
Indicate if a given link is on the 6 GHz band.
Definition: wifi-mac.cc:1205
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:1639
Mac48Address GetAddress() const
Definition: wifi-mac.cc:496
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2337
Callback< void > m_linkUp
Callback when a link is up.
Definition: wifi-mac.h:919
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: wifi-mac.cc:1063
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition: wifi-mac.cc:2244
virtual void SetWifiPhys(const std::vector< Ptr< WifiPhy > > &phys)
Definition: wifi-mac.cc:1293
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:593
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:695
void DoDispose() override
Destructor implementation.
Definition: wifi-mac.cc:417
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1539
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition: wifi-phy.cc:819
void SetOffMode()
Put in off mode.
Definition: wifi-phy.cc:1415
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 > MakePointerAccessor(T1 a1)
Definition: pointer.h:259
#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:92
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:96
@ WIFI_PM_POWERSAVE
Definition: sta-wifi-mac.h:95
@ WIFI_PM_SWITCHING_TO_PS
Definition: sta-wifi-mac.h:94
@ WIFI_PM_ACTIVE
Definition: sta-wifi-mac.h:93
@ 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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
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:700
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
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:150
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition: log.h:106
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
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:160
MgtFrameType m_frame
The body of the management frame used to update AP info.
Definition: sta-wifi-mac.h:174
WifiScanParams::Channel m_channel
The channel the management frame was received on.
Definition: sta-wifi-mac.h:175
Mac48Address m_apAddr
AP MAC address.
Definition: sta-wifi-mac.h:172
uint8_t m_linkId
ID of the link used to communicate with the AP.
Definition: sta-wifi-mac.h:176
Mac48Address m_bssid
BSSID.
Definition: sta-wifi-mac.h:171
double m_snr
SNR in linear scale.
Definition: sta-wifi-mac.h:173
Struct identifying a channel to scan.
Definition: sta-wifi-mac.h:70
WifiPhyBand band
PHY band.
Definition: sta-wifi-mac.h:72
uint16_t number
channel number
Definition: sta-wifi-mac.h:71
Structure holding scan parameters.
Definition: sta-wifi-mac.h:62
std::list< Channel > ChannelList
typedef for a list of channels
Definition: sta-wifi-mac.h:76
std::vector< ChannelList > channelList
list of channels to scan, for each link
Definition: sta-wifi-mac.h:80
Time probeDelay
delay prior to transmitting a Probe Request
Definition: sta-wifi-mac.h:81
WifiScanType type
indicates either active or passive scanning
Definition: sta-wifi-mac.h:78
Time maxChannelTime
maximum time to spend on each channel
Definition: sta-wifi-mac.h:83
Ssid ssid
desired SSID or wildcard SSID
Definition: sta-wifi-mac.h:79
Time minChannelTime
minimum time to spend on each channel
Definition: sta-wifi-mac.h:82