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-headers.h"
27#include "qos-txop.h"
28#include "snr-tag.h"
29#include "wifi-assoc-manager.h"
30#include "wifi-mac-queue.h"
31#include "wifi-net-device.h"
32#include "wifi-phy.h"
33
34#include "ns3/eht-configuration.h"
35#include "ns3/emlsr-manager.h"
36#include "ns3/he-configuration.h"
37#include "ns3/ht-configuration.h"
38#include "ns3/log.h"
39#include "ns3/packet.h"
40#include "ns3/pair.h"
41#include "ns3/pointer.h"
42#include "ns3/random-variable-stream.h"
43#include "ns3/simulator.h"
44#include "ns3/string.h"
45
46#include <numeric>
47
48namespace ns3
49{
50
51NS_LOG_COMPONENT_DEFINE("StaWifiMac");
52
54
55TypeId
57{
58 static TypeId tid =
59 TypeId("ns3::StaWifiMac")
61 .SetGroupName("Wifi")
62 .AddConstructor<StaWifiMac>()
63 .AddAttribute("ProbeRequestTimeout",
64 "The duration to actively probe the channel.",
65 TimeValue(Seconds(0.05)),
68 .AddAttribute("WaitBeaconTimeout",
69 "The duration to dwell on a channel while passively scanning for beacon",
73 .AddAttribute("AssocRequestTimeout",
74 "The interval between two consecutive association request attempts.",
75 TimeValue(Seconds(0.5)),
78 .AddAttribute("MaxMissedBeacons",
79 "Number of beacons which much be consecutively missed before "
80 "we attempt to restart association.",
81 UintegerValue(10),
83 MakeUintegerChecker<uint32_t>())
84 .AddAttribute(
85 "ActiveProbing",
86 "If true, we send probe requests. If false, we don't."
87 "NOTE: if more than one STA in your simulation is using active probing, "
88 "you should enable it at a different simulation time for each STA, "
89 "otherwise all the STAs will start sending probes at the same time resulting in "
90 "collisions. "
91 "See bug 1060 for more info.",
92 BooleanValue(false),
95 .AddAttribute("ProbeDelay",
96 "Delay (in microseconds) to be used prior to transmitting a "
97 "Probe frame during active scanning.",
98 StringValue("ns3::UniformRandomVariable[Min=50.0|Max=250.0]"),
100 MakePointerChecker<RandomVariableStream>())
101 .AddAttribute(
102 "PowerSaveMode",
103 "Enable/disable power save mode on the given link. The power management mode is "
104 "actually changed when the AP acknowledges a frame sent with the Power Management "
105 "field set to the value corresponding to the requested mode",
106 TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
108 MakePairAccessor<BooleanValue, UintegerValue>(&StaWifiMac::SetPowerSaveMode),
109 MakePairChecker<BooleanValue, UintegerValue>(MakeBooleanChecker(),
110 MakeUintegerChecker<uint8_t>()))
111 .AddAttribute("PmModeSwitchTimeout",
112 "If switching to a new Power Management mode is not completed within "
113 "this amount of time, make another attempt at switching Power "
114 "Management mode.",
115 TimeValue(Seconds(0.1)),
118 .AddTraceSource("Assoc",
119 "Associated with an access point. If this is an MLD that associated "
120 "with an AP MLD, the AP MLD address is provided.",
122 "ns3::Mac48Address::TracedCallback")
123 .AddTraceSource("LinkSetupCompleted",
124 "A link was setup in the context of ML setup with an AP MLD. "
125 "Provides ID of the setup link and AP MAC address",
127 "ns3::StaWifiMac::LinkSetupCallback")
128 .AddTraceSource("DeAssoc",
129 "Association with an access point lost. If this is an MLD "
130 "that disassociated with an AP MLD, the AP MLD address is provided.",
132 "ns3::Mac48Address::TracedCallback")
133 .AddTraceSource("LinkSetupCanceled",
134 "A link setup in the context of ML setup with an AP MLD was torn down. "
135 "Provides ID of the setup link and AP MAC address",
137 "ns3::StaWifiMac::LinkSetupCallback")
138 .AddTraceSource("BeaconArrival",
139 "Time of beacons arrival from associated AP",
141 "ns3::Time::TracedCallback")
142 .AddTraceSource("ReceivedBeaconInfo",
143 "Information about every received Beacon frame",
145 "ns3::ApInfo::TracedCallback");
146 return tid;
147}
148
150 : m_state(UNASSOCIATED),
151 m_aid(0),
152 m_assocRequestEvent()
153{
154 NS_LOG_FUNCTION(this);
155
156 // Let the lower layers know that we are acting as a non-AP STA in
157 // an infrastructure BSS.
159}
160
161void
163{
164 NS_LOG_FUNCTION(this);
168}
169
170void
172{
173 NS_LOG_FUNCTION(this);
174 if (m_assocManager)
175 {
176 m_assocManager->Dispose();
177 }
178 m_assocManager = nullptr;
179 if (m_emlsrManager)
180 {
181 m_emlsrManager->Dispose();
182 }
183 m_emlsrManager = nullptr;
185}
186
188{
189 NS_LOG_FUNCTION(this);
190}
191
193{
195}
196
197std::unique_ptr<WifiMac::LinkEntity>
199{
200 return std::make_unique<StaLinkEntity>();
201}
202
204StaWifiMac::GetLink(uint8_t linkId) const
205{
206 return static_cast<StaLinkEntity&>(WifiMac::GetLink(linkId));
207}
208
209int64_t
211{
212 NS_LOG_FUNCTION(this << stream);
213 m_probeDelay->SetStream(stream);
214 return 1;
215}
216
217void
219{
220 NS_LOG_FUNCTION(this << assocManager);
221 m_assocManager = assocManager;
222 m_assocManager->SetStaWifiMac(this);
223}
224
225void
227{
228 NS_LOG_FUNCTION(this << emlsrManager);
229 m_emlsrManager = emlsrManager;
230 m_emlsrManager->SetWifiMac(this);
231}
232
235{
236 return m_emlsrManager;
237}
238
239uint16_t
241{
242 NS_ASSERT_MSG(IsAssociated(), "This station is not associated to any AP");
243 return m_aid;
244}
245
246void
248{
249 NS_LOG_FUNCTION(this << enable);
250 m_activeProbing = enable;
251 if (m_state == SCANNING)
252 {
253 NS_LOG_DEBUG("STA is still scanning, reset scanning process");
255 }
256}
257
258bool
260{
261 return m_activeProbing;
262}
263
264void
265StaWifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
266{
267 NS_LOG_FUNCTION(this);
269 for (auto& phy : phys)
270 {
271 phy->SetCapabilitiesChangedCallback(
273 }
274}
275
277StaWifiMac::GetCurrentChannel(uint8_t linkId) const
278{
279 auto phy = GetWifiPhy(linkId);
280 uint16_t width = phy->GetOperatingChannel().IsOfdm() ? 20 : phy->GetChannelWidth();
281 uint8_t ch = phy->GetOperatingChannel().GetPrimaryChannelNumber(width, phy->GetStandard());
282 return {ch, phy->GetPhyBand()};
283}
284
285void
287{
288 NS_LOG_FUNCTION(this << linkId);
289 WifiMacHeader hdr;
294 hdr.SetDsNotFrom();
295 hdr.SetDsNotTo();
296 Ptr<Packet> packet = Create<Packet>();
298 probe.Get<Ssid>() = GetSsid();
299 auto supportedRates = GetSupportedRates(linkId);
300 probe.Get<SupportedRates>() = supportedRates.rates;
301 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
302 if (GetHtSupported())
303 {
305 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
306 }
307 if (GetVhtSupported(linkId))
308 {
309 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
310 }
311 if (GetHeSupported())
312 {
313 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
314 }
315 if (GetEhtSupported())
316 {
317 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
318 }
319 packet->AddHeader(probe);
320
321 if (!GetQosSupported())
322 {
323 GetTxop()->Queue(packet, hdr);
324 }
325 // "A QoS STA that transmits a Management frame determines access category used
326 // for medium access in transmission of the Management frame as follows
327 // (If dot11QMFActivated is false or not present)
328 // — If the Management frame is individually addressed to a non-QoS STA, category
329 // AC_BE should be selected.
330 // — If category AC_BE was not selected by the previous step, category AC_VO
331 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
332 else
333 {
334 GetVOQueue()->Queue(packet, hdr);
335 }
336}
337
338std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>
339StaWifiMac::GetAssociationRequest(bool isReassoc, uint8_t linkId) const
340{
341 NS_LOG_FUNCTION(this << isReassoc << +linkId);
342
343 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader> mgtFrame;
344
345 if (isReassoc)
346 {
348 reassoc.SetCurrentApAddress(GetBssid(linkId));
349 mgtFrame = std::move(reassoc);
350 }
351 else
352 {
353 mgtFrame = MgtAssocRequestHeader();
354 }
355
356 // lambda to set the fields of the (Re)Association Request
357 auto fill = [&](auto&& frame) {
358 frame.template Get<Ssid>() = GetSsid();
359 auto supportedRates = GetSupportedRates(linkId);
360 frame.template Get<SupportedRates>() = supportedRates.rates;
361 frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
362 frame.Capabilities() = GetCapabilities(linkId);
363 frame.SetListenInterval(0);
364 if (GetHtSupported())
365 {
366 frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
367 frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
368 }
369 if (GetVhtSupported(linkId))
370 {
371 frame.template Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
372 }
373 if (GetHeSupported())
374 {
375 frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
376 }
377 if (GetEhtSupported())
378 {
379 frame.template Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
380 }
381 };
382
383 std::visit(fill, mgtFrame);
384 return mgtFrame;
385}
386
388StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
389{
390 NS_LOG_FUNCTION(this << isReassoc << +linkId);
391
393 // The Common info field of the Basic Multi-Link element carried in the (Re)Association
394 // Request frame shall include the MLD MAC address, the MLD Capabilities and Operations,
395 // and the EML Capabilities subfields, and shall not include the Link ID Info, the BSS
396 // Parameters Change Count, and the Medium Synchronization Delay Information subfields
397 // (Sec. 35.3.5.4 of 802.11be D2.0)
398 // TODO Add the MLD Capabilities and Operations subfield
399 multiLinkElement.SetMldMacAddress(GetAddress());
400
401 if (m_emlsrManager) // EMLSR Manager is only installed if EMLSR is activated
402 {
403 multiLinkElement.SetEmlsrSupported(true);
404 TimeValue time;
405 m_emlsrManager->GetAttribute("EmlsrPaddingDelay", time);
406 multiLinkElement.SetEmlsrPaddingDelay(time.Get());
407 m_emlsrManager->GetAttribute("EmlsrTransitionDelay", time);
408 multiLinkElement.SetEmlsrTransitionDelay(time.Get());
409 // When the Transition Timeout subfield is included in a frame sent by a non-AP STA
410 // affiliated with a non-AP MLD, the Transition Timeout subfield is reserved
411 // (Section 9.4.2.312.2.3 of 802.11be D2.3)
412 }
413
414 // For each requested link in addition to the link on which the (Re)Association Request
415 // frame is transmitted, the Link Info field of the Basic Multi-Link element carried
416 // in the (Re)Association Request frame shall contain the corresponding Per-STA Profile
417 // subelement(s).
418 for (uint8_t index = 0; index < GetNLinks(); index++)
419 {
420 auto& link = GetLink(index);
421 if (index != linkId && link.apLinkId.has_value())
422 {
423 multiLinkElement.AddPerStaProfileSubelement();
424 auto& perStaProfile = multiLinkElement.GetPerStaProfile(
425 multiLinkElement.GetNPerStaProfileSubelements() - 1);
426 // The Link ID subfield of the STA Control field of the Per-STA Profile subelement
427 // for the corresponding non-AP STA that requests a link for multi-link (re)setup
428 // with the AP MLD is set to the link ID of the AP affiliated with the AP MLD that
429 // is operating on that link. The link ID is obtained during multi-link discovery
430 perStaProfile.SetLinkId(link.apLinkId.value());
431 // For each Per-STA Profile subelement included in the Link Info field, the
432 // Complete Profile subfield of the STA Control field shall be set to 1
433 perStaProfile.SetCompleteProfile();
434 // The MAC Address Present subfield indicates the presence of the STA MAC Address
435 // subfield in the STA Info field and is set to 1 if the STA MAC Address subfield
436 // is present in the STA Info field; otherwise set to 0. An STA sets this subfield
437 // to 1 when the element carries complete profile.
438 perStaProfile.SetStaMacAddress(link.feManager->GetAddress());
439 perStaProfile.SetAssocRequest(GetAssociationRequest(isReassoc, index));
440 }
441 }
442
443 return multiLinkElement;
444}
445
446void
448{
449 // find the link where the (Re)Association Request has to be sent
450 uint8_t linkId = 0;
451 while (linkId < GetNLinks())
452 {
453 if (GetLink(linkId).sendAssocReq)
454 {
455 break;
456 }
457 linkId++;
458 }
459 NS_ABORT_MSG_IF(linkId == GetNLinks(), "No link selected to send the (Re)Association Request");
460 auto& link = GetLink(linkId);
461 NS_ABORT_MSG_IF(!link.bssid.has_value(),
462 "No BSSID set for the link on which the (Re)Association Request is to be sent");
463
464 NS_LOG_FUNCTION(this << *link.bssid << isReassoc);
465 WifiMacHeader hdr;
467 hdr.SetAddr1(*link.bssid);
468 hdr.SetAddr2(link.feManager->GetAddress());
469 hdr.SetAddr3(*link.bssid);
470 hdr.SetDsNotFrom();
471 hdr.SetDsNotTo();
472 Ptr<Packet> packet = Create<Packet>();
473
474 auto frame = GetAssociationRequest(isReassoc, linkId);
475
476 // include a Multi-Link Element if this device has multiple links (independently
477 // of how many links will be setup) and the AP is a multi-link device
478 if (GetNLinks() > 1 &&
479 GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
480 {
481 auto addMle = [&](auto&& frame) {
482 frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
483 };
484 std::visit(addMle, frame);
485 }
486
487 if (!isReassoc)
488 {
489 packet->AddHeader(std::get<MgtAssocRequestHeader>(frame));
490 }
491 else
492 {
493 packet->AddHeader(std::get<MgtReassocRequestHeader>(frame));
494 }
495
496 if (!GetQosSupported())
497 {
498 GetTxop()->Queue(packet, hdr);
499 }
500 // "A QoS STA that transmits a Management frame determines access category used
501 // for medium access in transmission of the Management frame as follows
502 // (If dot11QMFActivated is false or not present)
503 // — If the Management frame is individually addressed to a non-QoS STA, category
504 // AC_BE should be selected.
505 // — If category AC_BE was not selected by the previous step, category AC_VO
506 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
507 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(*link.bssid))
508 {
509 GetBEQueue()->Queue(packet, hdr);
510 }
511 else
512 {
513 GetVOQueue()->Queue(packet, hdr);
514 }
515
517 {
519 }
522}
523
524void
526{
527 NS_LOG_FUNCTION(this);
528 switch (m_state)
529 {
530 case ASSOCIATED:
531 return;
532 case SCANNING:
533 /* we have initiated active or passive scanning, continue to wait
534 and gather beacons or probe responses until the scanning timeout
535 */
536 break;
537 case UNASSOCIATED:
538 /* we were associated but we missed a bunch of beacons
539 * so we should assume we are not associated anymore.
540 * We try to initiate a scan now.
541 */
542 m_linkDown();
544 break;
545 case WAIT_ASSOC_RESP:
546 /* we have sent an association request so we do not need to
547 re-send an association request right now. We just need to
548 wait until either assoc-request-timeout or until
549 we get an association response.
550 */
551 break;
552 case REFUSED:
553 /* we have sent an association request and received a negative
554 association response. We wait until someone restarts an
555 association with a given SSID.
556 */
557 break;
558 }
559}
560
561void
563{
564 NS_LOG_FUNCTION(this);
567
568 WifiScanParams scanParams;
569 scanParams.ssid = GetSsid();
570 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
571 {
573 (GetWifiPhy(linkId)->HasFixedPhyBand())
576
577 scanParams.channelList.push_back(channel);
578 }
579 if (m_activeProbing)
580 {
581 scanParams.type = WifiScanType::ACTIVE;
583 scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
584 }
585 else
586 {
587 scanParams.type = WifiScanType::PASSIVE;
589 }
590
591 m_assocManager->StartScanning(std::move(scanParams));
592}
593
594void
595StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& bestAp)
596{
597 NS_LOG_FUNCTION(this);
598
599 if (!bestAp.has_value())
600 {
601 NS_LOG_DEBUG("Exhausted list of candidate AP; restart scanning");
603 return;
604 }
605
606 NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
607 UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
608 // reset info on links to setup
609 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
610 {
611 auto& link = GetLink(linkId);
612 link.sendAssocReq = false;
613 link.apLinkId = std::nullopt;
614 link.bssid = std::nullopt;
615 }
616 // send Association Request on the link where the Beacon/Probe Response was received
617 GetLink(bestAp->m_linkId).sendAssocReq = true;
618 GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
619 // update info on links to setup (11be MLDs only)
620 for (const auto& [localLinkId, apLinkId] : bestAp->m_setupLinks)
621 {
622 NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
623 << ")");
624 GetLink(localLinkId).apLinkId = apLinkId;
625 if (localLinkId == bestAp->m_linkId)
626 {
627 continue;
628 }
629 auto mldAddress =
630 GetWifiRemoteStationManager(bestAp->m_linkId)->GetMldAddress(bestAp->m_bssid);
631 NS_ABORT_MSG_IF(!mldAddress.has_value(), "AP MLD address not set");
632 auto bssid = GetWifiRemoteStationManager(localLinkId)->GetAffiliatedStaAddress(*mldAddress);
633 NS_ABORT_MSG_IF(!mldAddress.has_value(),
634 "AP link address not set for local link " << +localLinkId);
635 GetLink(localLinkId).bssid = *bssid;
636 }
637 // lambda to get beacon interval from Beacon or Probe Response
638 auto getBeaconInterval = [](auto&& frame) {
639 using T = std::decay_t<decltype(frame)>;
640 if constexpr (std::is_same_v<T, MgtBeaconHeader> ||
641 std::is_same_v<T, MgtProbeResponseHeader>)
642 {
643 return MicroSeconds(frame.GetBeaconIntervalUs());
644 }
645 else
646 {
647 NS_ABORT_MSG("Unexpected frame type");
648 return Seconds(0);
649 }
650 };
651 Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
652 Time delay = beaconInterval * m_maxMissedBeacons;
653 // restart beacon watchdog for all links to setup
654 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
655 {
656 if (GetLink(linkId).apLinkId.has_value() || GetNLinks() == 1)
657 {
658 RestartBeaconWatchdog(delay, linkId);
659 }
660 }
663}
664
665void
667{
668 NS_LOG_FUNCTION(this);
671}
672
673void
675{
676 NS_LOG_FUNCTION(this << +linkId);
677 auto& link = GetLink(linkId);
678 if (link.beaconWatchdogEnd > Simulator::Now())
679 {
680 if (link.beaconWatchdog.IsRunning())
681 {
682 link.beaconWatchdog.Cancel();
683 }
684 link.beaconWatchdog = Simulator::Schedule(link.beaconWatchdogEnd - Simulator::Now(),
686 this,
687 linkId);
688 return;
689 }
690 NS_LOG_DEBUG("beacon missed");
691 // We need to switch to the UNASSOCIATED state. However, if we are receiving
692 // a frame, wait until the RX is completed (otherwise, crashes may occur if
693 // we are receiving a MU frame because its reception requires the STA-ID)
694 Time delay = Seconds(0);
695 if (GetWifiPhy(linkId)->IsStateRx())
696 {
697 delay = GetWifiPhy(linkId)->GetDelayUntilIdle();
698 }
699 Simulator::Schedule(delay, &StaWifiMac::Disassociated, this, linkId);
700}
701
702void
704{
705 NS_LOG_FUNCTION(this << +linkId);
706
707 auto& link = GetLink(linkId);
708 if (link.apLinkId.has_value())
709 {
710 // this is a link setup in an ML setup
711 m_setupCanceled(linkId, GetBssid(linkId));
712 }
713
714 // disable the given link
715 link.apLinkId = std::nullopt;
716 link.bssid = std::nullopt;
717 link.phy->SetOffMode();
718
719 for (uint8_t id = 0; id < GetNLinks(); id++)
720 {
721 if (GetLink(id).apLinkId.has_value())
722 {
723 // found an enabled link
724 return;
725 }
726 }
727
728 NS_LOG_DEBUG("Set state to UNASSOCIATED and start scanning");
730 // cancel the association request timer (see issue #862)
732 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId));
733 if (GetNLinks() > 1 && mldAddress.has_value())
734 {
735 // trace the AP MLD address
736 m_deAssocLogger(*mldAddress);
737 }
738 else
739 {
740 m_deAssocLogger(GetBssid(linkId));
741 }
742 m_aid = 0; // reset AID
743 // ensure all links are on
744 for (uint8_t id = 0; id < GetNLinks(); id++)
745 {
747 }
749}
750
751void
753{
754 NS_LOG_FUNCTION(this << delay << +linkId);
755 auto& link = GetLink(linkId);
756 link.beaconWatchdogEnd = std::max(Simulator::Now() + delay, link.beaconWatchdogEnd);
757 if (Simulator::GetDelayLeft(link.beaconWatchdog) < delay && link.beaconWatchdog.IsExpired())
758 {
759 NS_LOG_DEBUG("really restart watchdog.");
760 link.beaconWatchdog = Simulator::Schedule(delay, &StaWifiMac::MissedBeacons, this, linkId);
761 }
762}
763
764bool
766{
767 return m_state == ASSOCIATED;
768}
769
770bool
772{
773 return m_state == WAIT_ASSOC_RESP;
774}
775
776std::set<uint8_t>
778{
779 if (!IsAssociated())
780 {
781 return {};
782 }
783
784 std::set<uint8_t> linkIds;
785 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
786 {
787 if (GetLink(linkId).bssid)
788 {
789 linkIds.insert(linkId);
790 }
791 }
792 return linkIds;
793}
794
795std::optional<uint8_t>
796StaWifiMac::GetApLinkId(uint8_t linkId) const
797{
798 return GetLink(linkId).apLinkId;
799}
800
803{
804 auto linkIds = GetSetupLinkIds();
805 NS_ASSERT_MSG(!linkIds.empty(), "Not associated");
806 uint8_t linkId = *linkIds.begin();
807 return GetFrameExchangeManager(linkId)->GetAddress();
808}
809
810bool
812{
813 return (IsAssociated());
814}
815
816void
818{
819 NS_LOG_FUNCTION(this << packet << to);
820 if (!CanForwardPacketsTo(to))
821 {
822 NotifyTxDrop(packet);
824 return;
825 }
826 WifiMacHeader hdr;
827
828 // If we are not a QoS AP then we definitely want to use AC_BE to
829 // transmit the packet. A TID of zero will map to AC_BE (through \c
830 // QosUtilsMapTidToAc()), so we use that as our default here.
831 uint8_t tid = 0;
832
833 // For now, an AP that supports QoS does not support non-QoS
834 // associations, and vice versa. In future the AP model should
835 // support simultaneously associated QoS and non-QoS STAs, at which
836 // point there will need to be per-association QoS state maintained
837 // by the association state machine, and consulted here.
838 if (GetQosSupported())
839 {
842 hdr.SetQosNoEosp();
843 hdr.SetQosNoAmsdu();
844 // Transmission of multiple frames in the same TXOP is not
845 // supported for now
846 hdr.SetQosTxopLimit(0);
847
848 // Fill in the QoS control field in the MAC header
849 tid = QosUtilsGetTidForPacket(packet);
850 // Any value greater than 7 is invalid and likely indicates that
851 // the packet had no QoS tag, so we revert to zero, which'll
852 // mean that AC_BE is used.
853 if (tid > 7)
854 {
855 tid = 0;
856 }
857 hdr.SetQosTid(tid);
858 }
859 else
860 {
862 }
863 if (GetQosSupported())
864 {
865 hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
866 // yet implemented (set it to 1 when implemented)
867 }
868
869 // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for
870 // non-broadcast data frames exchanged between two MLDs
871 auto linkIds = GetSetupLinkIds();
872 NS_ASSERT(!linkIds.empty());
873 uint8_t linkId = *linkIds.begin();
874 if (const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId)))
875 {
876 hdr.SetAddr1(*apMldAddr);
877 hdr.SetAddr2(GetAddress());
878 }
879 else
880 {
881 hdr.SetAddr1(GetBssid(linkId));
883 }
884
885 hdr.SetAddr3(to);
886 hdr.SetDsNotFrom();
887 hdr.SetDsTo();
888
889 if (GetQosSupported())
890 {
891 // Sanity check that the TID is valid
892 NS_ASSERT(tid < 8);
893 GetQosTxop(tid)->Queue(packet, hdr);
894 }
895 else
896 {
897 GetTxop()->Queue(packet, hdr);
898 }
899}
900
901void
903{
904 NS_LOG_FUNCTION(this << *mpdu << +linkId);
905 // consider the MAC header of the original MPDU (makes a difference for data frames only)
906 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
907 Ptr<const Packet> packet = mpdu->GetPacket();
908 NS_ASSERT(!hdr->IsCtl());
910 : GetFrameExchangeManager(linkId)->GetAddress();
911 if (hdr->GetAddr3() == myAddr)
912 {
913 NS_LOG_LOGIC("packet sent by us.");
914 return;
915 }
916 if (hdr->GetAddr1() != myAddr && !hdr->GetAddr1().IsGroup())
917 {
918 NS_LOG_LOGIC("packet is not for us");
919 NotifyRxDrop(packet);
920 return;
921 }
922 if (hdr->IsData())
923 {
924 if (!IsAssociated())
925 {
926 NS_LOG_LOGIC("Received data frame while not associated: ignore");
927 NotifyRxDrop(packet);
928 return;
929 }
930 if (!(hdr->IsFromDs() && !hdr->IsToDs()))
931 {
932 NS_LOG_LOGIC("Received data frame not from the DS: ignore");
933 NotifyRxDrop(packet);
934 return;
935 }
936 std::set<Mac48Address> apAddresses; // link addresses of AP
937 for (auto id : GetSetupLinkIds())
938 {
939 apAddresses.insert(GetBssid(id));
940 }
941 if (apAddresses.count(mpdu->GetHeader().GetAddr2()) == 0)
942 {
943 NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
944 NotifyRxDrop(packet);
945 return;
946 }
947 if (!hdr->HasData())
948 {
949 NS_LOG_LOGIC("Received (QoS) Null Data frame: ignore");
950 NotifyRxDrop(packet);
951 return;
952 }
953 if (hdr->IsQosData())
954 {
955 if (hdr->IsQosAmsdu())
956 {
957 NS_ASSERT(apAddresses.count(mpdu->GetHeader().GetAddr3()) != 0);
959 packet = nullptr;
960 }
961 else
962 {
963 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
964 }
965 }
966 else
967 {
968 ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
969 }
970 return;
971 }
972
973 switch (hdr->GetType())
974 {
978 // This is a frame aimed at an AP, so we can safely ignore it.
979 NotifyRxDrop(packet);
980 break;
981
983 ReceiveBeacon(mpdu, linkId);
984 break;
985
987 ReceiveProbeResp(mpdu, linkId);
988 break;
989
992 ReceiveAssocResp(mpdu, linkId);
993 break;
994
996 if (auto [category, action] = WifiActionHeader::Peek(packet);
998 action.protectedEhtAction ==
1000 {
1001 // this is handled by the EMLSR Manager
1002 break;
1003 }
1004
1005 default:
1006 // Invoke the receive handler of our parent class to deal with any
1007 // other frames. Specifically, this will handle Block Ack-related
1008 // Management Action frames.
1009 WifiMac::Receive(mpdu, linkId);
1010 }
1011
1012 if (m_emlsrManager)
1013 {
1014 m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
1015 }
1016}
1017
1018void
1020{
1021 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1022 const WifiMacHeader& hdr = mpdu->GetHeader();
1023 NS_ASSERT(hdr.IsBeacon());
1024
1025 NS_LOG_DEBUG("Beacon received");
1026 MgtBeaconHeader beacon;
1027 mpdu->GetPacket()->PeekHeader(beacon);
1028 const auto& capabilities = beacon.Capabilities();
1029 NS_ASSERT(capabilities.IsEss());
1030 bool goodBeacon;
1031 if (IsWaitAssocResp() || IsAssociated())
1032 {
1033 // we have to process this Beacon only if sent by the AP we are associated
1034 // with or from which we are waiting an Association Response frame
1035 auto bssid = GetLink(linkId).bssid;
1036 goodBeacon = bssid.has_value() && (hdr.GetAddr3() == *bssid);
1037 }
1038 else
1039 {
1040 // we retain this Beacon as candidate AP if the supported rates fit the
1041 // configured BSS membership selector
1042 goodBeacon = CheckSupportedRates(beacon, linkId);
1043 }
1044
1045 SnrTag snrTag;
1046 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1047 NS_ASSERT(found);
1048 ApInfo apInfo = {.m_bssid = hdr.GetAddr3(),
1049 .m_apAddr = hdr.GetAddr2(),
1050 .m_snr = snrTag.Get(),
1051 .m_frame = std::move(beacon),
1052 .m_channel = {GetCurrentChannel(linkId)},
1053 .m_linkId = linkId};
1054
1055 if (!m_beaconInfo.IsEmpty())
1056 {
1057 m_beaconInfo(apInfo);
1058 }
1059
1060 if (!goodBeacon)
1061 {
1062 NS_LOG_LOGIC("Beacon is not for us");
1063 return;
1064 }
1065 if (m_state == ASSOCIATED)
1066 {
1068 Time delay = MicroSeconds(std::get<MgtBeaconHeader>(apInfo.m_frame).GetBeaconIntervalUs() *
1070 RestartBeaconWatchdog(delay, linkId);
1071 UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1072 }
1073 else
1074 {
1075 NS_LOG_DEBUG("Beacon received from " << hdr.GetAddr2());
1076 m_assocManager->NotifyApInfo(std::move(apInfo));
1077 }
1078}
1079
1080void
1082{
1083 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1084 const WifiMacHeader& hdr = mpdu->GetHeader();
1085 NS_ASSERT(hdr.IsProbeResp());
1086
1087 NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2());
1088 MgtProbeResponseHeader probeResp;
1089 mpdu->GetPacket()->PeekHeader(probeResp);
1090 if (!CheckSupportedRates(probeResp, linkId))
1091 {
1092 return;
1093 }
1094 SnrTag snrTag;
1095 bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1096 NS_ASSERT(found);
1097 m_assocManager->NotifyApInfo(ApInfo{.m_bssid = hdr.GetAddr3(),
1098 .m_apAddr = hdr.GetAddr2(),
1099 .m_snr = snrTag.Get(),
1100 .m_frame = std::move(probeResp),
1101 .m_channel = {GetCurrentChannel(linkId)},
1102 .m_linkId = linkId});
1103}
1104
1105void
1107{
1108 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1109 const WifiMacHeader& hdr = mpdu->GetHeader();
1110 NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp());
1111
1112 if (m_state != WAIT_ASSOC_RESP)
1113 {
1114 return;
1115 }
1116
1117 std::optional<Mac48Address> apMldAddress;
1118 MgtAssocResponseHeader assocResp;
1119 mpdu->GetPacket()->PeekHeader(assocResp);
1121 {
1123 }
1124 if (assocResp.GetStatusCode().IsSuccess())
1125 {
1126 m_aid = assocResp.GetAssociationId();
1127 NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed"));
1128 UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1129 NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
1130 SetBssid(hdr.GetAddr3(), linkId);
1131 if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
1132 {
1133 // this is an ML setup, trace the setup link
1134 m_setupCompleted(linkId, hdr.GetAddr3());
1135 apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
1136 }
1137 else
1138 {
1139 m_assocLogger(hdr.GetAddr3());
1140 }
1142 if (!m_linkUp.IsNull())
1143 {
1144 m_linkUp();
1145 }
1146 }
1147
1148 // if this is an MLD, check if we can setup (other) links
1149 if (GetNLinks() > 1)
1150 {
1151 // create a list of all local Link IDs. IDs are removed as we find a corresponding
1152 // Per-STA Profile Subelements indicating successful association. Links with
1153 // remaining IDs are not setup
1154 std::list<uint8_t> setupLinks(GetNLinks());
1155 std::iota(setupLinks.begin(), setupLinks.end(), 0);
1156 if (assocResp.GetStatusCode().IsSuccess())
1157 {
1158 setupLinks.remove(linkId);
1159 }
1160
1161 // if a Multi-Link Element is present, check its content
1162 if (const auto& mle = assocResp.Get<MultiLinkElement>())
1163 {
1164 NS_ABORT_MSG_IF(!GetLink(linkId).apLinkId.has_value(),
1165 "The link on which the Association Response was received "
1166 "is not a link we requested to setup");
1167 NS_ABORT_MSG_IF(*GetLink(linkId).apLinkId != mle->GetLinkIdInfo(),
1168 "The link ID of the AP that transmitted the Association "
1169 "Response does not match the stored link ID");
1171 mle->GetMldMacAddress(),
1172 "The AP MLD MAC address in the received Multi-Link Element does not "
1173 "match the address stored in the station manager for link "
1174 << +linkId);
1175 // process the Per-STA Profile Subelements in the Multi-Link Element
1176 for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
1177 {
1178 auto& perStaProfile = mle->GetPerStaProfile(elem);
1179 uint8_t apLinkId = perStaProfile.GetLinkId();
1180 uint8_t staLinkid = 0;
1181 while (staLinkid < GetNLinks())
1182 {
1183 if (GetLink(staLinkid).apLinkId == apLinkId)
1184 {
1185 break;
1186 }
1187 staLinkid++;
1188 }
1189 std::optional<Mac48Address> bssid;
1190 NS_ABORT_MSG_IF(staLinkid == GetNLinks() ||
1191 !(bssid = GetLink(staLinkid).bssid).has_value(),
1192 "Setup for AP link ID " << apLinkId << " was not requested");
1193 NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
1194 "The BSSID in the Per-STA Profile for link ID "
1195 << +staLinkid << " does not match the stored BSSID");
1198 perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
1199 "The AP MLD MAC address in the received Multi-Link Element does not "
1200 "match the address stored in the station manager for link "
1201 << +staLinkid);
1202 // process the Association Response contained in this Per-STA Profile
1203 MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
1204 if (assoc.GetStatusCode().IsSuccess())
1205 {
1206 NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
1207 "AID should be the same for all the links");
1208 m_aid = assoc.GetAssociationId();
1209 NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
1210 UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
1211 SetBssid(*bssid, staLinkid);
1212 m_setupCompleted(staLinkid, *bssid);
1214 apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
1215 if (!m_linkUp.IsNull())
1216 {
1217 m_linkUp();
1218 }
1219 }
1220 // remove the ID of the link we setup
1221 setupLinks.remove(staLinkid);
1222 }
1223 }
1224 // remaining links in setupLinks are not setup and hence must be disabled
1225 for (const auto& id : setupLinks)
1226 {
1227 GetLink(id).apLinkId = std::nullopt;
1228 GetLink(id).bssid = std::nullopt;
1229 // if at least one link was setup, disable the links that were not setup (if any)
1230 if (m_state == ASSOCIATED)
1231 {
1232 GetLink(id).phy->SetOffMode();
1233 }
1234 }
1235 if (apMldAddress)
1236 {
1237 // this is an ML setup, trace the MLD address of the AP (only once)
1238 m_assocLogger(*apMldAddress);
1239 }
1240 }
1241
1242 if (m_state == WAIT_ASSOC_RESP)
1243 {
1244 // if we didn't transition to ASSOCIATED, the request was refused
1245 NS_LOG_DEBUG("association refused");
1247 StartScanning();
1248 return;
1249 }
1250
1252}
1253
1254void
1256{
1257 NS_LOG_FUNCTION(this << linkId);
1258
1259 // STAs operating on setup links may need to transition to a new PM mode after the
1260 // acknowledgement of the Association Response. For this purpose, we connect a callback to
1261 // the PHY TX begin trace to catch the Ack transmitted after the Association Response.
1263 [=](WifiConstPsduMap psduMap, WifiTxVector txVector, double /* txPowerW */) {
1264 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
1265 psduMap.begin()->second->GetHeader(0).IsAck(),
1266 "Expected a Normal Ack after Association Response frame");
1267
1268 auto ackDuration =
1269 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
1270
1271 for (uint8_t id = 0; id < GetNLinks(); id++)
1272 {
1273 auto& link = GetLink(id);
1274
1275 if (!link.bssid)
1276 {
1277 // link has not been setup
1278 continue;
1279 }
1280
1281 if (id == linkId)
1282 {
1291 // if the user requested this link to be in powersave mode, we have to
1292 // switch PM mode
1293 if (link.pmMode == WIFI_PM_POWERSAVE)
1294 {
1295 Simulator::Schedule(ackDuration,
1297 this,
1298 std::pair<bool, uint8_t>{true, id});
1299 }
1300 link.pmMode = WIFI_PM_ACTIVE;
1301 }
1302 else
1303 {
1312 // if the user requested this link to be in active mode, we have to
1313 // switch PM mode
1314 if (link.pmMode == WIFI_PM_ACTIVE)
1315 {
1316 Simulator::Schedule(ackDuration,
1318 this,
1319 std::pair<bool, uint8_t>{false, id});
1320 }
1321 link.pmMode = WIFI_PM_POWERSAVE;
1322 }
1323 }
1324 });
1325
1326 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
1327 // after its transmission begins
1328 auto phy = GetLink(linkId).phy;
1329 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
1330 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
1331 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
1332}
1333
1334bool
1335StaWifiMac::CheckSupportedRates(std::variant<MgtBeaconHeader, MgtProbeResponseHeader> frame,
1336 uint8_t linkId)
1337{
1338 NS_LOG_FUNCTION(this << +linkId);
1339
1340 // lambda to invoke on the current frame variant
1341 auto check = [&](auto&& mgtFrame) -> bool {
1342 // check supported rates
1343 NS_ASSERT(mgtFrame.template Get<SupportedRates>());
1344 const auto rates = AllSupportedRates{*mgtFrame.template Get<SupportedRates>(),
1345 mgtFrame.template Get<ExtendedSupportedRatesIE>()};
1346 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1347 {
1348 if (!rates.IsBssMembershipSelectorRate(selector))
1349 {
1350 NS_LOG_DEBUG("Supported rates do not fit with the BSS membership selector");
1351 return false;
1352 }
1353 }
1354
1355 return true;
1356 };
1357
1358 return std::visit(check, frame);
1359}
1360
1361void
1363 const Mac48Address& apAddr,
1364 const Mac48Address& bssid,
1365 uint8_t linkId)
1366{
1367 NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId);
1368
1369 // ERP Information is not present in Association Response frames
1370 const std::optional<ErpInformation>* erpInformation = nullptr;
1371
1372 if (const auto* beacon = std::get_if<MgtBeaconHeader>(&frame))
1373 {
1374 erpInformation = &beacon->Get<ErpInformation>();
1375 }
1376 else if (const auto* probe = std::get_if<MgtProbeResponseHeader>(&frame))
1377 {
1378 erpInformation = &probe->Get<ErpInformation>();
1379 }
1380
1381 // lambda processing Information Elements included in all frame types
1382 auto commonOps = [&](auto&& frame) {
1383 const auto& capabilities = frame.Capabilities();
1384 NS_ASSERT(frame.template Get<SupportedRates>());
1385 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1386 frame.template Get<ExtendedSupportedRatesIE>()};
1387 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1388 {
1389 if (rates.IsSupportedRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1390 {
1391 GetWifiRemoteStationManager(linkId)->AddSupportedMode(apAddr, mode);
1392 if (rates.IsBasicRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1393 {
1395 }
1396 }
1397 }
1398
1399 bool isShortPreambleEnabled = capabilities.IsShortPreamble();
1400 if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId))
1401 {
1402 isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode();
1403 if ((*erpInformation)->GetUseProtection() != 0)
1404 {
1406 }
1407 else
1408 {
1410 }
1411 if (capabilities.IsShortSlotTime() == true)
1412 {
1413 // enable short slot time
1414 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1415 }
1416 else
1417 {
1418 // disable short slot time
1419 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1420 }
1421 }
1422 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled);
1424 capabilities.IsShortSlotTime());
1425
1426 if (!GetQosSupported())
1427 {
1428 return;
1429 }
1430 /* QoS station */
1431 bool qosSupported = false;
1432 const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
1433 if (edcaParameters.has_value())
1434 {
1435 qosSupported = true;
1436 // The value of the TXOP Limit field is specified as an unsigned integer, with the least
1437 // significant octet transmitted first, in units of 32 μs.
1439 edcaParameters->GetBeCWmin(),
1440 edcaParameters->GetBeCWmax(),
1441 edcaParameters->GetBeAifsn(),
1442 32 * MicroSeconds(edcaParameters->GetBeTxopLimit())},
1443 linkId);
1445 edcaParameters->GetBkCWmin(),
1446 edcaParameters->GetBkCWmax(),
1447 edcaParameters->GetBkAifsn(),
1448 32 * MicroSeconds(edcaParameters->GetBkTxopLimit())},
1449 linkId);
1451 edcaParameters->GetViCWmin(),
1452 edcaParameters->GetViCWmax(),
1453 edcaParameters->GetViAifsn(),
1454 32 * MicroSeconds(edcaParameters->GetViTxopLimit())},
1455 linkId);
1457 edcaParameters->GetVoCWmin(),
1458 edcaParameters->GetVoCWmax(),
1459 edcaParameters->GetVoAifsn(),
1460 32 * MicroSeconds(edcaParameters->GetVoTxopLimit())},
1461 linkId);
1462 }
1463 GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
1464
1465 if (!GetHtSupported())
1466 {
1467 return;
1468 }
1469 /* HT station */
1470 if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
1471 htCapabilities.has_value())
1472 {
1473 if (!htCapabilities->IsSupportedMcs(0))
1474 {
1476 }
1477 else
1478 {
1480 *htCapabilities);
1481 }
1482 }
1483 // TODO: process ExtendedCapabilities
1484 // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
1485
1486 // we do not return if VHT is not supported because HE STAs operating in
1487 // the 2.4 GHz band do not support VHT
1488 if (GetVhtSupported(linkId))
1489 {
1490 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1491 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1492 // to check whether it supports VHT
1493 if (vhtCapabilities.has_value() &&
1494 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1495 {
1497 *vhtCapabilities);
1498 // const auto& vhtOperation = frame.GetVhtOperation ();
1499 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_VHT))
1500 {
1501 if (vhtCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1502 {
1503 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1504 }
1505 }
1506 }
1507 }
1508
1509 if (!GetHeSupported())
1510 {
1511 return;
1512 }
1513 /* HE station */
1514 const auto& heCapabilities = frame.template Get<HeCapabilities>();
1515 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1516 {
1517 GetWifiRemoteStationManager(linkId)->AddStationHeCapabilities(apAddr, *heCapabilities);
1518 for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_HE))
1519 {
1520 if (heCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1521 {
1522 GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1523 }
1524 }
1525 if (const auto& heOperation = frame.template Get<HeOperation>();
1526 heOperation.has_value())
1527 {
1528 GetHeConfiguration()->SetAttribute("BssColor",
1529 UintegerValue(heOperation->GetBssColor()));
1530 }
1531 }
1532
1533 const auto& muEdcaParameters = frame.template Get<MuEdcaParameterSet>();
1534 if (muEdcaParameters.has_value())
1535 {
1537 muEdcaParameters->GetMuCwMin(AC_BE),
1538 muEdcaParameters->GetMuCwMax(AC_BE),
1539 muEdcaParameters->GetMuAifsn(AC_BE),
1540 muEdcaParameters->GetMuEdcaTimer(AC_BE)},
1541 linkId);
1543 muEdcaParameters->GetMuCwMin(AC_BK),
1544 muEdcaParameters->GetMuCwMax(AC_BK),
1545 muEdcaParameters->GetMuAifsn(AC_BK),
1546 muEdcaParameters->GetMuEdcaTimer(AC_BK)},
1547 linkId);
1549 muEdcaParameters->GetMuCwMin(AC_VI),
1550 muEdcaParameters->GetMuCwMax(AC_VI),
1551 muEdcaParameters->GetMuAifsn(AC_VI),
1552 muEdcaParameters->GetMuEdcaTimer(AC_VI)},
1553 linkId);
1555 muEdcaParameters->GetMuCwMin(AC_VO),
1556 muEdcaParameters->GetMuCwMax(AC_VO),
1557 muEdcaParameters->GetMuAifsn(AC_VO),
1558 muEdcaParameters->GetMuEdcaTimer(AC_VO)},
1559 linkId);
1560 }
1561
1562 if (!GetEhtSupported())
1563 {
1564 return;
1565 }
1566 /* EHT station */
1567 const auto& ehtCapabilities = frame.template Get<EhtCapabilities>();
1568 // TODO: once we support non constant rate managers, we should add checks here whether EHT
1569 // is supported by the peer
1570 GetWifiRemoteStationManager(linkId)->AddStationEhtCapabilities(apAddr, *ehtCapabilities);
1571
1572 if (const auto& mle = frame.template Get<MultiLinkElement>();
1573 mle && mle->HasEmlCapabilities() && m_emlsrManager)
1574 {
1575 m_emlsrManager->SetTransitionTimeout(mle->GetTransitionTimeout());
1576 }
1577 };
1578
1579 // process Information Elements included in the current frame variant
1580 std::visit(commonOps, frame);
1581}
1582
1583void
1584StaWifiMac::SetPowerSaveMode(const std::pair<bool, uint8_t>& enableLinkIdPair)
1585{
1586 const auto [enable, linkId] = enableLinkIdPair;
1587 NS_LOG_FUNCTION(this << enable << linkId);
1588
1589 auto& link = GetLink(linkId);
1590
1591 if (!IsAssociated())
1592 {
1593 NS_LOG_DEBUG("Not associated yet, record the PM mode to switch to upon association");
1594 link.pmMode = enable ? WIFI_PM_POWERSAVE : WIFI_PM_ACTIVE;
1595 return;
1596 }
1597
1598 if (!link.bssid)
1599 {
1600 NS_LOG_DEBUG("Link " << +linkId << " has not been setup, ignore request");
1601 return;
1602 }
1603
1604 if ((enable && link.pmMode == WIFI_PM_POWERSAVE) || (!enable && link.pmMode == WIFI_PM_ACTIVE))
1605 {
1606 NS_LOG_DEBUG("No PM mode change needed");
1607 return;
1608 }
1609
1611
1612 // reschedule a call to this function to make sure that the PM mode switch
1613 // is eventually completed
1616 this,
1617 enableLinkIdPair);
1618
1619 if (HasFramesToTransmit(linkId))
1620 {
1621 NS_LOG_DEBUG("Next transmitted frame will be sent with PM=" << enable);
1622 return;
1623 }
1624
1625 // No queued frames. Enqueue a Data Null frame to inform the AP of the PM mode change
1627
1628 hdr.SetAddr1(GetBssid(linkId));
1630 hdr.SetAddr3(GetBssid(linkId));
1631 hdr.SetDsNotFrom();
1632 hdr.SetDsTo();
1633 enable ? hdr.SetPowerManagement() : hdr.SetNoPowerManagement();
1634 if (GetQosSupported())
1635 {
1636 GetQosTxop(AC_BE)->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1637 }
1638 else
1639 {
1640 m_txop->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1641 }
1642}
1643
1645StaWifiMac::GetPmMode(uint8_t linkId) const
1646{
1647 return GetLink(linkId).pmMode;
1648}
1649
1650void
1652{
1653 NS_LOG_FUNCTION(this << *mpdu);
1654
1655 auto linkId = GetLinkIdByAddress(mpdu->GetHeader().GetAddr2());
1656
1657 if (!linkId)
1658 {
1659 // the given MPDU may be the original copy containing MLD addresses and not carrying
1660 // a valid PM bit (which is set on the aliases).
1661 auto linkIds = mpdu->GetInFlightLinkIds();
1662 NS_ASSERT_MSG(!linkIds.empty(),
1663 "The TA of the acked MPDU (" << *mpdu
1664 << ") is not a link "
1665 "address and the MPDU is not inflight");
1666 // in case the ack'ed MPDU is inflight on multiple links, we cannot really know if
1667 // it was received by the AP on all links or only on some links. Hence, we only
1668 // consider the first link ID in the set, given that in the most common case of MPDUs
1669 // that cannot be sent concurrently on multiple links, there will be only one link ID
1670 linkId = *linkIds.begin();
1671 mpdu = GetTxopQueue(mpdu->GetQueueAc())->GetAlias(mpdu, *linkId);
1672 }
1673
1674 auto& link = GetLink(*linkId);
1675 const WifiMacHeader& hdr = mpdu->GetHeader();
1676
1677 // we received an acknowledgment while switching PM mode; the PM mode change is effective now
1678 if (hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_PS)
1679 {
1680 link.pmMode = WIFI_PM_POWERSAVE;
1681 }
1682 else if (!hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_ACTIVE)
1683 {
1684 link.pmMode = WIFI_PM_ACTIVE;
1685 }
1686}
1687
1690{
1691 AllSupportedRates rates;
1692 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1693 {
1694 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
1695 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
1696 rates.AddSupportedRate(modeDataRate);
1697 }
1698 if (GetHtSupported())
1699 {
1700 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1701 {
1702 rates.AddBssMembershipSelectorRate(selector);
1703 }
1704 }
1705 return rates;
1706}
1707
1709StaWifiMac::GetCapabilities(uint8_t linkId) const
1710{
1711 CapabilityInformation capabilities;
1712 capabilities.SetShortPreamble(GetWifiPhy(linkId)->GetShortPhyPreambleSupported() ||
1713 GetErpSupported(linkId));
1715 return capabilities;
1716}
1717
1718void
1720{
1721 m_state = value;
1722}
1723
1724void
1725StaWifiMac::SetEdcaParameters(const EdcaParams& params, uint8_t linkId)
1726{
1727 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1728 edca->SetMinCw(params.cwMin, linkId);
1729 edca->SetMaxCw(params.cwMax, linkId);
1730 edca->SetAifsn(params.aifsn, linkId);
1731 edca->SetTxopLimit(params.txopLimit, linkId);
1732}
1733
1734void
1735StaWifiMac::SetMuEdcaParameters(const MuEdcaParams& params, uint8_t linkId)
1736{
1737 Ptr<QosTxop> edca = GetQosTxop(params.ac);
1738 edca->SetMuCwMin(params.cwMin, linkId);
1739 edca->SetMuCwMax(params.cwMax, linkId);
1740 edca->SetMuAifsn(params.aifsn, linkId);
1741 edca->SetMuEdcaTimer(params.muEdcaTimer, linkId);
1742}
1743
1744void
1746{
1747 NS_LOG_FUNCTION(this);
1748 if (IsAssociated())
1749 {
1750 NS_LOG_DEBUG("PHY capabilities changed: send reassociation request");
1753 }
1754}
1755
1756void
1758{
1759 NS_LOG_FUNCTION(this << +linkId);
1760
1762
1763 if (IsInitialized() && IsAssociated())
1764 {
1765 Disassociated(linkId);
1766 }
1767
1768 // notify association manager
1769 m_assocManager->NotifyChannelSwitched(linkId);
1770}
1771
1772std::ostream&
1773operator<<(std::ostream& os, const StaWifiMac::ApInfo& apInfo)
1774{
1775 os << "BSSID=" << apInfo.m_bssid << ", AP addr=" << apInfo.m_apAddr << ", SNR=" << apInfo.m_snr
1776 << ", Channel={" << apInfo.m_channel.number << "," << apInfo.m_channel.band
1777 << "}, Link ID=" << +apInfo.m_linkId << ", Frame=[";
1778 std::visit([&os](auto&& frame) { frame.Print(os); }, apInfo.m_frame);
1779 os << "]";
1780 return os;
1781}
1782
1783} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Base class for Callback class.
Definition: callback.h:360
Callback template class.
Definition: callback.h:438
bool IsNull() const
Check for null implementation.
Definition: callback.h:567
void SetShortSlotTime(bool shortSlotTime)
Set the short slot time bit in the capability information field.
void SetShortPreamble(bool shortPreamble)
Set the short preamble bit in the capability information field.
The IEEE 802.11be EHT Capabilities.
The ErpInformation Information Element.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
The IEEE 802.11ax HE Capabilities.
The HT Capabilities Information Element.
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address GetBroadcast()
Implement the header for management frames of type association request.
Definition: mgt-headers.h:161
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:338
StatusCode GetStatusCode()
Return the status code.
Definition: mgt-headers.cc:457
uint16_t GetAssociationId() const
Return the association ID.
Definition: mgt-headers.cc:487
Implement the header for management frames of type beacon.
Definition: mgt-headers.h:516
Implement the header for management frames of type probe request.
Definition: mgt-headers.h:436
Implement the header for management frames of type probe response.
Definition: mgt-headers.h:455
CapabilityInformation & Capabilities()
Definition: mgt-headers.cc:94
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:245
void SetCurrentApAddress(Mac48Address currentApAddr)
Set the address of the current access point.
Definition: mgt-headers.cc:332
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:311
bool IsInitialized() const
Check if the object has been initialized.
Definition: object.cc:212
Hold objects of type std::pair<A, B>.
Definition: pair.h:56
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:208
Introspection did not find any typical Config paths.
Definition: snr-tag.h:35
double Get() const
Return the SNR value.
Definition: snr-tag.cc:90
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
The Wifi MAC high model for a non-AP STA in a BSS.
Definition: sta-wifi-mac.h: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:573
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:571
void MissedBeacons(uint8_t linkId)
This method is called after we have not received a beacon from the AP on the given link.
bool m_activeProbing
active probing
Definition: sta-wifi-mac.h:578
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.
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:585
MacState
The current MAC state of the STA.
Definition: sta-wifi-mac.h:340
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.
void PhyCapabilitiesChanged()
Indicate that PHY capabilities have changed.
void ReceiveProbeResp(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Probe Response frame received on the given link.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
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 RestartBeaconWatchdog(Time delay, uint8_t linkId)
Restarts the beacon timer for the given 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:56
void DoDispose() override
Destructor implementation.
void SendProbeRequest(uint8_t linkId)
Enqueue a probe request packet for transmission on the given link.
StaLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
uint32_t m_maxMissedBeacons
maximum missed beacons
Definition: sta-wifi-mac.h:577
TracedCallback< uint8_t, Mac48Address > m_setupCompleted
link setup completed logger
Definition: sta-wifi-mac.h:584
std::optional< uint8_t > GetApLinkId(uint8_t linkId) const
TracedCallback< Mac48Address > m_assocLogger
association logger
Definition: sta-wifi-mac.h:583
void SetWifiPhys(const std::vector< Ptr< WifiPhy > > &phys) override
void SetMuEdcaParameters(const MuEdcaParams &params, uint8_t linkId)
Set the MU EDCA parameters for the given link.
void Disassociated(uint8_t linkId)
Check if any enabled link remains after the given link is disabled (because, e.g.,...
TracedCallback< uint8_t, Mac48Address > m_setupCanceled
link setup canceled logger
Definition: sta-wifi-mac.h:586
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 SetEmlsrManager(Ptr< EmlsrManager > emlsrManager)
Set the EMLSR Manager.
Time m_pmModeSwitchTimeout
PM mode switch timeout.
Definition: sta-wifi-mac.h:581
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...
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:579
TracedCallback< ApInfo > m_beaconInfo
beacon info logger
Definition: sta-wifi-mac.h:588
uint16_t m_aid
Association AID.
Definition: sta-wifi-mac.h:570
MacState m_state
MAC state.
Definition: sta-wifi-mac.h:569
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.
TracedCallback< Time > m_beaconArrival
beacon arrival logger
Definition: sta-wifi-mac.h:587
void AssocRequestTimeout()
This method is called after the association timeout occurred.
Ptr< EmlsrManager > m_emlsrManager
EMLSR Manager.
Definition: sta-wifi-mac.h:572
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:575
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:574
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:157
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:576
void SendAssociationRequest(bool isReassoc)
Forward an association or reassociation request packet to the DCF.
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
AttributeValue implementation for Time.
Definition: nstime.h:1423
Time Get() const
Definition: time.cc:532
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:501
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:936
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.
@ PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION
Definition: mgt-headers.h:714
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.
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.
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:94
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:864
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition: wifi-mac.cc:531
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition: wifi-mac.cc:580
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1358
Mac48Address GetBssid(uint8_t linkId) const
Definition: wifi-mac.cc:476
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1475
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition: wifi-mac.cc:491
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition: wifi-mac.cc:1712
Callback< void > m_linkDown
Callback when a link is down.
Definition: wifi-mac.h:790
bool GetQosSupported() const
Return whether the device supports QoS.
Definition: wifi-mac.cc:1030
Ptr< Txop > m_txop
TXOP used for transmission of frames to non-QoS peers.
Definition: wifi-mac.h:786
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:930
void DoInitialize() override
Initialize() implementation.
Definition: wifi-mac.cc:352
Ssid GetSsid() const
Definition: wifi-mac.cc:463
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition: wifi-mac.cc:1036
bool GetHtSupported() const
Return whether the device supports HT.
Definition: wifi-mac.cc:1487
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition: wifi-mac.cc:519
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition: wifi-mac.cc:418
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:978
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition: wifi-mac.cc:1506
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1500
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition: wifi-mac.cc:1655
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:936
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the MAC has frames to transmit over the given link.
Definition: wifi-mac.cc:550
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition: wifi-mac.cc:1493
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:1346
void SetBssid(Mac48Address bssid, uint8_t linkId)
Definition: wifi-mac.cc:469
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:437
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition: wifi-mac.cc:1644
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:543
bool GetShortSlotTimeSupported() const
Definition: wifi-mac.cc:1080
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:619
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:910
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition: wifi-mac.cc:1216
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:1223
Mac48Address GetAddress() const
Definition: wifi-mac.cc:450
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition: wifi-mac.cc:1849
Callback< void > m_linkUp
Callback when a link is up.
Definition: wifi-mac.h:789
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: wifi-mac.cc:922
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition: wifi-mac.cc:1793
virtual void SetWifiPhys(const std::vector< Ptr< WifiPhy > > &phys)
Definition: wifi-mac.cc:949
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:497
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:601
void DoDispose() override
Destructor implementation.
Definition: wifi-mac.cc:376
Time GetDelayUntilIdle()
Definition: wifi-phy.cc:2045
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1496
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition: wifi-phy.cc:789
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1005
void SetOffMode()
Put in off mode.
Definition: wifi-phy.cc:1366
bool HasFixedPhyBand() const
Definition: wifi-phy.cc:1053
void ResumeFromOff()
Resume from off mode.
Definition: wifi-phy.cc:1409
void SetShortSlotTimeEnabled(bool enable)
Enable or disable short slot time.
void AddBasicMode(WifiMode mode)
Invoked in a STA upon association to store the set of rates which belong to the BSSBasicRateSet of th...
void SetUseNonErpProtection(bool enable)
Enable or disable protection for non-ERP stations.
std::optional< Mac48Address > GetAffiliatedStaAddress(const Mac48Address &mldAddress) const
Get the address of the remote station operating on this link and affiliated with the MLD having the g...
void AddSupportedMcs(Mac48Address address, WifiMode mcs)
Record the MCS index supported by the station.
void RemoveAllSupportedMcs(Mac48Address address)
Invoked in a STA or AP to delete all of the supported MCS by a destination.
void AddStationVhtCapabilities(Mac48Address from, VhtCapabilities vhtCapabilities)
Records VHT capabilities of the remote station.
void SetShortPreambleEnabled(bool enable)
Enable or disable short PHY preambles.
void SetQosSupport(Mac48Address from, bool qosSupported)
Records QoS support of the remote station.
void AddStationHeCapabilities(Mac48Address from, HeCapabilities heCapabilities)
Records HE capabilities of the remote station.
void AddSupportedMode(Mac48Address address, WifiMode mode)
Invoked in a STA or AP to store the set of modes supported by a destination which is also supported l...
void AddStationEhtCapabilities(Mac48Address from, EhtCapabilities ehtCapabilities)
Records EHT capabilities of the remote station.
void AddStationHtCapabilities(Mac48Address from, HtCapabilities htCapabilities)
Records HT capabilities of the remote station.
std::optional< Mac48Address > GetMldAddress(const Mac48Address &address) const
Get the address of the MLD the given station is affiliated with, if any.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:227
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1444
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1424
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
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
@ STA
Definition: wifi-mac.h:63
@ 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:74
@ AC_VO
Voice.
Definition: qos-utils.h:80
@ AC_VI
Video.
Definition: qos-utils.h:78
@ AC_BK
Background.
Definition: qos-utils.h:76
-style-clang-format
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:702
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:129
@ 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
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.
Struct to hold information regarding observed AP through active/passive scanning.
Definition: sta-wifi-mac.h:164
MgtFrameType m_frame
The body of the management frame used to update AP info.
Definition: sta-wifi-mac.h:168
WifiScanParams::Channel m_channel
The channel the management frame was received on.
Definition: sta-wifi-mac.h:169
Mac48Address m_apAddr
AP MAC address.
Definition: sta-wifi-mac.h:166
uint8_t m_linkId
ID of the link used to communicate with the AP.
Definition: sta-wifi-mac.h:170
Mac48Address m_bssid
BSSID.
Definition: sta-wifi-mac.h:165
double m_snr
SNR in linear scale.
Definition: sta-wifi-mac.h:167
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