A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ap-wifi-mac.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006, 2009 INRIA
3 * Copyright (c) 2009 MIRKO BANCHI
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
8 * Mirko Banchi <mk.banchi@gmail.com>
9 */
10
11#include "ap-wifi-mac.h"
12
15#include "gcr-manager.h"
16#include "mac-rx-middle.h"
17#include "mac-tx-middle.h"
18#include "mgt-action-headers.h"
19#include "msdu-aggregator.h"
20#include "qos-txop.h"
23#include "wifi-mac-queue.h"
24#include "wifi-net-device.h"
25#include "wifi-ns3-constants.h"
26#include "wifi-phy.h"
27
28#include "ns3/ap-emlsr-manager.h"
29#include "ns3/eht-configuration.h"
30#include "ns3/eht-frame-exchange-manager.h"
31#include "ns3/he-configuration.h"
32#include "ns3/ht-configuration.h"
33#include "ns3/log.h"
34#include "ns3/packet.h"
35#include "ns3/pointer.h"
36#include "ns3/random-variable-stream.h"
37#include "ns3/simulator.h"
38#include "ns3/string.h"
39#include "ns3/uinteger.h"
40
41#include <algorithm>
42
43namespace ns3
44{
45
46NS_LOG_COMPONENT_DEFINE("ApWifiMac");
47
49
52{
53 static TypeId tid =
54 TypeId("ns3::ApWifiMac")
56 .SetGroupName("Wifi")
57 .AddConstructor<ApWifiMac>()
58 .AddAttribute(
59 "BeaconInterval",
60 "Delay between two beacons",
64 .AddAttribute("BeaconJitter",
65 "A random variable to cause the initial beacon starting time (after "
66 "simulation time 0) to be distributed between 0 and the BeaconInterval. "
67 "Generated values must be between 0 and 1.",
68 StringValue("ns3::UniformRandomVariable"),
71 .AddAttribute("EnableBeaconJitter",
72 "If beacons are enabled, whether to jitter the initial send event.",
73 BooleanValue(true),
76 .AddAttribute("BeaconDtimPeriod",
77 "The DTIM Period, in number of beacons",
81 .AddAttribute("BeaconGeneration",
82 "Whether or not beacons are generated.",
83 BooleanValue(true),
86 .AddAttribute("FdBeaconInterval6GHz",
87 "Time between a Beacon frame and a FILS Discovery (FD) frame or between "
88 "two FD frames to be sent on a 6GHz link. A value of zero disables the "
89 "transmission of FD frames.",
90 TimeValue(Time{0}),
93 .AddAttribute("FdBeaconIntervalNon6GHz",
94 "Time between a Beacon frame and a FILS Discovery (FD) frame or between "
95 "two FD frames to be sent on a non-6GHz link. A value of zero disables "
96 "the transmission of FD frames.",
97 TimeValue(Time{0}),
100 .AddAttribute("SendUnsolProbeResp",
101 "Send unsolicited broadcast Probe Response instead of FILS Discovery",
102 BooleanValue(false),
105 .AddAttribute("EnableNonErpProtection",
106 "Whether or not protection mechanism should be used when non-ERP STAs "
107 "are present within the BSS."
108 "This parameter is only used when ERP is supported by the AP.",
109 BooleanValue(true),
112 .AddAttribute("BsrLifetime",
113 "Lifetime of Buffer Status Reports received from stations.",
117 .AddAttribute(
118 "CwMinsForSta",
119 "The CW min values that the AP advertises in EDCA Parameter Set elements and the "
120 "associated stations will use. The value of this attribute is an AC-indexed map "
121 "containing the CW min values for given ACs for all the links (sorted in "
122 "increasing order of link ID). If no values are provided for an AC, the same "
123 "values used by the AP are advertised. In case a string is used to set this "
124 "attribute, the string shall contain the pairs separated by a semicolon (;); "
125 "in every pair, the AC index and the list of values are separated by a blank "
126 "space, and the values of a list are separated by a comma (,) without spaces. "
127 "E.g. \"BE 31,31,31; VI 15,15,15\" defines the CW min values for AC BE and AC VI "
128 "for an AP MLD having three links.",
129 StringValue(""),
133 .AddAttribute(
134 "CwMaxsForSta",
135 "The CW max values that the AP advertises in EDCA Parameter Set elements and the "
136 "associated stations will use. The value of this attribute is an AC-indexed map "
137 "containing the CW max values for given ACs for all the links (sorted in "
138 "increasing order of link ID). If no values are provided for an AC, the same "
139 "values used by the AP are advertised. In case a string is used to set this "
140 "attribute, the string shall contain the pairs separated by a semicolon (;); "
141 "in every pair, the AC index and the list of values are separated by a blank "
142 "space, and the values of a list are separated by a comma (,) without spaces. "
143 "E.g. \"BE 31,31,31; VI 15,15,15\" defines the CW max values for AC BE and AC VI "
144 "for an AP MLD having three links.",
145 StringValue(""),
149 .AddAttribute(
150 "AifsnsForSta",
151 "The AIFSN values that the AP advertises in EDCA Parameter Set elements and the "
152 "associated stations will use. The value of this attribute is an AC-indexed map "
153 "containing the AIFSN values for given ACs for all the links (sorted in "
154 "increasing order of link ID). If no values are provided for an AC, the same "
155 "values used by the AP are advertised. In case a string is used to set this "
156 "attribute, the string shall contain the pairs separated by a semicolon (;); "
157 "in every pair, the AC index and the list of values are separated by a blank "
158 "space, and the values of a list are separated by a comma (,) without spaces. "
159 "E.g. \"BE 3,3,3; VI 2,2,2\" defines the AIFSN values for AC BE and AC VI "
160 "for an AP MLD having three links.",
161 StringValue(""),
165 .AddAttribute(
166 "TxopLimitsForSta",
167 "The TXOP limit values that the AP advertises in EDCA Parameter Set elements and "
168 "the associated stations will use. The value of this attribute is an AC-indexed "
169 "map containing the TXOP limit values for given ACs for all the links (sorted in "
170 "increasing order of link ID). If no values are provided for an AC, the same "
171 "values used by the AP are advertised. In case a string is used to set this "
172 "attribute, the string shall contain the pairs separated by a semicolon (;); "
173 "in every pair, the AC index and the list of values are separated by a blank "
174 "space, and the values of a list are separated by a comma (,) without spaces. "
175 "E.g. \"BE 3200us,3200us,3200us; VI 2400us,2400us,2400us\" defines the TXOP limit "
176 "values for AC BE and AC VI for an AP MLD having three links.",
177 StringValue(""),
181 .AddAttribute("GcrManager",
182 "The GCR manager object.",
184 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
185 PointerValue(),
188 .AddTraceSource("AssociatedSta",
189 "A station associated with this access point.",
191 "ns3::ApWifiMac::AssociationCallback")
192 .AddTraceSource("DeAssociatedSta",
193 "A station lost association with this access point.",
195 "ns3::ApWifiMac::AssociationCallback");
196 return tid;
197}
198
199template <class T>
210
219
223{
224 NS_LOG_FUNCTION(this);
226 m_beaconTxop->SetTxMiddle(m_txMiddle);
227
228 // Let the lower layers know that we are acting as an AP.
230}
231
236
237void
239{
240 NS_LOG_FUNCTION(this);
241 m_beaconTxop->Dispose();
242 m_beaconTxop = nullptr;
245 {
246 m_apEmlsrManager->Dispose();
247 }
248 m_apEmlsrManager = nullptr;
249 if (m_gcrManager)
250 {
251 m_gcrManager->Dispose();
252 }
253 m_gcrManager = nullptr;
255}
256
262
263std::unique_ptr<WifiMac::LinkEntity>
265{
266 return std::make_unique<ApLinkEntity>();
267}
268
270ApWifiMac::GetLink(uint8_t linkId) const
271{
272 return static_cast<ApLinkEntity&>(WifiMac::GetLink(linkId));
273}
274
275void
277{
278 NS_LOG_FUNCTION(this << apEmlsrManager);
279 m_apEmlsrManager = apEmlsrManager;
280 m_apEmlsrManager->SetWifiMac(this);
281}
282
285{
286 return m_apEmlsrManager;
287}
288
289void
291{
292 NS_LOG_FUNCTION(this << gcrManager);
293 m_gcrManager = gcrManager;
294 m_gcrManager->SetWifiMac(this);
295}
296
299{
300 return m_gcrManager;
301}
302
303bool
305{
306 if (!hdr.IsQosData())
307 {
308 return false;
309 }
310
311 if (!IsGroupcast(hdr.GetAddr1()))
312 {
313 return false;
314 }
315
316 if (!m_gcrManager)
317 {
318 return false;
319 }
320
321 if (m_gcrManager->GetRetransmissionPolicy() ==
323 {
324 return false;
325 }
326
327 /*
328 * 802.11-2020 11.21.16.3.4 (GCR operation):
329 * An AP or mesh STA shall transmit a frame belonging to a group address
330 * via the GCR service if any associated STA or peer mesh STA has a GCR
331 * agreement for the group address and, otherwise, does not transmit the
332 * frame via the GCR service.
333 */
334 if (m_gcrManager->GetMemberStasForGroupAddress(hdr.GetAddr1()).empty())
335 {
336 return false;
337 }
338
339 return true;
340}
341
342void
344{
345 NS_LOG_FUNCTION(this);
346 m_beaconTxop->SetWifiMac(this);
347 // DCF behavior may be edited here; the default is PIFS access with zero backoff
348 m_beaconTxop->SetAifsns(std::vector<uint8_t>(GetNLinks(), 1));
349 m_beaconTxop->SetMinCws(std::vector<uint32_t>(GetNLinks(), 0));
350 m_beaconTxop->SetMaxCws(std::vector<uint32_t>(GetNLinks(), 0));
351 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
352 {
354 }
355
356 // the value 'exp' for the Group Addressed BU Indication Exponent must be such that 2^(exp+1)-1
357 // is at least equal to N-1, where N is the number of links (Sec. 35.3.15.1 of 802.11be D7.0).
358 // The max value for Group Addressed BU Indication Exponent is 3 (encoded in a 2-bit subfield)
359 while ((m_grpAddrBuIndicExp < 3) && ((1 << (m_grpAddrBuIndicExp + 1)) - 1 < GetNLinks() - 1))
360 {
362 }
363}
364
367{
368 if (ac == AC_BEACON)
369 {
370 return m_beaconTxop;
371 }
372 return WifiMac::GetTxopFor(ac);
373}
374
375void
377{
378 NS_LOG_FUNCTION(this << enable);
379 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
380 {
381 if (!enable)
382 {
383 GetLink(linkId).beaconEvent.Cancel();
384 }
385 else if (!m_enableBeaconGeneration)
386 {
387 GetLink(linkId).beaconEvent =
389 }
390 }
392}
393
394Time
396{
397 NS_LOG_FUNCTION(this);
398 return m_beaconInterval;
399}
400
401void
403{
404 NS_LOG_FUNCTION(this << &linkUp);
406
407 // The approach taken here is that, from the point of view of an AP,
408 // the link is always up, so we immediately invoke the callback if
409 // one is set
410 linkUp();
411}
412
413void
415{
416 NS_LOG_FUNCTION(this << interval);
417 if ((interval.GetMicroSeconds() % 1024) != 0)
418 {
419 NS_FATAL_ERROR("beacon interval should be multiple of 1024us (802.11 time unit), see IEEE "
420 "Std. 802.11-2012");
421 }
422 if (interval.GetMicroSeconds() > (1024 * 65535))
423 {
425 "beacon interval should be smaller then or equal to 65535 * 1024us (802.11 time unit)");
426 }
427 m_beaconInterval = interval;
428}
429
430int64_t
432{
433 NS_LOG_FUNCTION(this << stream);
434 m_beaconJitter->SetStream(stream);
435 auto currentStream = stream + 1;
436 currentStream += m_beaconTxop->AssignStreams(currentStream);
437 currentStream += WifiMac::AssignStreams(currentStream);
438 return (currentStream - stream);
439}
440
441void
443{
444 NS_LOG_FUNCTION(this << +linkId);
445 auto& link = GetLink(linkId);
446 if (GetErpSupported(linkId) && GetShortSlotTimeSupported() && (link.numNonErpStations == 0))
447 {
448 for (const auto& sta : link.staList)
449 {
451 {
452 link.shortSlotTimeEnabled = false;
453 return;
454 }
455 }
456 link.shortSlotTimeEnabled = true;
457 }
458 else
459 {
460 link.shortSlotTimeEnabled = false;
461 }
462}
463
464void
466{
467 NS_LOG_FUNCTION(this << +linkId);
468 auto& link = GetLink(linkId);
469 if (GetErpSupported(linkId) && GetWifiPhy(linkId)->GetShortPhyPreambleSupported())
470 {
471 for (const auto& sta : link.staList)
472 {
473 if (!GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(sta.second) ||
474 !GetWifiRemoteStationManager(linkId)->GetShortPreambleSupported(sta.second))
475 {
476 link.shortPreambleEnabled = false;
477 return;
478 }
479 }
480 link.shortPreambleEnabled = true;
481 }
482 else
483 {
484 link.shortPreambleEnabled = false;
485 }
486}
487
488bool
490{
491 return (to.IsGroup() || IsAssociated(to));
492}
493
494void
496{
497 NS_LOG_FUNCTION(this << *mpdu << to << from);
498
499 std::list<Mac48Address> addr2Set;
500 if (to.IsGroup())
501 {
502 // broadcast frames are transmitted on all the links
503 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
504 {
505 addr2Set.push_back(GetFrameExchangeManager(linkId)->GetAddress());
506 }
507 }
508 else
509 {
510 // the Transmitter Address (TA) is the MLD address only for non-broadcast data frames
511 // exchanged between two MLDs
512 addr2Set = {GetAddress()};
513 auto linkId = IsAssociated(to);
514 NS_ASSERT_MSG(linkId, "Station " << to << "is not associated, cannot send it a frame");
515 if (GetNLinks() == 1 || !GetWifiRemoteStationManager(*linkId)->GetMldAddress(to))
516 {
517 addr2Set = {GetFrameExchangeManager(*linkId)->GetAddress()};
518 }
519 }
520
521 for (auto addr2 = addr2Set.cbegin(); addr2 != addr2Set.cend(); ++addr2)
522 {
523 auto& hdr = mpdu->GetHeader();
524
525 hdr.SetAddr1(to);
526 hdr.SetAddr2(*addr2);
527 hdr.SetAddr3(from);
528 hdr.SetDsFrom();
529 hdr.SetDsNotTo();
530
531 auto txop = hdr.IsQosData() ? StaticCast<Txop>(GetQosTxop(hdr.GetQosTid())) : GetTxop();
532 NS_ASSERT(txop);
533 txop->Queue(mpdu);
534
535 // create another MPDU if needed
536 if (std::next(addr2) != addr2Set.cend())
537 {
538 mpdu = Create<WifiMpdu>(mpdu->GetPacket()->Copy(), hdr);
539 }
540 }
541}
542
543bool
545{
546 NS_LOG_FUNCTION(this);
547 return true;
548}
549
551ApWifiMac::GetSupportedRates(uint8_t linkId) const
552{
553 NS_LOG_FUNCTION(this << +linkId);
554 AllSupportedRates rates;
555 // Send the set of supported rates and make sure that we indicate
556 // the Basic Rate set in this set of supported rates.
557 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
558 {
559 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
560 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
561 rates.AddSupportedRate(modeDataRate);
562 // Add rates that are part of the BSSBasicRateSet (manufacturer dependent!)
563 // here we choose to add the mandatory rates to the BSSBasicRateSet,
564 // except for 802.11b where we assume that only the non HR-DSSS rates are part of the
565 // BSSBasicRateSet
566 if (mode.IsMandatory() && (mode.GetModulationClass() != WIFI_MOD_CLASS_HR_DSSS))
567 {
568 NS_LOG_DEBUG("Adding basic mode " << mode.GetUniqueName());
569 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
570 }
571 }
572 // set the basic rates
573 for (uint8_t j = 0; j < GetWifiRemoteStationManager(linkId)->GetNBasicModes(); j++)
574 {
575 WifiMode mode = GetWifiRemoteStationManager(linkId)->GetBasicMode(j);
576 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
577 NS_LOG_DEBUG("Setting basic rate " << mode.GetUniqueName());
578 rates.SetBasicRate(modeDataRate);
579 }
580 // If it is a HT AP, then add the BSSMembershipSelectorSet
581 // The standard says that the BSSMembershipSelectorSet
582 // must have its MSB set to 1 (must be treated as a Basic Rate)
583 // Also the standard mentioned that at least 1 element should be included in the SupportedRates
584 // the rest can be in the ExtendedSupportedRates
585 if (GetHtSupported(linkId))
586 {
587 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
588 {
589 rates.AddBssMembershipSelectorRate(selector);
590 }
591 }
592 return rates;
593}
594
597{
598 NS_LOG_FUNCTION(this << +linkId);
600 DsssParameterSet dsssParameters;
601 dsssParameters.SetCurrentChannel(GetWifiPhy(linkId)->GetChannelNumber());
602 return dsssParameters;
603}
604
606ApWifiMac::GetCapabilities(uint8_t linkId) const
607{
608 NS_LOG_FUNCTION(this << +linkId);
609 CapabilityInformation capabilities;
610 capabilities.SetShortPreamble(GetLink(linkId).shortPreambleEnabled);
611 capabilities.SetShortSlotTime(GetLink(linkId).shortSlotTimeEnabled);
612 capabilities.SetEss();
613 return capabilities;
614}
615
617ApWifiMac::GetBufferedDataFor(Mac48Address address, uint8_t linkId) const
618{
619 if (!GetQosSupported())
620 {
621 const auto queueId = MakeWifiUnicastQueueId(WIFI_DATA_QUEUE, address);
622 return GetTxopQueue(AC_BE_NQOS)->PeekByQueueId(queueId);
623 }
624
625 const auto singleLink = !GetMldAddress(address).has_value();
626
627 for (uint8_t tid = 0; tid < 8; ++tid)
628 {
629 auto mpdu = GetTxopQueue(QosUtilsMapTidToAc(tid))->PeekByTidAndAddress(tid, address);
630
631 if (!mpdu)
632 {
633 continue; // queue empty, look for another TID
634 }
635
636 if (linkId != WIFI_LINKID_UNDEFINED && !singleLink &&
637 !TidMappedOnLink(address, WifiDirection::DOWNLINK, tid, linkId))
638 {
639 continue; // this TID is not mapped on the link for which we want a buffered unit
640 }
641
642 // (Sec. 35.3.12.4 802.11be D6.0) An AP MLD shall buffer a BU with a TID at the AP MLD if
643 // the TID is not mapped to any link on which the corresponding non-AP STA affiliated with
644 // a non-AP MLD is in active mode
645 if (std::none_of(GetLinks().cbegin(), GetLinks().cend(), [=, this](const auto& pair) {
646 const auto lnkId = pair.first;
647 const auto& link = pair.second;
648 // return true if the STA operating on this link is in active mode and the TID is
649 // mapped on this link (or the STA is a single link device)
650 return link->stationManager->IsAssociated(address) &&
651 !link->stationManager->IsInPsMode(address) &&
652 (singleLink ||
653 TidMappedOnLink(address, WifiDirection::DOWNLINK, tid, lnkId));
654 }))
655 {
656 NS_LOG_DEBUG("Found BU: " << *mpdu << " for STA " << address << " and TID=" << +tid);
657 return mpdu;
658 }
659 }
660 return nullptr;
661}
662
664ApWifiMac::GetBufferedMmpduFor(Mac48Address address, uint8_t linkId) const
665{
666 // TODO: 802.11be specs (Sec. 35.3.12.4 of D6.0) allow an AP MLD to avoid buffering an
667 // MMPDU if a non-AP STA is in active mode, even if the non-AP STA is not the intended
668 // receiver of the MMPDU. In case the MMPDU is sent on a link other than the one on which
669 // the intended receiver is operating, the MMPDU shall carry the MLO Link Info element.
670 // Until this mechanism is supported, an MMPDU is buffered if the intended receiver is
671 // in powersave mode
672 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
673 const auto linkIds = (linkId == WIFI_LINKID_UNDEFINED ? GetLinkIds() : std::set{linkId});
674
675 for (const auto& id : linkIds)
676 {
677 auto& link = GetLink(id);
678 if (!link.stationManager->IsInPsMode(address))
679 {
680 continue; // STA on this link is not in PS mode
681 }
682 for (const auto& aci : acList)
683 {
684 const auto queueId = MakeWifiUnicastQueueId(
686 link.stationManager->GetAffiliatedStaAddress(address).value_or(address));
687
688 if (auto mpdu = GetTxopQueue(aci)->PeekByQueueId(queueId))
689 {
690 NS_LOG_DEBUG("Found MMPDU: " << *mpdu << " for STA " << address << " on link "
691 << +id);
692 return mpdu;
693 }
694 }
695 }
696 return nullptr;
697}
698
699bool
701{
702 auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
703
704 const auto blocked =
705 GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(linkId,
708
709 if (blocked)
710 {
711 // temporarily unblock queues with group addressed frames, otherwise buffered group
712 // addressed frames will not be detected
714 {linkId},
716 }
717
718 const auto found = std::any_of(acList.cbegin(), acList.cend(), [=, this](const auto aci) {
719 auto queueId = m_scheduler->GetNext(aci, linkId);
720
721 while (queueId)
722 {
723 if (queueId->addrType == WifiRcvAddr::BROADCAST ||
724 queueId->addrType == WifiRcvAddr::GROUPCAST)
725 {
726 NS_LOG_DEBUG("Found some group addressed frames for link " << +linkId);
727 return true;
728 }
729 queueId = m_scheduler->GetNext(aci, linkId, *queueId);
730 }
731 return false;
732 });
733
734 if (blocked)
735 {
737 {linkId},
739 }
740
741 return found;
742}
743
744Tim
745ApWifiMac::GetTim(uint8_t linkId) const
746{
747 NS_LOG_FUNCTION(this << linkId);
748
749 Tim tim;
750 tim.m_dtimCount = GetLink(linkId).beaconDtimCount;
752
753 // Iterate over the list of associated non-AP STAs or MLDs
754 for (const auto& [aid, address] : m_aidToMldOrLinkAddress)
755 {
756 if (GetStaList(linkId).contains(aid) &&
757 (GetBufferedDataFor(address) || GetBufferedMmpduFor(address)))
758 {
759 tim.AddAid(aid);
760 }
761 }
762
763 // Check for group addressed frames, but only if this is a DTIM
764 if (tim.m_dtimCount == 0)
765 {
766 if (GetLink(linkId).nStationsInPsMode > 0)
767 {
769 }
770
771 /**
772 * Sec. 35.3.15.1 of 802.11be D7.0:
773 * The bits 1 to N of the bitmap in the Partial Virtual Bitmap field are for the AP MLD
774 * where N is equal to 2^(Group Addressed BU Indication Exponent + 1) – 1.
775 * The first n bits of N bits are used to indicate that one or more group addressed frames
776 * are buffered for each AP of the other AP(s) that are affiliated with the same AP MLD by
777 * setting the corresponding bit value to 1 in an increasing order of their link IDs. The
778 * remaining (N – n) bits are set to 0.
779 */
780 if (GetNLinks() > 1)
781 {
782 uint16_t aid = MIN_AID;
783 for (uint8_t id = 0; id < GetNLinks(); ++id)
784 {
785 if (id == linkId || GetLink(id).nStationsInPsMode == 0)
786 {
787 continue;
788 }
789 if (HasBufferedGroupcast(id))
790 {
791 tim.AddAid(aid);
792 }
793 ++aid;
794 }
795 }
796 }
797
798 return tim;
799}
800
801bool
803{
804 NS_LOG_FUNCTION(this << *mpdu << linkId);
805
806 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
807 const auto& hdr = mpdu->GetHeader();
808 const auto addr1 = hdr.GetAddr1();
809
810 if (addr1.IsGroup())
811 {
812 NS_ASSERT_MSG(GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(
813 linkId,
816 "Expected unicast transmissions to be blocked");
817
818 return std::any_of(acList.cbegin(), acList.cend(), [=, this](const auto aci) {
819 auto item = mpdu->IsQueued() && mpdu->GetQueueAc() == aci ? mpdu : nullptr;
820 return GetTxopQueue(aci)->PeekFirstAvailable(linkId, item) != nullptr;
821 });
822 }
823
824 // Sec. 9.2.4.1.8 802.11be D6.0:
825 // A non-DMG and non-S1G STA uses the More Data subfield to indicate to a STA that is not
826 // affiliated with a non-AP MLD and in PS mode that more BUs are buffered for that STA at
827 // the AP.
828 // For a non-AP MLD, an AP affiliated with an AP MLD uses the More Data subfield to indicate to
829 // a non-AP STA in PS mode affiliated with the non-AP MLD that more BUs, corresponding to Data
830 // frames with TIDs that are mapped to this link [...] or bufferable Management frames are
831 // buffered for the non-AP MLD at the AP MLD
832
833 const auto receiver = GetLink(linkId).stationManager->GetMldAddress(addr1).value_or(addr1);
834 const auto isSingleLink = (addr1 == receiver);
835
836 // look for buffered data frames
837 if (!GetQosSupported())
838 {
839 const auto queueId = MakeWifiUnicastQueueId(WIFI_DATA_QUEUE, receiver);
840 auto start = hdr.IsData() ? mpdu : nullptr;
841 if (auto bu = GetTxopQueue(AC_BE_NQOS)->PeekByQueueId(queueId, start))
842 {
843 NS_LOG_DEBUG("Found a buffered unit: " << *bu);
844 return true;
845 }
846 }
847 else
848 {
849 for (uint8_t tid = 0; tid < 8; ++tid)
850 {
851 if (!isSingleLink && !TidMappedOnLink(receiver, WifiDirection::DOWNLINK, tid, linkId))
852 {
853 continue; // this TID is not mapped on this link
854 }
855
856 auto start =
857 (hdr.IsQosData() && hdr.GetQosTid() == tid) ? mpdu->GetOriginal() : nullptr;
858
859 if (auto bu = GetTxopQueue(QosUtilsMapTidToAc(tid))
860 ->PeekByTidAndAddress(tid,
861 receiver,
863 start))
864 {
865 NS_LOG_DEBUG("Found a buffered unit: " << *bu);
866 return true;
867 }
868 }
869 }
870
871 // look for buffered management frames
872 for (const auto aci : acList)
873 {
874 const auto queueId = MakeWifiUnicastQueueId(WIFI_MGT_QUEUE, addr1);
875 auto start = (hdr.IsMgt() && mpdu->GetQueueAc() == aci) ? mpdu : nullptr;
876
877 if (auto bu = GetTxopQueue(aci)->PeekByQueueId(queueId, start))
878 {
879 NS_LOG_DEBUG("Found a buffered unit: " << *bu);
880 return true;
881 }
882 }
883
884 return false;
885}
886
888ApWifiMac::GetErpInformation(uint8_t linkId) const
889{
890 NS_LOG_FUNCTION(this << +linkId);
891 NS_ASSERT(GetErpSupported(linkId));
892 ErpInformation information;
893
894 information.SetNonErpPresent(GetLink(linkId).numNonErpStations > 0);
895 information.SetUseProtection(GetUseNonErpProtection(linkId));
896 if (GetLink(linkId).shortPreambleEnabled)
897 {
898 information.SetBarkerPreambleMode(0);
899 }
900 else
901 {
902 information.SetBarkerPreambleMode(1);
903 }
904
905 return information;
906}
907
910{
911 NS_LOG_FUNCTION(this << +linkId);
913 EdcaParameterSet edcaParameters;
914
915 Ptr<QosTxop> edca;
916 Time txopLimit;
917
918 edca = GetQosTxop(AC_BE);
919 edcaParameters.SetBeAci(0);
920 edcaParameters.SetBeCWmin(m_cwMinsForSta.contains(AC_BE) ? m_cwMinsForSta.at(AC_BE).at(linkId)
921 : edca->GetMinCw(linkId));
922 edcaParameters.SetBeCWmax(m_cwMaxsForSta.contains(AC_BE) ? m_cwMaxsForSta.at(AC_BE).at(linkId)
923 : edca->GetMaxCw(linkId));
924 edcaParameters.SetBeAifsn(m_aifsnsForSta.contains(AC_BE) ? m_aifsnsForSta.at(AC_BE).at(linkId)
925 : edca->GetAifsn(linkId));
926 txopLimit = m_txopLimitsForSta.contains(AC_BE) ? m_txopLimitsForSta.at(AC_BE).at(linkId)
927 : edca->GetTxopLimit(linkId);
928 edcaParameters.SetBeTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
929
930 edca = GetQosTxop(AC_BK);
931 edcaParameters.SetBkAci(1);
932 edcaParameters.SetBkCWmin(m_cwMinsForSta.contains(AC_BK) ? m_cwMinsForSta.at(AC_BK).at(linkId)
933 : edca->GetMinCw(linkId));
934 edcaParameters.SetBkCWmax(m_cwMaxsForSta.contains(AC_BK) ? m_cwMaxsForSta.at(AC_BK).at(linkId)
935 : edca->GetMaxCw(linkId));
936 edcaParameters.SetBkAifsn(m_aifsnsForSta.contains(AC_BK) ? m_aifsnsForSta.at(AC_BK).at(linkId)
937 : edca->GetAifsn(linkId));
938 txopLimit = m_txopLimitsForSta.contains(AC_BK) ? m_txopLimitsForSta.at(AC_BK).at(linkId)
939 : edca->GetTxopLimit(linkId);
940 edcaParameters.SetBkTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
941
942 edca = GetQosTxop(AC_VI);
943 edcaParameters.SetViAci(2);
944 edcaParameters.SetViCWmin(m_cwMinsForSta.contains(AC_VI) ? m_cwMinsForSta.at(AC_VI).at(linkId)
945 : edca->GetMinCw(linkId));
946 edcaParameters.SetViCWmax(m_cwMaxsForSta.contains(AC_VI) ? m_cwMaxsForSta.at(AC_VI).at(linkId)
947 : edca->GetMaxCw(linkId));
948 edcaParameters.SetViAifsn(m_aifsnsForSta.contains(AC_VI) ? m_aifsnsForSta.at(AC_VI).at(linkId)
949 : edca->GetAifsn(linkId));
950 txopLimit = m_txopLimitsForSta.contains(AC_VI) ? m_txopLimitsForSta.at(AC_VI).at(linkId)
951 : edca->GetTxopLimit(linkId);
952 edcaParameters.SetViTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
953
954 edca = GetQosTxop(AC_VO);
955 edcaParameters.SetVoAci(3);
956 edcaParameters.SetVoCWmin(m_cwMinsForSta.contains(AC_VO) ? m_cwMinsForSta.at(AC_VO).at(linkId)
957 : edca->GetMinCw(linkId));
958 edcaParameters.SetVoCWmax(m_cwMaxsForSta.contains(AC_VO) ? m_cwMaxsForSta.at(AC_VO).at(linkId)
959 : edca->GetMaxCw(linkId));
960 edcaParameters.SetVoAifsn(m_aifsnsForSta.contains(AC_VO) ? m_aifsnsForSta.at(AC_VO).at(linkId)
961 : edca->GetAifsn(linkId));
962 txopLimit = m_txopLimitsForSta.contains(AC_VO) ? m_txopLimitsForSta.at(AC_VO).at(linkId)
963 : edca->GetTxopLimit(linkId);
964 edcaParameters.SetVoTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
965
966 edcaParameters.SetQosInfo(0);
967
968 return edcaParameters;
969}
970
971std::optional<MuEdcaParameterSet>
973{
974 NS_LOG_FUNCTION(this);
976
977 Ptr<HeConfiguration> heConfiguration = GetHeConfiguration();
978 NS_ASSERT(heConfiguration);
979
980 MuEdcaParameterSet muEdcaParameters;
981 muEdcaParameters.SetQosInfo(0);
982
983 muEdcaParameters.SetMuAifsn(AC_BE, heConfiguration->m_muBeAifsn);
984 muEdcaParameters.SetMuCwMin(AC_BE, heConfiguration->m_muBeCwMin);
985 muEdcaParameters.SetMuCwMax(AC_BE, heConfiguration->m_muBeCwMax);
986 muEdcaParameters.SetMuEdcaTimer(AC_BE, heConfiguration->m_beMuEdcaTimer);
987
988 muEdcaParameters.SetMuAifsn(AC_BK, heConfiguration->m_muBkAifsn);
989 muEdcaParameters.SetMuCwMin(AC_BK, heConfiguration->m_muBkCwMin);
990 muEdcaParameters.SetMuCwMax(AC_BK, heConfiguration->m_muBkCwMax);
991 muEdcaParameters.SetMuEdcaTimer(AC_BK, heConfiguration->m_bkMuEdcaTimer);
992
993 muEdcaParameters.SetMuAifsn(AC_VI, heConfiguration->m_muViAifsn);
994 muEdcaParameters.SetMuCwMin(AC_VI, heConfiguration->m_muViCwMin);
995 muEdcaParameters.SetMuCwMax(AC_VI, heConfiguration->m_muViCwMax);
996 muEdcaParameters.SetMuEdcaTimer(AC_VI, heConfiguration->m_viMuEdcaTimer);
997
998 muEdcaParameters.SetMuAifsn(AC_VO, heConfiguration->m_muVoAifsn);
999 muEdcaParameters.SetMuCwMin(AC_VO, heConfiguration->m_muVoCwMin);
1000 muEdcaParameters.SetMuCwMax(AC_VO, heConfiguration->m_muVoCwMax);
1001 muEdcaParameters.SetMuEdcaTimer(AC_VO, heConfiguration->m_voMuEdcaTimer);
1002
1003 // The timers of the MU EDCA Parameter Set must be either all zero or all
1004 // non-zero. The information element is advertised if all timers are non-zero
1005 auto timerNotNull = [&muEdcaParameters](uint8_t aci) {
1006 return !muEdcaParameters.GetMuEdcaTimer(aci).IsZero();
1007 };
1008 auto aci = {0, 1, 2, 3};
1009 if (std::all_of(aci.begin(), aci.end(), timerNotNull))
1010 {
1011 return muEdcaParameters;
1012 }
1013
1014 NS_ABORT_MSG_UNLESS(std::none_of(aci.begin(), aci.end(), timerNotNull),
1015 "MU EDCA Timers must be all zero if the IE is not advertised.");
1016
1017 return std::nullopt;
1018}
1019
1020std::optional<ReducedNeighborReport>
1022{
1023 NS_LOG_FUNCTION(this << +linkId);
1024
1025 if (GetNLinks() <= 1)
1026 {
1027 return std::nullopt;
1028 }
1029
1032
1033 for (uint8_t index = 0; index < GetNLinks(); ++index)
1034 {
1035 if (index != linkId) // all links but the one used to send this Beacon frame
1036 {
1037 rnr.AddNbrApInfoField();
1038 std::size_t nbrId = rnr.GetNNbrApInfoFields() - 1;
1039 rnr.SetOperatingChannel(nbrId, GetLink(index).phy->GetOperatingChannel());
1040 rnr.AddTbttInformationField(nbrId);
1041 rnr.SetBssid(nbrId, 0, GetLink(index).feManager->GetAddress());
1042 rnr.SetShortSsid(nbrId, 0, 0);
1043 rnr.SetBssParameters(nbrId, 0, 0);
1044 rnr.SetPsd20MHz(nbrId, 0, 0);
1045 rnr.SetMldParameters(nbrId, 0, {0, index, 0, 0, 0});
1046 }
1047 }
1048 return rnr;
1049}
1050
1053 WifiMacType frameType,
1054 const Mac48Address& to,
1055 const std::optional<MultiLinkElement>& mlProbeReqMle)
1056{
1057 NS_LOG_FUNCTION(this << +linkId << frameType << to);
1058 NS_ABORT_IF(GetNLinks() == 1);
1059 NS_ABORT_MSG_IF(mlProbeReqMle.has_value() && frameType != WIFI_MAC_MGT_PROBE_RESPONSE,
1060 "ML Probe Request Multi-Link Element cannot be provided for frame type "
1061 << frameType);
1062
1065 mle.SetLinkIdInfo(linkId);
1067
1068 auto ehtConfiguration = GetEhtConfiguration();
1069 NS_ASSERT(ehtConfiguration);
1070
1071 if (ehtConfiguration->m_emlsrActivated)
1072 {
1073 mle.SetEmlsrSupported(true);
1074 // When the EMLSR Padding Delay subfield is included in a frame sent by an AP affiliated
1075 // with an AP MLD, the EMLSR Padding Delay subfield is reserved.
1076 // When the EMLSR Transition Delay subfield is included in a frame sent by an AP affiliated
1077 // with an AP MLD, the EMLSR Transition Delay subfield is reserved. (Sec. 9.4.2.312.2.3
1078 // of 802.11be D2.3)
1079 TimeValue time;
1080 mle.SetTransitionTimeout(ehtConfiguration->m_transitionTimeout);
1081
1082 // An AP affiliated with an AP MLD may include the Medium Synchronization Delay Information
1083 // subfield in the Common Info field of the Basic Multi-Link element carried in transmitted
1084 // (Re)Association Response or Multi-Link Probe Response frames to provide medium
1085 // synchronization information used by the AP MLD. (Section 35.3.16.8.2 of 802.11be D3.1)
1086 if (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE)
1087 {
1088 auto& commonInfo = mle.GetCommonInfoBasic();
1089 commonInfo.SetMediumSyncDelayTimer(ehtConfiguration->m_mediumSyncDuration);
1090 commonInfo.SetMediumSyncOfdmEdThreshold(ehtConfiguration->m_msdOfdmEdThreshold);
1091 commonInfo.SetMediumSyncMaxNTxops(ehtConfiguration->m_msdMaxNTxops);
1092 }
1093 }
1094
1095 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
1096 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
1097 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
1098 if (frameType == WIFI_MAC_MGT_BEACON || frameType == WIFI_MAC_MGT_PROBE_RESPONSE ||
1099 frameType == WIFI_MAC_MGT_ASSOCIATION_REQUEST ||
1102 {
1103 auto& mldCapabilities = mle.GetCommonInfoBasic().m_mldCapabilities;
1104 mldCapabilities.emplace();
1105 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
1106 mldCapabilities->srsSupport = 0;
1107 mldCapabilities->tidToLinkMappingSupport =
1108 static_cast<uint8_t>(ehtConfiguration->m_tidLinkMappingSupport);
1109 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
1110 mldCapabilities->aarSupport = 0; // not supported yet
1111 }
1112
1113 // if the Multi-Link Element is being inserted in a (Re)Association Response frame
1114 // and the remote station is affiliated with an MLD, try multi-link setup
1115 if (auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1116 (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE ||
1118 staMldAddress.has_value())
1119 {
1120 for (uint8_t i = 0; i < GetNLinks(); i++)
1121 {
1122 auto remoteStationManager = GetWifiRemoteStationManager(i);
1123 if (auto staAddress = remoteStationManager->GetAffiliatedStaAddress(*staMldAddress);
1124 i != linkId && staAddress.has_value() &&
1125 (remoteStationManager->IsWaitAssocTxOk(*staAddress) ||
1126 remoteStationManager->IsAssocRefused(*staAddress)))
1127 {
1128 // For each requested link in addition to the link on which the
1129 // (Re)Association Response frame is transmitted, the Link Info field
1130 // of the Basic Multi-Link element carried in the (Re)Association
1131 // Response frame shall contain the corresponding Per-STA Profile
1132 // subelement(s) (Sec. 35.3.5.4 of 802.11be D2.0)
1134 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
1135 // The Link ID subfield of the STA Control field of the Per-STA Profile
1136 // subelement for the AP corresponding to a link is set to the link ID
1137 // of the AP affiliated with the AP MLD that is operating on that link.
1138 perStaProfile.SetLinkId(i);
1139 perStaProfile.SetCompleteProfile();
1140 // For each Per-STA Profile subelement included in the Link Info field,
1141 // the Complete Profile subfield of the STA Control field shall be set to 1
1142 perStaProfile.SetStaMacAddress(GetFrameExchangeManager(i)->GetAddress());
1143 perStaProfile.SetAssocResponse(GetAssocResp(*staAddress, i));
1144 }
1145 }
1146 }
1147
1148 if (!mlProbeReqMle.has_value())
1149 {
1150 return mle; // not a multi-link probe request
1151 }
1152
1153 auto reqVar = mlProbeReqMle->GetVariant();
1155 "Invalid MLE variant " << reqVar);
1156
1157 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
1158 // If either the Address 1 field or the Address 3 field of the multi-link probe request is set
1159 // to the MAC address of the responding AP that operates on the same link where the multi-link
1160 // probe request is sent, then the AP MLD ID subfield shall be present in the Probe Request
1161 // Multi-Link element of the multi-link probe request value and targeted AP MLD is identified by
1162 // AP MLD ID subfield, which is set to the same AP MLD ID as the one used by the AP that is
1163 // addressed by the multi-link probe request to identify the AP MLD
1164 // in the Beacon and Probe Response frames that it transmits.
1165 auto apMldId = mlProbeReqMle->GetApMldId();
1166 NS_ASSERT_MSG(apMldId.has_value(), "AP MLD ID subfield missing");
1167
1168 // IEEE 802.11be D6.0 9.4.2.169.2 Neighbor AP Information field
1169 // If the reported AP is affiliated with the same MLD as the reporting AP sending the frame
1170 // carrying this element, the AP MLD ID subfield is set to 0. AP MLD ID value advertised in
1171 // Beacons and Probe Responses is 0. Multi-BSSID feature not supported.
1172 NS_ASSERT_MSG(*apMldId == 0, "AP MLD ID expected value is 0. value = " << +apMldId.value());
1173
1174 // Using set to handle case of multiple Per-STA Profiles including same link ID
1175 std::set<uint8_t> respLinkIds{}; // Set of Link IDs to include in Probe Response
1176 if (const auto nProfiles = mlProbeReqMle->GetNPerStaProfileSubelements(); nProfiles == 0)
1177 {
1178 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
1179 // If the Probe Request Multi-link element in the multi-link probe request does not include
1180 // any per-STA profile, then all APs affiliated with the same AP MLD as the AP identified in
1181 // the Address 1 or Address 3 field or AP MLD ID shall be requested APs.
1182 for (std::size_t i = 0; i < GetNLinks(); ++i)
1183 {
1184 if (i != linkId)
1185 {
1186 respLinkIds.insert(i);
1187 }
1188 }
1189 }
1190
1191 for (std::size_t i = 0; i < mlProbeReqMle->GetNPerStaProfileSubelements(); ++i)
1192 {
1193 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
1194 // If the Probe Request Multi-Link element in the multi-link probe request includes one or
1195 // more per-STA profiles, then only APs affiliated with the same AP MLD whose link ID is
1196 // equal to the value in the Link ID Field in a per-STA profile in the Probe Request
1197 // Multi-link element shall be requested APs.
1198 const auto& perStaProfile = mlProbeReqMle->GetPerStaProfile(i);
1199 auto currLinkId = perStaProfile.GetLinkId();
1200 if ((currLinkId < GetNLinks()) && (currLinkId != linkId))
1201 {
1202 respLinkIds.insert(currLinkId); // Only consider valid link IDs
1203 }
1204 }
1205
1206 auto setPerStaProfile = [&](uint8_t id) -> void {
1208 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
1209 perStaProfile.SetLinkId(id);
1210 // Current support limited to Complete Profile request per link ID
1211 // TODO: Add support for Partial Per-STA Profile request
1212 perStaProfile.SetProbeResponse(GetProbeRespProfile(id));
1213 perStaProfile.SetCompleteProfile();
1214 };
1215
1216 std::for_each(respLinkIds.begin(), respLinkIds.end(), setPerStaProfile);
1217 return mle;
1218}
1219
1221ApWifiMac::GetHtOperation(uint8_t linkId) const
1222{
1223 NS_LOG_FUNCTION(this << +linkId);
1224 NS_ASSERT(GetHtSupported(linkId));
1225 HtOperation operation;
1226 auto phy = GetWifiPhy(linkId);
1227 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1228
1229 operation.SetPrimaryChannel(phy->GetPrimaryChannelNumber(MHz_u{20}));
1230 operation.SetRifsMode(false);
1231 operation.SetNonGfHtStasPresent(true);
1232 if (phy->GetChannelWidth() > MHz_u{20})
1233 {
1234 operation.SetSecondaryChannelOffset(1);
1235 operation.SetStaChannelWidth(1);
1236 }
1237 if (GetLink(linkId).numNonHtStations == 0)
1238 {
1239 operation.SetHtProtection(NO_PROTECTION);
1240 }
1241 else
1242 {
1244 }
1245 uint64_t maxSupportedRate = 0; // in bit/s
1246 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HT))
1247 {
1248 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
1249 NS_ASSERT(nss > 0 && nss < 5);
1250 uint64_t dataRate =
1251 mcs.GetDataRate(phy->GetChannelWidth(),
1252 NanoSeconds(GetHtConfiguration()->m_sgiSupported ? 400 : 800),
1253 nss);
1254 if (dataRate > maxSupportedRate)
1255 {
1256 maxSupportedRate = dataRate;
1257 NS_LOG_DEBUG("Updating maxSupportedRate to " << maxSupportedRate);
1258 }
1259 }
1260 uint8_t maxSpatialStream = phy->GetMaxSupportedTxSpatialStreams();
1261 auto mcsList = phy->GetMcsList(WIFI_MOD_CLASS_HT);
1262 uint8_t nMcs = mcsList.size();
1263 for (const auto& sta : GetLink(linkId).staList)
1264 {
1265 if (remoteStationManager->GetHtSupported(sta.second) ||
1266 remoteStationManager->GetStationHe6GhzCapabilities(sta.second))
1267 {
1268 uint64_t maxSupportedRateByHtSta = 0; // in bit/s
1269 auto itMcs = mcsList.begin();
1270 for (uint8_t j = 0;
1271 j < (std::min(nMcs, remoteStationManager->GetNMcsSupported(sta.second)));
1272 j++)
1273 {
1274 WifiMode mcs = *itMcs++;
1275 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
1276 NS_ASSERT(nss > 0 && nss < 5);
1277 uint64_t dataRate = mcs.GetDataRate(
1278 remoteStationManager->GetChannelWidthSupported(sta.second),
1279 NanoSeconds(remoteStationManager->GetShortGuardIntervalSupported(sta.second)
1280 ? 400
1281 : 800),
1282 nss);
1283 if (dataRate > maxSupportedRateByHtSta)
1284 {
1285 maxSupportedRateByHtSta = dataRate;
1286 }
1287 }
1288 if (maxSupportedRateByHtSta < maxSupportedRate)
1289 {
1290 maxSupportedRate = maxSupportedRateByHtSta;
1291 }
1292 if (remoteStationManager->GetNMcsSupported(sta.second) < nMcs)
1293 {
1294 nMcs = remoteStationManager->GetNMcsSupported(sta.second);
1295 }
1296 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1297 {
1298 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1299 }
1300 }
1301 }
1303 static_cast<uint16_t>(maxSupportedRate / 1e6)); // in Mbit/s
1304 operation.SetTxMcsSetDefined(nMcs > 0);
1305 operation.SetTxMaxNSpatialStreams(maxSpatialStream);
1306 // To be filled in once supported
1307 operation.SetObssNonHtStasPresent(0);
1308 operation.SetDualBeacon(0);
1309 operation.SetDualCtsProtection(0);
1310 operation.SetStbcBeacon(0);
1312 operation.SetPcoActive(0);
1313 operation.SetPhase(0);
1314 operation.SetRxMcsBitmask(0);
1315 operation.SetTxRxMcsSetUnequal(0);
1316 operation.SetTxUnequalModulation(0);
1317
1318 return operation;
1319}
1320
1322ApWifiMac::GetVhtOperation(uint8_t linkId) const
1323{
1324 NS_LOG_FUNCTION(this << +linkId);
1325 NS_ASSERT(GetVhtSupported(linkId));
1326 VhtOperation operation;
1327 auto phy = GetWifiPhy(linkId);
1328 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1329
1330 const auto bssBandwidth = phy->GetChannelWidth();
1331 // Set to 0 for 20 MHz or 40 MHz BSS bandwidth.
1332 // Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS bandwidth.
1333 operation.SetChannelWidth((bssBandwidth > MHz_u{40}) ? 1 : 0);
1334 // For 20, 40, or 80 MHz BSS bandwidth, indicates the channel center frequency
1335 // index for the 20, 40, or 80 MHz channel on which the VHT BSS operates.
1336 // For 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
1337 // indicates the channel center frequency index of the 80 MHz channel
1338 // segment that contains the primary channel.
1339 // For 80+80 MHz BSS bandwidth and the Channel Width subfield equal to 1 or 3,
1340 // indicates the channel center frequency index for the primary 80 MHz channel of the VHT BSS.
1341 operation.SetChannelCenterFrequencySegment0((bssBandwidth == MHz_u{160})
1342 ? phy->GetPrimaryChannelNumber(MHz_u{80})
1343 : phy->GetChannelNumber());
1344 // For a 20, 40, or 80 MHz BSS bandwidth, this subfield is set to 0.
1345 // For a 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
1346 // indicates the channel center frequency index of the 160 MHz channel on
1347 // which the VHT BSS operates.
1348 // For an 80+80 MHz BSS bandwidth and the Channel Width subfield equal to 1 or 3,
1349 // indicates the channel center frequency index of the secondary 80 MHz channel of the VHT BSS.
1350 const auto& operatingChannel = phy->GetOperatingChannel();
1351 const auto is80Plus80 =
1352 operatingChannel.GetWidthType() == WifiChannelWidthType::CW_80_PLUS_80MHZ;
1353 operation.SetChannelCenterFrequencySegment1((bssBandwidth == MHz_u{160})
1354 ? is80Plus80 ? operatingChannel.GetNumber(1)
1355 : phy->GetChannelNumber()
1356 : 0);
1357 uint8_t maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
1358 for (const auto& sta : GetLink(linkId).staList)
1359 {
1360 if (remoteStationManager->GetVhtSupported(sta.second))
1361 {
1362 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1363 {
1364 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1365 }
1366 }
1367 }
1368 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
1369 {
1370 uint8_t maxMcs =
1371 9; // TBD: hardcode to 9 for now since we assume all MCS values are supported
1372 operation.SetMaxVhtMcsPerNss(nss, maxMcs);
1373 }
1374
1375 return operation;
1376}
1377
1379ApWifiMac::GetHeOperation(uint8_t linkId) const
1380{
1381 NS_LOG_FUNCTION(this << +linkId);
1383 HeOperation operation;
1384 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1385
1386 uint8_t maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
1387 for (const auto& sta : GetLink(linkId).staList)
1388 {
1389 if (remoteStationManager->GetHeSupported(sta.second))
1390 {
1391 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1392 {
1393 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1394 }
1395 }
1396 }
1397 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
1398 {
1399 operation.SetMaxHeMcsPerNss(
1400 nss,
1401 11); // TBD: hardcode to 11 for now since we assume all MCS values are supported
1402 }
1403 operation.m_bssColorInfo.m_bssColor = GetHeConfiguration()->m_bssColor;
1404
1405 if (auto phy = GetWifiPhy(linkId); phy && phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ)
1406 {
1408 const auto bw = phy->GetChannelWidth();
1409 const auto ch = phy->GetOperatingChannel();
1410 op6Ghz.m_chWid = (bw == MHz_u{20}) ? 0 : (bw == MHz_u{40}) ? 1 : (bw == MHz_u{80}) ? 2 : 3;
1411 op6Ghz.m_primCh = ch.GetPrimaryChannelNumber(MHz_u{20}, WIFI_STANDARD_80211ax);
1412 op6Ghz.m_chCntrFreqSeg0 = (bw == MHz_u{160})
1413 ? ch.GetPrimaryChannelNumber(MHz_u{80}, WIFI_STANDARD_80211ax)
1414 : ch.GetNumber();
1415 // TODO: for 80+80 MHz channels, set this field to the secondary 80 MHz segment number
1416 op6Ghz.m_chCntrFreqSeg1 = (bw == MHz_u{160}) ? ch.GetNumber() : 0;
1417
1418 operation.m_6GHzOpInfo = op6Ghz;
1419 }
1420
1421 return operation;
1422}
1423
1425ApWifiMac::GetEhtOperation(uint8_t linkId) const
1426{
1427 NS_LOG_FUNCTION(this << +linkId);
1429 EhtOperation operation;
1430 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1431 const auto phy = GetWifiPhy(linkId);
1432
1433 auto maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
1434 for (const auto& sta : GetLink(linkId).staList)
1435 {
1436 if (remoteStationManager->GetEhtSupported(sta.second))
1437 {
1438 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1439 {
1440 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1441 }
1442 }
1443 }
1444 operation.SetMaxRxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1445 operation.SetMaxTxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1447
1448 if (const auto bw = phy->GetChannelWidth();
1449 (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) && (bw == MHz_u{320}))
1450 {
1451 operation.m_opInfo.emplace(EhtOperation::EhtOpInfo{{.channelWidth = 4}});
1452 operation.m_params.opInfoPresent = 1;
1453 }
1454 return operation;
1455}
1456
1457void
1459 Mac48Address to,
1460 uint8_t linkId)
1461{
1462 NS_LOG_FUNCTION(this << to << +linkId);
1464 hdr.SetAddr1(to);
1465 hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
1466 hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
1467 hdr.SetDsNotFrom();
1468 hdr.SetDsNotTo();
1469 Ptr<Packet> packet = Create<Packet>();
1470 packet->AddHeader(probeResp);
1471
1472 if (!GetQosSupported())
1473 {
1474 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1475 }
1476 // "A QoS STA that transmits a Management frame determines access category used
1477 // for medium access in transmission of the Management frame as follows
1478 // (If dot11QMFActivated is false or not present)
1479 // — If the Management frame is individually addressed to a non-QoS STA, category
1480 // AC_BE should be selected.
1481 // — If category AC_BE was not selected by the previous step, category AC_VO
1482 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1483 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1484 {
1485 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1486 }
1487 else
1488 {
1489 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1490 }
1491}
1492
1495{
1497 probe.Get<Ssid>() = GetSsid();
1498 auto supportedRates = GetSupportedRates(linkId);
1499 probe.Get<SupportedRates>() = supportedRates.rates;
1500 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1502 probe.m_capability = GetCapabilities(linkId);
1503 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(
1504 GetLink(linkId).shortPreambleEnabled);
1505 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1506 GetLink(linkId).shortSlotTimeEnabled);
1507 if (GetDsssSupported(linkId))
1508 {
1509 probe.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1510 }
1511 if (GetErpSupported(linkId))
1512 {
1513 probe.Get<ErpInformation>() = GetErpInformation(linkId);
1514 }
1515 if (GetQosSupported())
1516 {
1517 probe.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1518 }
1519 if (GetHtSupported(linkId))
1520 {
1522 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1523 probe.Get<HtOperation>() = GetHtOperation(linkId);
1524 }
1525 if (GetVhtSupported(linkId))
1526 {
1527 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1528 probe.Get<VhtOperation>() = GetVhtOperation(linkId);
1529 }
1530 if (GetHeSupported())
1531 {
1532 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1533 probe.Get<HeOperation>() = GetHeOperation(linkId);
1534 if (auto muEdcaParameterSet = GetMuEdcaParameterSet())
1535 {
1536 probe.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1537 }
1538 if (Is6GhzBand(linkId))
1539 {
1541 }
1542 }
1543 if (GetEhtSupported())
1544 {
1545 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1546 probe.Get<EhtOperation>() = GetEhtOperation(linkId);
1547 }
1548
1549 return probe;
1550}
1551
1553ApWifiMac::GetProbeResp(uint8_t linkId, const std::optional<MultiLinkElement>& reqMle)
1554{
1555 NS_LOG_FUNCTION(this << linkId << reqMle.has_value());
1556 NS_ASSERT_MSG(linkId < GetNLinks(), "Invalid link ID = " << +linkId);
1557
1558 auto probeResp = GetProbeRespProfile(linkId);
1559
1560 if (GetNLinks() > 1)
1561 {
1562 /*
1563 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1564 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1565 * include a TBTT Information field in a Reduced Neighbor Report element with the
1566 * TBTT Information Length field set to 16 or higher, for each of the other APs
1567 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1568 */
1569 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1570 {
1571 probeResp.Get<ReducedNeighborReport>() = std::move(*rnr);
1572 }
1573 /*
1574 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1575 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1576 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1577 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1578 * channel switching, extended channel switching, and channel quieting) are
1579 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1580 */
1581 probeResp.Get<MultiLinkElement>() = GetMultiLinkElement(linkId,
1584 reqMle);
1585 }
1586 return probeResp;
1587}
1588
1591{
1593 StatusCode code;
1594 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1595 if (remoteStationManager->IsWaitAssocTxOk(to))
1596 {
1597 code.SetSuccess();
1598 }
1599 else
1600 {
1601 NS_ABORT_IF(!remoteStationManager->IsAssocRefused(to));
1602 // reset state
1603 remoteStationManager->RecordDisassociated(to);
1604 code.SetFailure();
1605 }
1606 auto supportedRates = GetSupportedRates(linkId);
1607 assoc.Get<SupportedRates>() = supportedRates.rates;
1608 assoc.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1609 assoc.m_statusCode = code;
1610 assoc.m_capability = GetCapabilities(linkId);
1611 if (GetQosSupported())
1612 {
1613 assoc.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1614 }
1615 if (GetHtSupported(linkId))
1616 {
1618 assoc.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1619 assoc.Get<HtOperation>() = GetHtOperation(linkId);
1620 }
1621 if (GetVhtSupported(linkId))
1622 {
1623 assoc.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1624 assoc.Get<VhtOperation>() = GetVhtOperation(linkId);
1625 }
1626 if (GetHeSupported())
1627 {
1628 assoc.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1629 assoc.Get<HeOperation>() = GetHeOperation(linkId);
1630 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1631 {
1632 assoc.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1633 }
1634 if (Is6GhzBand(linkId))
1635 {
1637 }
1638 }
1639 if (GetEhtSupported())
1640 {
1641 assoc.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1642 assoc.Get<EhtOperation>() = GetEhtOperation(linkId);
1643 // The AP MLD that accepts the requested TID-to-link mapping shall not include in the
1644 // (Re)Association Response frame the TID-to-link Mapping element.
1645 // (Sec. 35.3.7.1.8 of 802.11be D3.1).
1646 // For now, we assume that AP MLDs always accept requested TID-to-link mappings.
1647 }
1648 return assoc;
1649}
1650
1653 const Mac48Address& to,
1654 uint8_t linkId)
1655{
1656 // find all the links to setup (i.e., those for which status code is success)
1657 std::map<uint8_t /* link ID */, Mac48Address> linkIdStaAddrMap;
1658
1659 if (assoc.m_statusCode.IsSuccess())
1660 {
1661 linkIdStaAddrMap[linkId] = to;
1662 }
1663
1664 if (const auto& mle = assoc.Get<MultiLinkElement>())
1665 {
1666 const auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1667 NS_ABORT_MSG_IF(!staMldAddress.has_value(),
1668 "Sending a Multi-Link Element to a single link device");
1669 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1670 {
1671 auto& perStaProfile = mle->GetPerStaProfile(idx);
1672 if (perStaProfile.HasAssocResponse() &&
1673 perStaProfile.GetAssocResponse().m_statusCode.IsSuccess())
1674 {
1675 uint8_t otherLinkId = perStaProfile.GetLinkId();
1676 auto staAddress = GetWifiRemoteStationManager(otherLinkId)
1677 ->GetAffiliatedStaAddress(*staMldAddress);
1678 NS_ABORT_MSG_IF(!staAddress.has_value(),
1679 "No STA to associate with on link " << +otherLinkId);
1680 const auto [it, inserted] = linkIdStaAddrMap.insert({otherLinkId, *staAddress});
1681 NS_ABORT_MSG_IF(!inserted,
1682 "More than one Association Response to MLD "
1683 << *staMldAddress << " on link ID " << +otherLinkId);
1684 }
1685 }
1686 }
1687
1688 return linkIdStaAddrMap;
1689}
1690
1691void
1693{
1694 if (linkIdStaAddrMap.empty())
1695 {
1696 // no link to setup, nothing to do
1697 return;
1698 }
1699
1700 const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
1701 const auto addr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1702
1703 // check if an AID is already allocated to the device that is associating
1704 std::set<uint16_t> aids;
1705
1706 for (const auto& [id, link] : GetLinks())
1707 {
1708 if (const auto aid = link->stationManager->GetAssociationId(addr); aid != SU_STA_ID)
1709 {
1710 aids.insert(aid);
1711 }
1712 }
1713
1714 NS_ABORT_MSG_IF(aids.size() > 1, addr << " cannot have more than one AID assigned");
1715
1716 const auto aid = aids.empty() ? GetNextAssociationId() : *aids.cbegin();
1717
1718 // store the MLD or link address in the AID-to-address map
1719 const auto [it, inserted] = m_aidToMldOrLinkAddress.emplace(aid, addr);
1720
1721 NS_ABORT_MSG_IF(!inserted, "AID " << aid << " already present, cannot be assigned to " << addr);
1722
1723 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1724 {
1725 auto& link = GetLink(id);
1726
1727 if (const auto [it, inserted] = link.staList.emplace(aid, staAddr); inserted)
1728 {
1729 // the STA on this link had no AID assigned
1730 link.stationManager->SetAssociationId(staAddr, aid);
1731
1732 if (link.stationManager->GetDsssSupported(staAddr) &&
1733 !link.stationManager->GetErpOfdmSupported(staAddr))
1734 {
1735 link.numNonErpStations++;
1736 }
1737 if (!link.stationManager->GetHtSupported(staAddr) &&
1738 !link.stationManager->GetStationHe6GhzCapabilities(staAddr))
1739 {
1740 link.numNonHtStations++;
1741 }
1744 }
1745 else
1746 {
1747 // the STA on this link had an AID assigned
1748 NS_ABORT_MSG_IF(it->first != aid,
1749 "AID " << it->first << " already assigned to " << staAddr
1750 << ", could not assign " << aid);
1751 }
1752 }
1753
1754 // set the AID in all the Association Responses. NOTE that the Association
1755 // Responses included in the Per-STA Profile Subelements of the Multi-Link
1756 // Element must not contain the AID field. We set the AID field in such
1757 // Association Responses anyway, in order to ease future implementation of
1758 // the inheritance mechanism.
1759 if (assoc.m_statusCode.IsSuccess())
1760 {
1761 assoc.m_aid = aid;
1762 }
1763 if (const auto& mle = assoc.Get<MultiLinkElement>())
1764 {
1765 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1766 {
1767 if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1768 perStaProfile.HasAssocResponse() &&
1769 perStaProfile.GetAssocResponse().m_statusCode.IsSuccess())
1770 {
1771 perStaProfile.GetAssocResponse().m_aid = aid;
1772 }
1773 }
1774 }
1775}
1776
1777void
1778ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1779{
1780 NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1781 WifiMacHeader hdr;
1784 hdr.SetAddr1(to);
1787 hdr.SetDsNotFrom();
1788 hdr.SetDsNotTo();
1789
1790 MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1791
1792 // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1793 // Request frame that carries a Basic Multi-Link element shall include a Basic
1794 // Multi-Link element in the (Re)Association Response frame that it transmits
1795 // (Sec. 35.3.5.4 of 802.11be D2.0)
1796 // If the STA included a Multi-Link Element in the (Re)Association Request, we
1797 // stored its MLD address in the remote station manager
1798 if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1799 {
1800 assoc.Get<MultiLinkElement>() = GetMultiLinkElement(linkId, hdr.GetType(), to);
1801 }
1802
1803 auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1804 SetAid(assoc, linkIdStaAddrMap);
1805
1806 Ptr<Packet> packet = Create<Packet>();
1807 packet->AddHeader(assoc);
1808
1809 if (!GetQosSupported())
1810 {
1811 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1812 }
1813 // "A QoS STA that transmits a Management frame determines access category used
1814 // for medium access in transmission of the Management frame as follows
1815 // (If dot11QMFActivated is false or not present)
1816 // — If the Management frame is individually addressed to a non-QoS STA, category
1817 // AC_BE should be selected.
1818 // — If category AC_BE was not selected by the previous step, category AC_VO
1819 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1820 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1821 {
1822 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1823 }
1824 else
1825 {
1826 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1827 }
1828}
1829
1830void
1832{
1833 NS_LOG_FUNCTION(this << +linkId);
1834 auto& link = GetLink(linkId);
1835 WifiMacHeader hdr;
1838 hdr.SetAddr2(link.feManager->GetAddress());
1839 hdr.SetAddr3(link.feManager->GetAddress());
1840 hdr.SetDsNotFrom();
1841 hdr.SetDsNotTo();
1842 Ptr<Packet> packet = Create<Packet>();
1843 MgtBeaconHeader beacon;
1844 beacon.Get<Ssid>() = GetSsid();
1845 auto supportedRates = GetSupportedRates(linkId);
1846 beacon.Get<SupportedRates>() = supportedRates.rates;
1847 beacon.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1849 beacon.m_capability = GetCapabilities(linkId);
1850 beacon.Get<Tim>() = GetTim(linkId);
1851 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1852 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1853 if (GetDsssSupported(linkId))
1854 {
1855 beacon.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1856 }
1857 if (GetErpSupported(linkId))
1858 {
1859 beacon.Get<ErpInformation>() = GetErpInformation(linkId);
1860 }
1861 if (GetQosSupported())
1862 {
1863 beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1864 }
1865 if (GetHtSupported(linkId))
1866 {
1868 beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1869 beacon.Get<HtOperation>() = GetHtOperation(linkId);
1870 }
1871 if (GetVhtSupported(linkId))
1872 {
1873 beacon.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1874 beacon.Get<VhtOperation>() = GetVhtOperation(linkId);
1875 }
1876 if (GetHeSupported())
1877 {
1878 beacon.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1879 beacon.Get<HeOperation>() = GetHeOperation(linkId);
1880 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1881 {
1882 beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1883 }
1884 if (Is6GhzBand(linkId))
1885 {
1886 beacon.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
1887 }
1888 }
1889 if (GetEhtSupported())
1890 {
1891 beacon.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1892 beacon.Get<EhtOperation>() = GetEhtOperation(linkId);
1893
1894 if (GetNLinks() > 1)
1895 {
1896 /*
1897 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1898 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1899 * include a TBTT Information field in a Reduced Neighbor Report element with the
1900 * TBTT Information Length field set to 16 or higher, for each of the other APs
1901 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1902 */
1903 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1904 {
1905 beacon.Get<ReducedNeighborReport>() = std::move(*rnr);
1906 }
1907 /*
1908 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1909 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1910 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1911 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1912 * channel switching, extended channel switching, and channel quieting) are
1913 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1914 */
1916 }
1917 }
1918 packet->AddHeader(beacon);
1919
1920 NS_LOG_INFO("Generating beacon from " << link.feManager->GetAddress() << " linkID " << +linkId);
1921 // The beacon has it's own special queue, so we load it in there
1922 m_beaconTxop->Queue(Create<WifiMpdu>(packet, hdr));
1923 link.beaconEvent =
1925
1927
1928 // If a STA that does not support Short Slot Time associates,
1929 // the AP shall use long slot time beginning at the first Beacon
1930 // subsequent to the association of the long slot time STA.
1931 if (GetErpSupported(linkId))
1932 {
1933 if (link.shortSlotTimeEnabled)
1934 {
1935 // Enable short slot time
1936 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1937 }
1938 else
1939 {
1940 // Disable short slot time
1941 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1942 }
1943 }
1944
1945 // Update the DTIM Count
1946 auto& dtimCount = GetLink(linkId).beaconDtimCount;
1947 dtimCount = dtimCount == 0 ? (m_dtimPeriod - 1) : (dtimCount - 1);
1948
1949 const auto& tim = beacon.Get<Tim>();
1950 NS_ASSERT(tim);
1951 if (tim->m_dtimCount == 0 && tim->m_hasMulticastPending)
1952 {
1953 // connect a callback to intercept the transmission of the Beacon frame and start
1954 // transmitting the pending group addressed frames
1955 link.phy->TraceConnectWithoutContext(
1956 "PhyTxPsduBegin",
1958 }
1959}
1960
1961void
1963 WifiConstPsduMap psduMap,
1964 WifiTxVector /* txVector */,
1965 Watt_u /* txPower */)
1966{
1967 NS_LOG_FUNCTION(this << linkId);
1968
1969 if (psduMap.size() > 1 || !psduMap.cbegin()->second->GetHeader(0).IsBeacon())
1970 {
1971 return;
1972 }
1973
1974 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
1975
1976 std::map<AcIndex, bool> hasFramesToTransmit;
1977 for (const auto aci : acList)
1978 {
1979 // save the status of the AC queues before unblocking the queues
1980 hasFramesToTransmit[aci] = GetTxopFor(aci)->HasFramesToTransmit(linkId);
1981 }
1982
1983 NS_LOG_DEBUG("Unblock transmission of group addressed frames on link " << +linkId);
1985 {linkId},
1987
1988 NS_LOG_DEBUG("Block transmission of unicast frames on link " << +linkId);
1990 {linkId},
1992
1993 for (const auto aci : acList)
1994 {
1995 GetTxopFor(aci)->StartAccessAfterEvent(linkId,
1996 hasFramesToTransmit[aci],
1998 }
1999
2000 // the Beacon frame has been intercepted, we can disconnect the callback (right after all
2001 // callbacks connected to the trace source are called)
2002 Simulator::ScheduleNow([=, this]() {
2003 GetLink(linkId).phy->TraceDisconnectWithoutContext(
2004 "PhyTxPsduBegin",
2006 });
2007
2008 // connect another callback to be notified of packets removed from the MAC queues; this is
2009 // needed to detect that all pending group addressed frames have been transmitted
2010 for (const auto aci : acList)
2011 {
2012 GetTxopQueue(aci)->TraceConnectWithoutContext(
2013 "Dequeue",
2015 GetTxopQueue(aci)->TraceConnectWithoutContext(
2016 "Drop",
2018 }
2019
2020 // check that the AP actually has group addressed frames to transmit
2022}
2023
2024void
2026{
2027 NS_LOG_FUNCTION(this << linkId);
2028
2029 if (!GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(
2030 linkId,
2033 {
2034 NS_LOG_DEBUG("Unicast frames are not blocked on link " << +linkId << ", nothing to do");
2035 return;
2036 }
2037
2038 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
2039
2040 // when this function is called right after sending the Beacon frame, no MPDU is passed
2041 const auto noGroupAddressed =
2042 !mpdu && std::all_of(acList.cbegin(), acList.cend(), [=, this](const auto aci) {
2043 return (GetTxopQueue(aci)->PeekFirstAvailable(linkId) == nullptr);
2044 });
2045 const auto lastGroupAddressed =
2046 mpdu && mpdu->GetHeader().GetAddr1().IsGroup() && !mpdu->GetHeader().IsMoreData();
2047
2048 if (noGroupAddressed || lastGroupAddressed)
2049 {
2050 NS_LOG_DEBUG((noGroupAddressed ? "No group addressed frames queued for link "
2051 : "Sent a group addressed frame with More Data=0 on link ")
2052 << +linkId);
2053
2054 std::map<AcIndex, bool> hasFramesToTransmit;
2055 for (const auto aci : acList)
2056 {
2057 // save the status of the AC queues before unblocking the queues
2058 hasFramesToTransmit[aci] = GetTxopFor(aci)->HasFramesToTransmit(linkId);
2059 }
2060
2062 {linkId},
2065 {linkId},
2067 // do not block transmission of Beacon frames
2069 AC_BEACON,
2072 GetFrameExchangeManager(linkId)->GetAddress());
2073
2074 for (const auto aci : acList)
2075 {
2076 GetTxopFor(aci)->StartAccessAfterEvent(linkId,
2077 hasFramesToTransmit[aci],
2079 }
2080
2081 // disconnect callbacks (right after all callbacks connected to the trace source are called)
2082 Simulator::ScheduleNow([=, this]() {
2083 for (const auto aci : acList)
2084 {
2085 GetTxopQueue(aci)->TraceDisconnectWithoutContext(
2086 "Dequeue",
2088 GetTxopQueue(aci)->TraceDisconnectWithoutContext(
2089 "Drop",
2091 }
2092 });
2093 }
2094}
2095
2097ApWifiMac::GetFilsDiscovery(uint8_t linkId) const
2098{
2101 auto& link = GetLink(linkId);
2102 hdr.SetAddr2(link.feManager->GetAddress());
2103 hdr.SetAddr3(link.feManager->GetAddress());
2104 hdr.SetDsNotFrom();
2105 hdr.SetDsNotTo();
2106
2107 WifiActionHeader actionHdr;
2109 action.publicAction = WifiActionHeader::FILS_DISCOVERY;
2110 actionHdr.SetAction(WifiActionHeader::PUBLIC, action);
2111
2112 FilsDiscHeader fils;
2113 fils.SetSsid(GetSsid().PeekString());
2114 fils.m_beaconInt = (m_beaconInterval / WIFI_TU).GetHigh();
2115
2117 fils.m_fdCap->SetOpChannelWidth(link.phy->GetChannelWidth());
2118 fils.m_fdCap->SetMaxNss(std::min(link.phy->GetMaxSupportedTxSpatialStreams(),
2119 link.phy->GetMaxSupportedRxSpatialStreams()));
2120 fils.m_fdCap->SetStandard(link.phy->GetStandard());
2121
2122 fils.SetLengthSubfield();
2123 fils.m_rnr = GetReducedNeighborReport(linkId);
2124
2125 auto packet = Create<Packet>();
2126 packet->AddHeader(fils);
2127 packet->AddHeader(actionHdr);
2128
2129 return Create<WifiMpdu>(packet, hdr);
2130}
2131
2132void
2134{
2135 NS_LOG_FUNCTION(this << linkId);
2136 auto phy = GetLink(linkId).phy;
2137
2138 auto fdBeaconInterval = (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) ? m_fdBeaconInterval6GHz
2140
2141 if (!fdBeaconInterval.IsStrictlyPositive())
2142 {
2143 NS_LOG_DEBUG("Sending FILS Discovery/unsolicited Probe Response disabled");
2144 return;
2145 }
2146
2147 // Schedule FD or unsolicited Probe Response frames (IEEE Std 802.11ax-2021 26.17.2.3.2)
2148 for (uint8_t count = 1; count < (m_beaconInterval / fdBeaconInterval).GetHigh(); ++count)
2149 {
2151 {
2152 Simulator::Schedule(fdBeaconInterval * count,
2154 this,
2155 GetProbeResp(linkId, std::nullopt),
2157 linkId);
2158 }
2159 else
2160 {
2161 Simulator::Schedule(fdBeaconInterval * count,
2162 [=, this]() { m_beaconTxop->Queue(GetFilsDiscovery(linkId)); });
2163 }
2164 }
2165}
2166
2167void
2169{
2170 NS_LOG_FUNCTION(this << *mpdu);
2171 const WifiMacHeader& hdr = mpdu->GetHeader();
2172
2173 if (hdr.IsAssocResp() || hdr.IsReassocResp())
2174 {
2175 MgtAssocResponseHeader assocResp;
2176 mpdu->GetPacket()->PeekHeader(assocResp);
2177 auto aid = assocResp.m_aid;
2178
2179 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
2180 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
2181
2182 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
2183 {
2184 NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
2185 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxOk(hdr.GetAddr1());
2186 m_assocLogger(aid, hdr.GetAddr1());
2187 }
2188
2189 if (auto staMldAddress =
2190 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
2191 staMldAddress.has_value())
2192 {
2193 /**
2194 * The STA is affiliated with an MLD. From Sec. 35.3.7.1.4 of 802.11be D3.0:
2195 * When a link becomes enabled for a non-AP STA that is affiliated with a non-AP MLD
2196 * after successful association with an AP MLD with (Re)Association Request/Response
2197 * frames transmitted on another link [...], the power management mode of the non-AP
2198 * STA, immediately after the acknowledgement of the (Re)Association Response frame
2199 * [...], is power save mode, and its power state is doze.
2200 *
2201 * Thus, STAs operating on all the links but the link used to establish association
2202 * transition to power save mode.
2203 */
2204 for (uint8_t i = 0; i < GetNLinks(); i++)
2205 {
2206 auto stationManager = GetWifiRemoteStationManager(i);
2207 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
2208 staAddress.has_value() && i != *linkId &&
2209 stationManager->IsWaitAssocTxOk(*staAddress))
2210 {
2212 << " associated with STA=" << *staAddress);
2213 stationManager->RecordGotAssocTxOk(*staAddress);
2214 m_assocLogger(aid, *staAddress);
2215 StaSwitchingToPsMode(*staAddress, i);
2216 }
2217 }
2218
2219 // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
2221 }
2222
2223 if (auto extendedCapabilities =
2224 GetWifiRemoteStationManager(*linkId)->GetStationExtendedCapabilities(
2225 hdr.GetAddr1());
2227 {
2228 const auto isGcrCapable =
2229 extendedCapabilities && extendedCapabilities->m_robustAvStreaming;
2230 m_gcrManager->NotifyStaAssociated(hdr.GetAddr1(), isGcrCapable);
2231 }
2232 }
2233 else if (hdr.IsAction())
2234 {
2235 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
2236 category == WifiActionHeader::PROTECTED_EHT &&
2237 action.protectedEhtAction ==
2239 {
2240 // the EMLSR client acknowledged the EML Operating Mode Notification frame;
2241 // we can stop the timer and enforce the configuration deriving from the
2242 // EML Notification frame sent by the EMLSR client
2243 if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
2244 eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsPending())
2245 {
2246 // no need to wait until the expiration of the transition timeout
2247 eventIt->second.PeekEventImpl()->Invoke();
2248 eventIt->second.Cancel();
2249 }
2250 }
2251 }
2252}
2253
2254void
2256{
2257 NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
2258 const WifiMacHeader& hdr = mpdu->GetHeader();
2259
2260 if (hdr.IsAssocResp() || hdr.IsReassocResp())
2261 {
2262 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
2263 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
2264
2265 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
2266 {
2267 NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
2268 << " association failed with STA=" << hdr.GetAddr1());
2269 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxFailed(hdr.GetAddr1());
2270 }
2271
2272 if (auto staMldAddress =
2273 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
2274 staMldAddress.has_value())
2275 {
2276 // the STA is affiliated with an MLD
2277 for (uint8_t i = 0; i < GetNLinks(); i++)
2278 {
2279 auto stationManager = GetWifiRemoteStationManager(i);
2280 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
2281 staAddress.has_value() && i != *linkId &&
2282 stationManager->IsWaitAssocTxOk(*staAddress))
2283 {
2285 << " association failed with STA=" << *staAddress);
2286 stationManager->RecordGotAssocTxFailed(*staAddress);
2287 }
2288 }
2289 }
2290
2291 // free the assigned AID
2292 MgtAssocResponseHeader assocResp;
2293 mpdu->GetPacket()->PeekHeader(assocResp);
2294 auto aid = assocResp.m_aid;
2295 m_aidToMldOrLinkAddress.erase(aid);
2296 for (const auto& [id, lnk] : GetLinks())
2297 {
2298 auto& link = GetLink(id);
2299 link.staList.erase(aid);
2300 }
2301 }
2302}
2303
2304void
2306{
2307 NS_LOG_FUNCTION(this << *mpdu << linkId);
2308
2309 Mac48Address staAddr = mpdu->GetHeader().GetAddr2();
2310 bool staInPsMode = GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr);
2311
2312 if (!staInPsMode && mpdu->GetHeader().IsPowerManagement())
2313 {
2314 // the sending STA is switching to Power Save mode
2315 StaSwitchingToPsMode(staAddr, linkId);
2316 }
2317 else if (staInPsMode && !mpdu->GetHeader().IsPowerManagement())
2318 {
2319 // the sending STA is switching back to Active mode
2321 }
2322}
2323
2324void
2325ApWifiMac::StaSwitchingToPsMode(const Mac48Address& staAddr, uint8_t linkId)
2326{
2327 NS_LOG_FUNCTION(this << staAddr << linkId);
2328
2329 auto rsm = GetWifiRemoteStationManager(linkId);
2330 if (rsm->IsInPsMode(staAddr))
2331 {
2332 NS_LOG_DEBUG(staAddr << " is already in PS mode, nothing to do");
2333 return;
2334 }
2335
2336 rsm->SetPsMode(staAddr, true);
2337
2338 // Block frames addressed to the STA in PS mode
2339 NS_LOG_DEBUG("Block destination " << staAddr << " on link " << +linkId);
2340 auto staMldAddr = rsm->GetMldAddress(staAddr).value_or(staAddr);
2342
2343 if (GetLink(linkId).nStationsInPsMode++ == 0)
2344 {
2345 // this is the first associated STA switching to PS mode. Group addressed frames shall be
2346 // sent after Beacon frames including a DTIM
2347 NS_LOG_DEBUG("Block transmission of group addressed frames on link " << +linkId);
2349 {linkId},
2351 // do not block transmission of Beacon frames
2353 AC_BEACON,
2356 GetFrameExchangeManager(linkId)->GetAddress());
2357 }
2358}
2359
2360void
2362{
2363 NS_LOG_FUNCTION(this << staAddr << linkId);
2364
2365 if (!GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr))
2366 {
2367 NS_LOG_DEBUG(staAddr << " is already in active mode, nothing to do");
2368 return;
2369 }
2370
2371 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, false);
2372
2373 // unblock transmissions to the station
2374 NS_LOG_DEBUG("Unblock destination " << staAddr << " on link " << +linkId);
2375 auto staMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
2377
2378 if (--GetLink(linkId).nStationsInPsMode == 0)
2379 {
2380 // the last STA in PS mode switched back to active mode or deassociated. No need to
2381 // keep blocking group addressed frames
2382 NS_LOG_DEBUG("Unblock transmission of group addressed frames on link " << +linkId);
2384 {linkId},
2386 }
2387}
2388
2389std::size_t
2391{
2392 return GetLink(linkId).nStationsInPsMode;
2393}
2394
2395std::optional<uint8_t>
2397{
2398 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
2399 {
2400 if (GetWifiRemoteStationManager(linkId)->IsAssociated(address))
2401 {
2402 return linkId;
2403 }
2404 }
2405 NS_LOG_DEBUG(address << " is not associated");
2406 return std::nullopt;
2407}
2408
2411{
2412 auto linkId = IsAssociated(remoteAddr);
2413 NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
2414 return GetFrameExchangeManager(*linkId)->GetAddress();
2415}
2416
2417std::optional<Mac48Address>
2419{
2420 if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
2421 staIt != m_aidToMldOrLinkAddress.cend())
2422 {
2423 return staIt->second;
2424 }
2425 return std::nullopt;
2426}
2427
2428void
2430{
2431 NS_LOG_FUNCTION(this << *mpdu << +linkId);
2432 // consider the MAC header of the original MPDU (makes a difference for data frames only)
2433 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
2434 Ptr<const Packet> packet = mpdu->GetPacket();
2435 Mac48Address from = hdr->GetAddr2();
2436 if (hdr->IsData())
2437 {
2438 std::optional<uint8_t> apLinkId;
2439 if (!hdr->IsFromDs() && hdr->IsToDs() &&
2440 (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
2441 mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
2442 {
2443 // this MPDU is being acknowledged by the AP, so we can process
2444 // the Power Management flag
2445 ProcessPowerManagementFlag(mpdu, *apLinkId);
2446
2447 Mac48Address to = hdr->GetAddr3();
2448 // Address3 can be our MLD/link address (e.g., this is an MPDU containing a single MSDU
2449 // addressed to us and the sender is an MLD/SLD) or a BSSID (e.g., this is an MPDU
2450 // containing an A-MSDU)
2451 if (to == GetAddress() || to == GetLocalAddress(from) ||
2452 (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
2453 {
2454 NS_LOG_DEBUG("frame for me from=" << from);
2455 if (hdr->IsQosData())
2456 {
2457 if (hdr->IsQosAmsdu())
2458 {
2459 NS_LOG_DEBUG("Received A-MSDU from=" << from
2460 << ", size=" << packet->GetSize());
2462 packet = nullptr;
2463 }
2464 else if (hdr->HasData())
2465 {
2466 ForwardUp(packet, from, GetAddress());
2467 }
2468 }
2469 else if (hdr->HasData())
2470 {
2471 ForwardUp(packet, from, GetAddress());
2472 }
2473 }
2474 else if (to.IsGroup() || IsAssociated(to))
2475 {
2476 NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
2477 Ptr<Packet> copy = packet->Copy();
2478
2479 // If the frame we are forwarding is of type QoS Data,
2480 // then we need to preserve the UP in the QoS control
2481 // header...
2482 if (hdr->IsQosData())
2483 {
2484 WifiMac::Enqueue(copy, to, from, hdr->GetQosTid());
2485 }
2486 else
2487 {
2488 WifiMac::Enqueue(copy, to, from);
2489 }
2490 ForwardUp(packet, from, to);
2491 }
2492 else if (hdr->HasData())
2493 {
2494 ForwardUp(packet, from, to);
2495 }
2496 }
2497 // NOLINTBEGIN(bugprone-branch-clone)
2498 else if (hdr->IsFromDs() && hdr->IsToDs())
2499 {
2500 // this is an AP-to-AP frame
2501 // we ignore for now.
2502 NotifyRxDrop(packet);
2503 }
2504 // NOLINTEND(bugprone-branch-clone)
2505 else
2506 {
2507 // we can ignore these frames since
2508 // they are not targeted at the AP
2509 NotifyRxDrop(packet);
2510 }
2511 return;
2512 }
2513 else if (hdr->IsMgt())
2514 {
2515 if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress() &&
2517 {
2518 // this MPDU is being acknowledged by the AP, so we can process
2519 // the Power Management flag
2520 ProcessPowerManagementFlag(mpdu, linkId);
2521 }
2522 if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
2523 hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
2524 {
2525 // In the case where the Address 1 field contains a group address, the
2526 // Address 3 field also is validated to verify that the group addressed
2527 // frame originated from a STA in the BSS of which the receiving STA is
2528 // a member (Section 9.3.3.1 of 802.11-2020)
2529 if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
2530 hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
2531 {
2532 // not addressed to us
2533 return;
2534 }
2535 MgtProbeRequestHeader probeRequestHeader;
2536 packet->PeekHeader(probeRequestHeader);
2537 const auto& ssid = probeRequestHeader.Get<Ssid>();
2538 if (ssid == GetSsid() || ssid->IsBroadcast())
2539 {
2540 NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
2541 const auto isReqBcast = hdr->GetAddr1().IsGroup() && hdr->GetAddr3().IsBroadcast();
2542 // not an ML Probe Request if ADDR1 and ADDR3 are broadcast
2543 const auto probeResp = GetProbeResp(
2544 linkId,
2545 isReqBcast ? std::nullopt : probeRequestHeader.Get<MultiLinkElement>());
2546 EnqueueProbeResp(probeResp, from, linkId);
2547 }
2548 return;
2549 }
2550 else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
2551 {
2552 switch (hdr->GetType())
2553 {
2556 NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
2557 << " request received from " << from
2558 << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
2559
2560 MgtAssocRequestHeader assocReq;
2561 MgtReassocRequestHeader reassocReq;
2562 AssocReqRefVariant frame = assocReq;
2563 if (hdr->IsAssocReq())
2564 {
2565 packet->PeekHeader(assocReq);
2566 }
2567 else
2568 {
2569 packet->PeekHeader(reassocReq);
2570 frame = reassocReq;
2571 }
2572 if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
2573 {
2574 ParseReportedStaInfo(frame, from, linkId);
2575 }
2576 SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
2577 return;
2578 }
2580 NS_LOG_DEBUG("Disassociation received from " << from);
2581 const auto aid = GetAssociationId(from, linkId);
2582 if (aid == SU_STA_ID)
2583 {
2584 NS_LOG_DEBUG("Station " << from << " is not associated");
2585 return;
2586 }
2587 const auto address =
2588 GetWifiRemoteStationManager(linkId)->GetMldAddress(from).value_or(from);
2589 m_deAssocLogger(aid, address);
2590 if (m_gcrManager)
2591 {
2592 m_gcrManager->NotifyStaDeassociated(address);
2593 }
2594
2595 for (const auto& [id, lnk] : GetLinks())
2596 {
2597 auto& link = GetLink(id);
2598 auto it = link.staList.find(aid);
2599
2600 if (it == link.staList.cend())
2601 {
2602 continue; // STA has not setup this link
2603 }
2604
2605 // a STA operating on this link is associated with the AP
2607 link.staList.erase(it);
2608 m_aidToMldOrLinkAddress.erase(aid);
2609 GetWifiRemoteStationManager(id)->RecordDisassociated(address);
2611 !GetWifiRemoteStationManager(id)->GetErpOfdmSupported(address))
2612 {
2613 link.numNonErpStations--;
2614 }
2615 if (!GetWifiRemoteStationManager(id)->GetHtSupported(address) &&
2616 !GetWifiRemoteStationManager(id)->GetStationHe6GhzCapabilities(address))
2617 {
2618 link.numNonHtStations--;
2619 }
2622 }
2623 return;
2624 }
2625 case WIFI_MAC_MGT_ACTION: {
2626 auto pkt = mpdu->GetPacket()->Copy();
2627 auto [category, action] = WifiActionHeader::Remove(pkt);
2628 if (category == WifiActionHeader::PROTECTED_EHT &&
2629 action.protectedEhtAction ==
2631 IsAssociated(hdr->GetAddr2()))
2632 {
2633 // received an EML Operating Mode Notification frame from an associated station
2634 MgtEmlOmn frame;
2635 pkt->RemoveHeader(frame);
2636 ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
2637 RespondToEmlOmn(frame, hdr->GetAddr2(), linkId);
2638 return;
2639 }
2640 break;
2641 }
2642 default:;
2643 // do nothing
2644 }
2645 }
2646 }
2647
2648 // Invoke the receive handler of our parent class to deal with any other frames
2649 WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
2650}
2651
2652bool
2654 const Mac48Address& from,
2655 uint8_t linkId)
2656{
2657 NS_LOG_FUNCTION(this << from << +linkId);
2658
2659 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
2660
2661 auto failure = [&](const std::string& msg) -> bool {
2662 NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
2663 remoteStationManager->RecordAssocRefused(from);
2664 return false;
2665 };
2666
2667 // lambda to process received (Re)Association Request
2668 auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
2669 const auto& frame = frameRefWrapper.get();
2670
2671 // first, verify that the the station's supported
2672 // rate set is compatible with our Basic Rate set
2673 const CapabilityInformation& capabilities = frame.m_capability;
2674 remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
2675 NS_ASSERT(frame.template Get<SupportedRates>());
2676 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
2677 frame.template Get<ExtendedSupportedRatesIE>()};
2678
2679 if (rates.GetNRates() == 0)
2680 {
2681 return failure("STA's supported rate set not compatible with our Basic Rate set");
2682 }
2683
2684 if (GetHtSupported(linkId))
2685 {
2686 // check whether the HT STA supports all MCSs in Basic MCS Set
2687 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2688 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
2689 {
2690 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2691 {
2692 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2693 if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
2694 {
2695 return failure("HT STA does not support all MCSs in Basic MCS Set");
2696 }
2697 }
2698 }
2699 }
2700 if (GetVhtSupported(linkId))
2701 {
2702 // check whether the VHT STA supports all MCSs in Basic MCS Set
2703 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2704 if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
2705 {
2706 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2707 {
2708 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2709 if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2710 {
2711 return failure("VHT STA does not support all MCSs in Basic MCS Set");
2712 }
2713 }
2714 }
2715 }
2716 if (GetHeSupported())
2717 {
2718 // check whether the HE STA supports all MCSs in Basic MCS Set
2719 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2720 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2721 {
2722 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2723 {
2724 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2725 if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2726 {
2727 return failure("HE STA does not support all MCSs in Basic MCS Set");
2728 }
2729 }
2730 }
2731 if (Is6GhzBand(linkId))
2732 {
2733 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
2734 {
2735 remoteStationManager->AddStationHe6GhzCapabilities(from, *he6GhzCapabilities);
2736 }
2737 }
2738 }
2739 if (GetEhtSupported())
2740 {
2741 // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
2742 auto ehtConfig = GetEhtConfiguration();
2743 NS_ASSERT(ehtConfig);
2744
2745 if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
2746 !tidLinkMapping.empty())
2747 {
2748 // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
2749 // We refuse association if we do not support TID-to-Link mapping negotiation
2750 // or the non-AP MLD included more than two TID-to-Link Mapping IEs
2751 // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
2752 // or there is some TID that is not mapped to any link
2753 // or the direction(s) is/are not set properly
2754 if (tidLinkMapping.size() > 2)
2755 {
2756 return failure("More than two TID-to-Link Mapping IEs");
2757 }
2758
2759 // if only one Tid-to-Link Mapping element is present, it must be valid for
2760 // both directions
2761 bool bothDirIfOneTlm =
2762 tidLinkMapping.size() != 1 ||
2763 tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
2764 // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
2765 // Request frame or a (Re)Association Response frame shall set the Direction
2766 // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
2767 // subfield in the other TID-To- Link Mapping element to 1.
2768 // (Sec. 35.3.7.1.8 of 802.11be D3.1)
2769 bool distinctDirsIfTwoTlms =
2770 tidLinkMapping.size() != 2 ||
2771 (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2772 tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2773 tidLinkMapping[0].m_control.direction !=
2774 tidLinkMapping[1].m_control.direction);
2775
2776 if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
2777 {
2778 return failure("Incorrect directions in TID-to-Link Mapping IEs");
2779 }
2780
2781 if (ehtConfig->m_tidLinkMappingSupport ==
2783 {
2784 return failure("TID-to-Link Mapping negotiation not supported");
2785 }
2786
2787 auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
2788 if (tlmIe.m_control.defaultMapping)
2789 {
2790 return;
2791 }
2792 for (uint8_t tid = 0; tid < 8; tid++)
2793 {
2794 if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
2795 {
2796 mapping.emplace(tid, std::move(linkSet));
2797 }
2798 }
2799 };
2800
2801 WifiTidLinkMapping dlMapping;
2802 WifiTidLinkMapping ulMapping;
2803
2804 switch (tidLinkMapping[0].m_control.direction)
2805 {
2807 getMapping(tidLinkMapping.at(0), dlMapping);
2808 ulMapping = dlMapping;
2809 break;
2811 getMapping(tidLinkMapping.at(0), dlMapping);
2812 getMapping(tidLinkMapping.at(1), ulMapping);
2813 break;
2815 getMapping(tidLinkMapping.at(0), ulMapping);
2816 getMapping(tidLinkMapping.at(1), dlMapping);
2817 break;
2818 }
2819
2820 if (ehtConfig->m_tidLinkMappingSupport ==
2822 !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
2823 {
2824 return failure("Mapping TIDs to distinct link sets is incompatible with "
2825 "negotiation support of 1");
2826 }
2827
2828 // otherwise, we accept the TID-to-link Mapping and store it
2829 const auto& mle = frame.template Get<MultiLinkElement>();
2830 NS_ASSERT_MSG(mle,
2831 "Multi-Link Element not present in an Association Request including "
2832 "TID-to-Link Mapping element(s)");
2833 auto mldAddr = mle->GetMldMacAddress();
2834
2835 // The requested link mappings are valid and can be accepted; store them.
2837 UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
2838 }
2839 }
2840
2841 // The association request from the station can be accepted.
2842 // Record all its supported modes in its associated WifiRemoteStation
2843 auto phy = GetWifiPhy(linkId);
2844
2845 for (const auto& mode : phy->GetModeList())
2846 {
2847 if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
2848 {
2849 remoteStationManager->AddSupportedMode(from, mode);
2850 }
2851 }
2852 if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
2853 capabilities.IsShortSlotTime())
2854 {
2855 remoteStationManager->AddSupportedErpSlotTime(from, true);
2856 }
2857 if (GetHtSupported(linkId))
2858 {
2859 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2860 if (htCapabilities.has_value())
2861 {
2862 remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
2863 }
2864 const auto& extendedCapabilities = frame.template Get<ExtendedCapabilities>();
2865 if (extendedCapabilities.has_value())
2866 {
2867 remoteStationManager->AddStationExtendedCapabilities(from, *extendedCapabilities);
2868 }
2869 }
2870 if (GetVhtSupported(linkId))
2871 {
2872 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2873 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
2874 // to check whether it supports VHT
2875 if (vhtCapabilities.has_value() &&
2876 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
2877 {
2878 remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
2879 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
2880 {
2881 if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2882 {
2883 remoteStationManager->AddSupportedMcs(from, mcs);
2884 // here should add a control to add basic MCS when it is implemented
2885 }
2886 }
2887 }
2888 }
2889 if (GetHeSupported())
2890 {
2891 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2892 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2893 {
2894 remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
2895 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
2896 {
2897 if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2898 {
2899 remoteStationManager->AddSupportedMcs(from, mcs);
2900 // here should add a control to add basic MCS when it is implemented
2901 }
2902 }
2903 }
2904 }
2905 if (GetEhtSupported())
2906 {
2907 if (const auto& ehtCapabilities = frame.template Get<EhtCapabilities>())
2908 {
2909 remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
2910 }
2911 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
2912 {
2913 // TODO: Add check whether MCS is supported from the capabilities
2914 remoteStationManager->AddSupportedMcs(from, mcs);
2915 // here should add a control to add basic MCS when it is implemented
2916 }
2917 }
2918
2919 NS_LOG_DEBUG("Association Request from " << from << " accepted");
2920 remoteStationManager->RecordWaitAssocTxOk(from);
2921 return true;
2922 };
2923
2924 return std::visit(recvAssocRequest, assoc);
2925}
2926
2927void
2929{
2930 NS_LOG_FUNCTION(this << from << +linkId);
2931
2932 // lambda to process received Multi-Link Element
2933 auto recvMle = [&](auto&& frame) {
2934 const auto& mle = frame.get().template Get<MultiLinkElement>();
2935
2936 if (!mle.has_value())
2937 {
2938 return;
2939 }
2940
2941 auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
2942 GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
2943
2944 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
2945 {
2946 auto& perStaProfile = mle->GetPerStaProfile(i);
2947 if (!perStaProfile.HasStaMacAddress())
2948 {
2949 NS_LOG_DEBUG("[i=" << i
2950 << "] Cannot setup a link if the STA MAC address is missing");
2951 continue;
2952 }
2953 uint8_t newLinkId = perStaProfile.GetLinkId();
2954 if (newLinkId == linkId || newLinkId >= GetNLinks())
2955 {
2956 NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
2957 continue;
2958 }
2959 if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
2960 {
2961 NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
2962 continue;
2963 }
2964
2965 ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
2966 perStaProfile.GetStaMacAddress(),
2967 newLinkId);
2968 GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
2969 perStaProfile.GetStaMacAddress(),
2970 mleCommonInfo);
2971 }
2972 };
2973
2974 std::visit(recvMle, assoc);
2975}
2976
2977void
2978ApWifiMac::ReceiveEmlOmn(const MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
2979{
2980 NS_LOG_FUNCTION(this << frame << sender << linkId);
2981
2982 auto ehtConfiguration = GetEhtConfiguration();
2983
2984 if (!ehtConfiguration || !ehtConfiguration->m_emlsrActivated)
2985 {
2987 "Received an EML Operating Mode Notification frame but EMLSR is not activated");
2988 return;
2989 }
2990
2992 {
2994 auto emlCapabilities =
2995 GetWifiRemoteStationManager(linkId)->GetStationEmlCapabilities(sender);
2996 NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
2997
2998 // update values stored in remote station manager
2999 emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
3000 emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
3001 }
3002}
3003
3004void
3005ApWifiMac::RespondToEmlOmn(MgtEmlOmn frame, const Mac48Address& sender, uint8_t linkId)
3006{
3007 NS_LOG_FUNCTION(this << frame << sender << linkId);
3008
3009 // The AP MLD has to consider the changes carried by the received EML Notification frame
3010 // as effective at the same time as the non-AP MLD. Therefore, we need to start a time
3011 // when the transmission of the Ack following the received EML Notification frame is
3012 // completed. For this purpose, we connect a callback to the PHY TX begin trace to catch
3013 // the Ack transmitted after the EML Notification frame.
3015 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
3016 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
3017 psduMap.begin()->second->GetHeader(0).IsAck(),
3018 "Expected a Normal Ack after EML Notification frame");
3019
3020 auto ackDuration =
3021 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
3022
3024 Simulator::Schedule(ackDuration + GetEhtConfiguration()->m_transitionTimeout,
3026 this,
3027 frame,
3028 sender,
3029 linkId);
3030 });
3031
3032 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
3033 // after its transmission begins
3034 auto phy = GetLink(linkId).phy;
3035 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
3036 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
3037 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
3038
3039 // An AP MLD with dot11EHTEMLSROptionActivated equal to true sets the EMLSR Mode subfield
3040 // to the value obtained from the EMLSR Mode subfield of the received EML Operating Mode
3041 // Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
3042
3043 // When included in a frame sent by an AP affiliated with an AP MLD, the EMLSR Parameter
3044 // Update Control subfield is set to 0. (Sec. 9.6.35.8 of 802.11be D3.0)
3046
3047 // An AP MLD with dot11EHTEMLSROptionImplemented equal to true sets the EMLSR Link Bitmap
3048 // subfield to the value obtained from the EMLSR Link Bitmap subfield of the received
3049 // EML Operating Mode Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
3050
3051 // The EMLSR Parameter Update field [..] is present if [..] the Action frame is sent by
3052 // a non-AP STA affiliated with a non-AP MLD (Sec. 9.6.35.8 of 802.11be D3.0)
3053 frame.m_emlsrParamUpdate.reset();
3054
3056 ehtFem->SendEmlOmn(sender, frame);
3057}
3058
3059void
3061 const Mac48Address& sender,
3062 uint8_t linkId)
3063{
3064 NS_LOG_FUNCTION(this << frame << sender << linkId);
3065
3066 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
3067 NS_ASSERT_MSG(mldAddress, "No MLD address stored for STA " << sender);
3068 auto emlsrLinks =
3069 frame.m_emlControl.emlsrMode == 1 ? frame.GetLinkBitmap() : std::list<uint8_t>{};
3070
3071 for (uint8_t id = 0; id < GetNLinks(); id++)
3072 {
3073 auto linkAddress = GetWifiRemoteStationManager(id)->GetAffiliatedStaAddress(*mldAddress);
3074 if (!linkAddress)
3075 {
3076 // this link has not been setup by the non-AP MLD
3077 continue;
3078 }
3079
3080 if (!emlsrLinks.empty())
3081 {
3082 // the non-AP MLD is enabling EMLSR mode
3083 /**
3084 * After the successful transmission of the EML Operating Mode
3085 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
3086 * the non-AP MLD shall operate in the EMLSR mode and the other non-AP
3087 * STAs operating on the corresponding EMLSR links shall transition to
3088 * active mode after the transition delay indicated in the Transition
3089 * Timeout subfield in the EML Capabilities subfield of the Basic
3090 * Multi-Link element or immediately after receiving an EML Operating
3091 * Mode Notification frame from one of the APs operating on the EMLSR
3092 * links and affiliated with the AP MLD (Sec. 35.3.17 of 802.11be D3.0)
3093 */
3094 auto enabled =
3095 std::find(emlsrLinks.cbegin(), emlsrLinks.cend(), id) != emlsrLinks.cend();
3096 if (enabled)
3097 {
3099 }
3100 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, enabled);
3101 }
3102 else
3103 {
3104 // the non-AP MLD is disabling EMLSR mode
3105 /**
3106 * After the successful transmission of the EML Operating Mode
3107 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
3108 * the non-AP MLD shall disable the EMLSR mode and the other non-AP
3109 * STAs operating on the corresponding EMLSR links shall transition to
3110 * power save mode after the transition delay indicated in the
3111 * Transition Timeout subfield in the EML Capabilities subfield of the
3112 * Basic Multi-Link element or immediately after receiving an EML
3113 * Operating Mode Notification frame from one of the APs operating on
3114 * the EMLSR links and affiliated with the AP MLD. (Sec. 35.3.17 of
3115 * 802.11be D3.0)
3116 */
3117 if (id != linkId && GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*linkAddress))
3118 {
3119 StaSwitchingToPsMode(*linkAddress, id);
3120 }
3121 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, false);
3122 }
3123 }
3124}
3125
3126void
3128{
3129 NS_LOG_FUNCTION(this << *mpdu);
3130 for (auto& i : *PeekPointer(mpdu))
3131 {
3132 auto from = i.second.GetSourceAddr();
3133 auto to = i.second.GetDestinationAddr();
3134
3135 if (to.IsGroup() || IsAssociated(to))
3136 {
3137 NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
3138 WifiMac::Enqueue(i.first->Copy(), to, from, mpdu->GetHeader().GetQosTid());
3139 }
3140
3141 ForwardUp(i.first, from, to);
3142 }
3143}
3144
3145void
3147{
3148 NS_LOG_FUNCTION(this);
3149 m_beaconTxop->Initialize();
3150
3151 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
3152 {
3153 GetLink(linkId).beaconEvent.Cancel();
3155 {
3156 uint64_t jitterUs{0};
3158 {
3159 const auto value = m_beaconJitter->GetValue();
3160 NS_ABORT_MSG_IF(value < 0 || value > 1,
3161 "Jitter (" << value << ") must be between 0 and 1");
3162 jitterUs = static_cast<uint64_t>(value * (GetBeaconInterval().GetMicroSeconds()));
3163 }
3164
3165 NS_LOG_DEBUG("Scheduling initial beacon for access point "
3166 << GetAddress() << " at time " << jitterUs << "us");
3169 this,
3170 linkId);
3171 }
3174 }
3175
3176 if (m_gcrManager)
3177 {
3178 m_gcrManager->Initialize();
3179 }
3180
3185}
3186
3187bool
3189{
3190 bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
3191 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
3192 return useProtection;
3193}
3194
3195uint16_t
3197{
3198 const auto& links = GetLinks();
3199
3200 // if this is an AP MLD, AIDs from 1 to N, where N is 2^(Group_addr_BU_Indic_Exp + 1) - 1
3201 // shall not be allocated (see Section 35.3.15.1 of 802.11be D7.0)
3202 const uint16_t startAid = links.size() == 1 ? MIN_AID : (1 << (m_grpAddrBuIndicExp + 1));
3203
3204 // Return the first AID value between min and max that is free for all the links
3205 const auto maxAid = GetEhtSupported() ? EHT_MAX_AID : MAX_AID;
3206 for (uint16_t nextAid = startAid; nextAid <= maxAid; ++nextAid)
3207 {
3208 if (std::none_of(links.cbegin(), links.cend(), [&](auto&& idLinkPair) {
3209 return GetStaList(idLinkPair.first).contains(nextAid);
3210 }))
3211 {
3212 return nextAid;
3213 }
3214 }
3215 NS_FATAL_ERROR("No free association ID available!");
3216 return 0;
3217}
3218
3219const std::map<uint16_t, Mac48Address>&
3220ApWifiMac::GetStaList(uint8_t linkId) const
3221{
3222 return GetLink(linkId).staList;
3223}
3224
3225uint16_t
3227{
3228 return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
3229}
3230
3231uint8_t
3232ApWifiMac::GetBufferStatus(uint8_t tid, Mac48Address address) const
3233{
3234 auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
3235 if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
3236 {
3237 return 255;
3238 }
3239 return it->second.value;
3240}
3241
3242void
3243ApWifiMac::SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
3244{
3245 if (size == 255)
3246 {
3247 // no point in storing an unspecified size
3248 m_bufferStatus.erase(WifiAddressTidPair(address, tid));
3249 }
3250 else
3251 {
3252 m_bufferStatus[WifiAddressTidPair(address, tid)] = {size, Simulator::Now()};
3253 }
3254}
3255
3256uint8_t
3258{
3259 uint8_t maxSize = 0;
3260 bool found = false;
3261
3262 for (uint8_t tid = 0; tid < 8; tid++)
3263 {
3264 uint8_t size = GetBufferStatus(tid, address);
3265 if (size != 255)
3266 {
3267 maxSize = std::max(maxSize, size);
3268 found = true;
3269 }
3270 }
3271
3272 if (found)
3273 {
3274 return maxSize;
3275 }
3276 return 255;
3277}
3278
3279bool
3281 uint8_t tid) const
3282{
3284 return GetQosTxop(tid)->GetBaManager()->IsGcrAgreementEstablished(
3285 groupAddress,
3286 tid,
3287 m_gcrManager->GetMemberStasForGroupAddress(groupAddress));
3288}
3289
3290} // namespace ns3
Wi-Fi AP state machine.
Definition ap-wifi-mac.h:62
void SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
Forward an association or a reassociation response packet to the DCF/EDCA.
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
std::unique_ptr< LinkEntity > CreateLinkEntity() const override
Create a LinkEntity object.
void RespondToEmlOmn(MgtEmlOmn frame, const Mac48Address &sender, uint8_t linkId)
Respond to the EML Operating Mode Notification frame received from the given station on the given lin...
Ptr< Txop > m_beaconTxop
Dedicated Txop for beacons.
void SetBeaconGeneration(bool enable)
Enable or disable beacon generation of the AP.
void ParseReportedStaInfo(const AssocReqRefVariant &assoc, Mac48Address from, uint8_t linkId)
Given a (Re)Association Request frame body containing a Multi-Link Element, check if a link can be se...
void UpdateShortSlotTimeEnabled(uint8_t linkId)
Update whether short slot time should be enabled or not in the BSS corresponding to the given link.
void DoCompleteConfig() override
Allow subclasses to complete the configuration of the MAC layer components.
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId) const
Get a const reference to the map of associated stations on the given link.
void DoDispose() override
Destructor implementation.
void SetBeaconInterval(Time interval)
bool ReceiveAssocRequest(const AssocReqRefVariant &assoc, const Mac48Address &from, uint8_t linkId)
Check whether the supported rate set included in the received (Re)Association Request frame is compat...
std::map< uint8_t, Mac48Address > LinkIdStaAddrMap
Map of (link ID, remote STA address) of the links to setup.
Ptr< RandomVariableStream > m_beaconJitter
UniformRandomVariable used to randomize the time of the first beacon.
std::map< Mac48Address, EventId > m_transitionTimeoutEvents
transition timeout events running for EMLSR clients
UintAccessParamsMap m_cwMaxsForSta
Per-AC CW max values to advertise to stations.
void ScheduleFilsDiscOrUnsolProbeRespFrames(uint8_t linkId)
Schedule the transmission of FILS Discovery frames or unsolicited Probe Response frames on the given ...
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...
CapabilityInformation GetCapabilities(uint8_t linkId) const
Return the Capability information of the current AP for the given link.
Ptr< ApEmlsrManager > m_apEmlsrManager
AP EMLSR Manager.
Ptr< WifiMpdu > GetBufferedMmpduFor(Mac48Address address, uint8_t linkId=WIFI_LINKID_UNDEFINED) const
Check whether the AP MLD has buffered MMPDUs for the given destination because non-AP STAs operating ...
void EnqueueProbeResp(const MgtProbeResponseHeader &probeResp, Mac48Address to, uint8_t linkId)
Send a packet prepared using the given Probe Response to the given receiver on the given link.
void TxGroupAddrFramesAfterDtim(uint8_t linkId, WifiConstPsduMap psduMap, WifiTxVector, Watt_u)
This function is connected to the PhyTxPsduBegin PHY trace source when enqueuing a Beacon frame conta...
bool CanForwardPacketsTo(Mac48Address to) const override
Return true if packets can be forwarded to the given destination, false otherwise.
bool m_enableNonErpProtection
Flag whether protection mechanism is used or not when non-ERP STAs are present within the BSS.
bool HasMoreDataAfter(Ptr< const WifiMpdu > mpdu, uint8_t linkId) const
Return whether at least one additional buffered unit is present for the same STA after transmitting t...
uint8_t m_dtimPeriod
DTIM Period.
EdcaParameterSet GetEdcaParameterSet(uint8_t linkId) const
Return the EDCA Parameter Set of the current AP for the given link.
void StaSwitchingToActiveModeOrDeassociated(const Mac48Address &staAddr, uint8_t linkId)
Perform the necessary actions when a given station that is in powersave mode deassociates or switches...
HtOperation GetHtOperation(uint8_t linkId) const
Return the HT operation of the current AP for the given link.
std::optional< Mac48Address > GetMldOrLinkAddressByAid(uint16_t aid) const
Ptr< GcrManager > m_gcrManager
GCR Manager.
void UpdateShortPreambleEnabled(uint8_t linkId)
Update whether short preamble should be enabled or not in the BSS corresponding to the given link.
uint16_t GetNextAssociationId() const
void TxOk(Ptr< const WifiMpdu > mpdu)
The packet we sent was successfully received by the receiver (i.e.
Time m_fdBeaconIntervalNon6GHz
Time elapsing between a beacon and FILS Discovery (FD) frame or between two FD frames on 2....
Tim GetTim(uint8_t linkId) const
Return the TIM for the current AP to transmit on the given link.
std::map< uint16_t, Mac48Address > m_aidToMldOrLinkAddress
Maps AIDs to MLD addresses (for MLDs) or link addresses (in case of single link devices).
TracedCallback< uint16_t, Mac48Address > m_deAssocLogger
deassociation logger
void Enqueue(Ptr< WifiMpdu > mpdu, Mac48Address to, Mac48Address from) override
LinkIdStaAddrMap GetLinkIdStaAddrMap(MgtAssocResponseHeader &assoc, const Mac48Address &to, uint8_t linkId)
Get a map of (link ID, remote STA address) of the links to setup.
void SetAid(MgtAssocResponseHeader &assoc, const LinkIdStaAddrMap &linkIdStaAddrMap)
Set the AID field of the given Association Response frame.
void EmlOmnExchangeCompleted(const MgtEmlOmn &frame, const Mac48Address &sender, uint8_t linkId)
Take necessary actions upon completion of an exchange of EML Operating Mode Notification frames.
static Ptr< const AttributeChecker > GetTimeAccessParamsChecker()
Get a checker for the TxopLimitsForSta attribute, which can be used to deserialize an ACI-indexed map...
bool m_enableBeaconGeneration
Flag whether beacons are being generated.
Time m_beaconInterval
Beacon interval.
Ptr< GcrManager > GetGcrManager() const
MultiLinkElement GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac48Address &to=Mac48Address::GetBroadcast(), const std::optional< MultiLinkElement > &mlProbeReqMle=std::nullopt)
Return the Multi-Link Element that the current AP includes in the management frames of the given type...
bool m_enableBeaconJitter
Flag whether the first beacon should be generated at random time.
std::unordered_map< WifiAddressTidPair, BsrType, WifiAddressTidHash > m_bufferStatus
Per (MAC address, TID) buffer status reports.
DsssParameterSet GetDsssParameterSet(uint8_t linkId) const
Return the DSSS Parameter Set that we support on the given link.
void ReceiveEmlOmn(const MgtEmlOmn &frame, const Mac48Address &sender, uint8_t linkId)
Process the EML Operating Mode Notification frame received from the given station on the given link.
TracedCallback< uint16_t, Mac48Address > m_assocLogger
association logger
uint8_t m_grpAddrBuIndicExp
Group Addressed BU Indication Exponent of EHT Operation IE.
Time GetBeaconInterval() const
static TypeId GetTypeId()
Get the type ID.
std::optional< ReducedNeighborReport > GetReducedNeighborReport(uint8_t linkId) const
Return the Reduced Neighbor Report (RNR) element that the current AP sends on the given link,...
Ptr< ApEmlsrManager > GetApEmlsrManager() const
Time m_fdBeaconInterval6GHz
Time elapsing between a beacon and FILS Discovery (FD) frame or between two FD frames on 6GHz links.
uint8_t GetMaxBufferStatus(Mac48Address address) const
Return the maximum among the values of the Queue Size subfield of the last QoS Data or QoS Null frame...
Time m_bsrLifetime
Lifetime of Buffer Status Reports.
bool HasBufferedGroupcast(uint8_t linkId) const
Check whether the AP MLD has buffered frames with a destination groupcast address to be sent on the g...
ApLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
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...
std::size_t GetNStationsInPsMode(linkId_t linkId) const
Get the number of STAs associated on the given link that are in PowerSave mode.
void CheckGroupAddrFramesAfterDtimDone(uint8_t linkId, Ptr< const WifiMpdu > mpdu=nullptr) const
Check whether the AP is done with the transmission of group addressed frames after a DTIM transmitted...
PairValue< EnumValue< AcIndex >, AttributeContainerValue< TimeValue, ',', std::vector > > TimeAccessParamsPairValue
AttributeValue type of a pair (ACI, access parameters of type Time).
uint8_t GetBufferStatus(uint8_t tid, Mac48Address address) const
Return the value of the Queue Size subfield of the last QoS Data or QoS Null frame received from the ...
EhtOperation GetEhtOperation(uint8_t linkId) const
Return the EHT operation of the current AP for the given link.
bool UseGcr(const WifiMacHeader &hdr) const
Return whether GCR is used to transmit a packet.
bool m_sendUnsolProbeResp
send unsolicited Probe Response instead of FILS Discovery
ErpInformation GetErpInformation(uint8_t linkId) const
Return the ERP information of the current AP for the given link.
void SetLinkUpCallback(Callback< void > linkUp) override
VhtOperation GetVhtOperation(uint8_t linkId) const
Return the VHT operation of the current AP for the given link.
~ApWifiMac() override
Ptr< WifiMpdu > GetBufferedDataFor(Mac48Address address, uint8_t linkId=WIFI_LINKID_UNDEFINED) const
Check whether the AP MLD has buffered (QoS) data frame(s) for the given destination because non-AP ST...
void TxFailed(WifiMacDropReason timeoutReason, Ptr< const WifiMpdu > mpdu)
The packet we sent was successfully received by the receiver (i.e.
HeOperation GetHeOperation(uint8_t linkId) const
Return the HE operation of the current AP for the given link.
bool IsGcrBaAgreementEstablishedWithAllMembers(const Mac48Address &groupAddress, uint8_t tid) const
Check if a GCR Block Ack agreement has been successfully established with all members of its group.
void SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
Store the value of the Queue Size subfield of the last QoS Data or QoS Null frame received from the s...
TimeAccessParamsMap m_txopLimitsForSta
Per-AC TXOP limits values to advertise to stations.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
Ptr< Txop > GetTxopFor(AcIndex ac) const override
Get the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed, or a null pointer,...
std::optional< MuEdcaParameterSet > GetMuEdcaParameterSet() const
Return the MU EDCA Parameter Set of the current AP, if one needs to be advertised.
void ProcessPowerManagementFlag(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Power Management bit in the Frame Control field of an MPDU successfully received on the g...
void DeaggregateAmsduAndForward(Ptr< const WifiMpdu > mpdu) override
This method is called to de-aggregate an A-MSDU and forward the constituent packets up the stack.
bool SupportsSendFrom() const override
MgtAssocResponseHeader GetAssocResp(Mac48Address to, uint8_t linkId)
Get the Association Response frame to send on a given link.
void SetGcrManager(Ptr< GcrManager > gcrManager)
Set the GCR Manager.
Ptr< WifiMpdu > GetFilsDiscovery(uint8_t linkId) const
Get the FILS Discovery frame to send on the given link.
PairValue< EnumValue< AcIndex >, AttributeContainerValue< UintegerValue, ',', std::vector > > UintAccessParamsPairValue
AttributeValue type of a pair (ACI, access parameters of type unsigned integer).
static Ptr< const AttributeChecker > GetUintAccessParamsChecker()
Get a checker for the CwMinsForSta, CwMaxsForSta and AifsnsForSta attributes, which can be used to de...
void DoInitialize() override
Initialize() implementation.
std::optional< uint8_t > IsAssociated(const Mac48Address &address) const
Get the ID of a link (if any) that has been setup with the station having the given MAC address.
void SendOneBeacon(uint8_t linkId)
Forward a beacon packet to the beacon special DCF for transmission on the given link.
void SetApEmlsrManager(Ptr< ApEmlsrManager > apEmlsrManager)
Set the AP EMLSR Manager.
bool GetUseNonErpProtection(uint8_t linkId) const
Return whether protection for non-ERP stations is used in the BSS corresponding to the given link.
MgtProbeResponseHeader GetProbeRespProfile(uint8_t linkId) const
Get Probe Response Per-STA Profile for the given link.
UintAccessParamsMap m_cwMinsForSta
Per-AC CW min values to advertise to stations.
UintAccessParamsMap m_aifsnsForSta
Per-AC AIFS values to advertise to stations.
MgtProbeResponseHeader GetProbeResp(uint8_t linkId, const std::optional< MultiLinkElement > &reqMle)
Get Probe Response based on the given Probe Request Multi-link Element (if any).
void StaSwitchingToPsMode(const Mac48Address &staAddr, uint8_t linkId)
Perform the necessary actions when a given station that is in active mode switches to powersave mode.
AllSupportedRates GetSupportedRates(uint8_t linkId) const
Return an instance of SupportedRates that contains all rates that we support for the given link (incl...
A container for one type of attribute.
Base class for Callback class.
Definition callback.h:347
Callback template class.
Definition callback.h:428
void SetEss()
Set the Extended Service Set (ESS) bit in the capability information field.
bool IsShortSlotTime() const
Check if the short slot time in the capability information field is set to 1.
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.
bool IsShortPreamble() const
Check if the short preamble bit in the capability information field is set to 1.
The DSSS Parameter Set.
void SetCurrentChannel(uint8_t currentChannel)
Set the Current Channel field in the DsssParameterSet information element.
The EDCA Parameter Set.
void SetViTxopLimit(uint16_t txop)
Set the AC_VI TXOP Limit field in the EdcaParameterSet information element.
void SetViAifsn(uint8_t aifsn)
Set the AC_VI AIFSN field in the EdcaParameterSet information element.
void SetVoAci(uint8_t aci)
Set the AC_VO ACI field in the EdcaParameterSet information element.
void SetVoCWmax(uint32_t cwMax)
Set the AC_VO CWmax field in the EdcaParameterSet information element.
void SetViCWmin(uint32_t cwMin)
Set the AC_VI CWmin field in the EdcaParameterSet information element.
void SetVoTxopLimit(uint16_t txop)
Set the AC_VO TXOP Limit field in the EdcaParameterSet information element.
void SetVoAifsn(uint8_t aifsn)
Set the AC_VO AIFSN field in the EdcaParameterSet information element.
void SetQosInfo(uint8_t qosInfo)
Set the QoS Info field in the EdcaParameterSet information element.
void SetBkCWmin(uint32_t cwMin)
Set the AC_BK CWmin field in the EdcaParameterSet information element.
void SetViAci(uint8_t aci)
Set the AC_VI ACI field in the EdcaParameterSet information element.
void SetViCWmax(uint32_t cwMax)
Set the AC_VI CWmax field in the EdcaParameterSet information element.
void SetVoCWmin(uint32_t cwMin)
Set the AC_VO CWmin field in the EdcaParameterSet information element.
void SetBeTxopLimit(uint16_t txop)
Set the AC_BE TXOP Limit field in the EdcaParameterSet information element.
void SetBeCWmax(uint32_t cwMax)
Set the AC_BE CWmax field in the EdcaParameterSet information element.
void SetBeAci(uint8_t aci)
Set the AC_BE ACI field in the EdcaParameterSet information element.
void SetBkCWmax(uint32_t cwMax)
Set the AC_BK CWmax field in the EdcaParameterSet information element.
void SetBkTxopLimit(uint16_t txop)
Set the AC_BK TXOP Limit field in the EdcaParameterSet information element.
void SetBkAifsn(uint8_t aifsn)
Set the AC_BK AIFSN field in the EdcaParameterSet information element.
void SetBeCWmin(uint32_t cwMin)
Set the AC_BE CWmin field in the EdcaParameterSet information element.
void SetBkAci(uint8_t aci)
Set the AC_BK ACI field in the EdcaParameterSet information element.
void SetBeAifsn(uint8_t aifsn)
Set the AC_BE AIFSN field in the EdcaParameterSet information element.
The IEEE 802.11be EHT Capabilities.
EHT Operation Information Element.
void SetMaxTxNss(uint8_t maxNss, uint8_t mcsStart, uint8_t mcsEnd)
Set the max Tx NSS for input MCS index range.
void SetMaxRxNss(uint8_t maxNss, uint8_t mcsStart, uint8_t mcsEnd)
Set the max Rx NSS for input MCS index range.
EhtOpParams m_params
EHT Operation Parameters.
std::optional< EhtOpInfo > m_opInfo
EHT Operation Information.
Hold variables of type enum.
Definition enum.h:52
The ErpInformation Information Element.
void SetBarkerPreambleMode(uint8_t barkerPreambleMode)
Set the Barker_Preamble_Mode field in the ErpInformation information element.
void SetUseProtection(uint8_t useProtection)
Set the Use_Protection field in the ErpInformation information element.
void SetNonErpPresent(uint8_t nonErpPresent)
Set the Non_Erp_Present field in the ErpInformation information element.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
Implement the FILS (Fast Initial Link Setup) action frame.
uint16_t m_beaconInt
Beacon Interval in TU (1024 us).
std::optional< ReducedNeighborReport > m_rnr
Reduced Neighbor Report.
void SetSsid(const std::string &ssid)
Set the SSID field.
OptFieldWithPresenceInd< FdCapability > m_fdCap
FD Capability.
void SetLengthSubfield()
sets value of Length subfield
The HE 6 GHz Band Capabilities (IEEE 802.11ax-2021 9.4.2.263).
The IEEE 802.11ax HE Capabilities.
The HE Operation Information Element.
OptFieldWithPresenceInd< OpInfo6GHz > m_6GHzOpInfo
6 GHz Operation Information field
void SetMaxHeMcsPerNss(uint8_t nss, uint8_t maxHeMcs)
Set the Basic HE-MCS and NSS field in the HE Operation information element by specifying the pair (ns...
BssColorInfo m_bssColorInfo
BSS Color Information field.
The HT Capabilities Information Element.
The HT Operation Information Element.
void SetObssNonHtStasPresent(uint8_t obssNonHtStasPresent)
Set the OBSS non HT STAs present.
void SetRifsMode(uint8_t rifsMode)
Set the RIFS mode.
void SetSecondaryChannelOffset(uint8_t secondaryChannelOffset)
Set the secondary channel offset.
void SetPcoActive(uint8_t pcoActive)
Set the PCO active.
void SetTxUnequalModulation(uint8_t txUnequalModulation)
Set the transmit unequal modulation.
void SetHtProtection(uint8_t htProtection)
Set the HT protection.
void SetTxMaxNSpatialStreams(uint8_t maxTxSpatialStreams)
Set the transmit maximum number spatial streams.
void SetTxRxMcsSetUnequal(uint8_t txRxMcsSetUnequal)
Set the transmit / receive MCS set unequal.
void SetDualBeacon(uint8_t dualBeacon)
Set the dual beacon.
void SetNonGfHtStasPresent(uint8_t nonGfHtStasPresent)
Set the non GF HT STAs present.
void SetTxMcsSetDefined(uint8_t txMcsSetDefined)
Set the transmit MCS set defined.
void SetLSigTxopProtectionFullSupport(uint8_t lSigTxopProtectionFullSupport)
Set the LSIG TXOP protection full support.
void SetStaChannelWidth(uint8_t staChannelWidth)
Set the STA channel width.
void SetRxHighestSupportedDataRate(uint16_t maxSupportedRate)
Set the receive highest supported data rate.
void SetRxMcsBitmask(uint8_t index)
Set the receive MCS bitmask.
void SetPrimaryChannel(uint8_t ctrl)
Set the Primary Channel field in the HT Operation information element.
void SetDualCtsProtection(uint8_t dualCtsProtection)
Set the dual CTS protection.
void SetPhase(uint8_t pcoPhase)
Set the PCO phase.
void SetStbcBeacon(uint8_t stbcBeacon)
Set the STBC beacon.
an EUI-48 address
bool IsGroup() const
static Mac48Address GetBroadcast()
bool IsBroadcast() const
Implement the header for management frames of type association request.
Implement the header for management frames of type association and reassociation response.
StatusCode m_statusCode
Status code.
CapabilityInformation m_capability
Capability information.
Implement the header for management frames of type beacon.
uint64_t m_beaconInterval
Beacon interval (microseconds).
CapabilityInformation m_capability
Capability information.
Implement the header for Action frames of type EML Operating Mode Notification.
EmlControl m_emlControl
EML Control field.
std::optional< EmlsrParamUpdate > m_emlsrParamUpdate
EMLSR Parameter Update field.
std::list< uint8_t > GetLinkBitmap() const
Implement the header for management frames of type probe request.
Implement the header for management frames of type probe response.
uint64_t m_beaconInterval
Beacon interval.
CapabilityInformation m_capability
Capability information.
Implement the header for management frames of type reassociation request.
The MU EDCA Parameter Set.
void SetMuCwMin(uint8_t aci, uint16_t cwMin)
Set the ECWmin subfield of the ECWmin/ECWmax field in the MU AC Parameter Record field corresponding ...
void SetMuEdcaTimer(uint8_t aci, Time timer)
Set the MU EDCA Timer field in the MU AC Parameter Record field corresponding to the given AC Index (...
void SetMuAifsn(uint8_t aci, uint8_t aifsn)
Set the AIFSN subfield of the ACI/AIFSN field in the MU AC Parameter Record field corresponding to th...
void SetQosInfo(uint8_t qosInfo)
Set the QoS Info field in the MuEdcaParameterSet information element.
Time GetMuEdcaTimer(uint8_t aci) const
Get the MU EDCA Timer value encoded in the MU AC Parameter Record field corresponding to the given AC...
void SetMuCwMax(uint8_t aci, uint16_t cwMax)
Set the ECWmax subfield of the ECWmin/ECWmax field in the MU AC Parameter Record field corresponding ...
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
AttributeValue implementation for Pointer.
Definition pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
The Reduced Neighbor Report element.
std::size_t GetNNbrApInfoFields() const
Get the number of Neighbor AP Information fields.
void SetShortSsid(std::size_t nbrApInfoId, std::size_t index, uint32_t shortSsid)
Set the Short SSID field of the i-th TBTT Information field of the given Neighbor AP Information fiel...
void SetBssid(std::size_t nbrApInfoId, std::size_t index, Mac48Address bssid)
Set the BSSID field of the i-th TBTT Information field of the given Neighbor AP Information field.
void SetPsd20MHz(std::size_t nbrApInfoId, std::size_t index, uint8_t psd20MHz)
Set the 20 MHz PSD field of the i-th TBTT Information field of the given Neighbor AP Information fiel...
void AddNbrApInfoField()
Add a Neighbor AP Information field.
void SetBssParameters(std::size_t nbrApInfoId, std::size_t index, uint8_t bssParameters)
Set the BSS Parameters field of the i-th TBTT Information field of the given Neighbor AP Information ...
void SetMldParameters(std::size_t nbrApInfoId, std::size_t index, const MldParameters &mldParams)
Set the MLD Parameters subfield of the i-th TBTT Information field of the given Neighbor AP Informati...
void AddTbttInformationField(std::size_t nbrApInfoId)
Add a TBTT Information fields to the TBTT Information Set field of the given Neighbor AP Information ...
void SetOperatingChannel(std::size_t nbrApInfoId, const WifiPhyOperatingChannel &channel)
Set the Operating Class and the Channel Number fields of the given Neighbor AP Information field base...
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
Status code for association response.
Definition status-code.h:21
bool IsSuccess() const
Return whether the status code is success.
void SetFailure()
Set success bit to 1 (failure).
void SetSuccess()
Set success bit to 0 (success).
Hold variables of type string.
Definition string.h:45
The Supported Rates Information Element.
The Traffic Indication Map Information Element.
Definition tim.h:29
uint8_t m_dtimPeriod
The DTIM Period field.
Definition tim.h:86
uint8_t m_dtimCount
The DTIM Count field.
Definition tim.h:85
void AddAid(uint16_t aid)
Add the provided AID value to the list contained in the Virtual Bitmap.
Definition tim.cc:40
bool m_hasMulticastPending
Whether there is Multicast / Broadcast data.
Definition tim.h:87
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:305
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:408
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
Definition txop.h:413
a unique identifier for an interface.
Definition type-id.h:50
@ ATTR_GET
The attribute can be read.
Definition type-id.h:55
@ ATTR_CONSTRUCT
The attribute can be written at construction-time.
Definition type-id.h:57
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
The IEEE 802.11ac VHT Capabilities.
The VHT Operation Information Element.
void SetMaxVhtMcsPerNss(uint8_t nss, uint8_t maxVhtMcs)
Set the Basic VHT-MCS and NSS field in the VHT Operation information element by specifying the tuple ...
void SetChannelWidth(uint8_t channelWidth)
Set the Channel Width field in the VHT Operation information element.
void SetChannelCenterFrequencySegment1(uint8_t channelCenterFrequencySegment1)
Set the Channel Center Frequency Segment 1 field in the VHT Operation information element.
void SetChannelCenterFrequencySegment0(uint8_t channelCenterFrequencySegment0)
Set the Channel Center Frequency Segment 0 field in the VHT Operation information element.
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
static std::pair< CategoryValue, ActionValue > Peek(Ptr< const Packet > pkt)
Peek an Action header from the given packet.
static std::pair< CategoryValue, ActionValue > Remove(Ptr< Packet > pkt)
Remove an Action header from the given packet.
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
bool IsAssocReq() const
Return true if the header is an Association Request header.
bool IsProbeReq() const
Return true if the header is a Probe Request header.
bool IsQosAmsdu() const
Check if IsQosData() is true and the A-MSDU present bit is set in the QoS control field.
Mac48Address GetAddr3() const
Return the address in the Address 3 field.
bool IsAssocResp() const
Return true if the header is an Association Response header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
virtual WifiMacType GetType() const
Return the type (WifiMacType).
bool IsMgt() const
Return true if the Type is Management.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsAction() const
Return true if the header is an Action header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
bool IsReassocReq() const
Return true if the header is a Reassociation Request header.
bool IsData() const
Return true if the Type is DATA.
bool IsReassocResp() const
Return true if the header is a Reassociation Response header.
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.
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:1034
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition wifi-mac.cc:652
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition wifi-mac.cc:1878
Ptr< HeConfiguration > GetHeConfiguration() const
Definition wifi-mac.cc:2000
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition wifi-mac.cc:1111
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition wifi-mac.cc:572
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition wifi-mac.cc:2280
bool GetQosSupported() const
Return whether the device supports QoS.
Definition wifi-mac.cc:1429
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition wifi-mac.cc:705
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition wifi-mac.cc:1126
void Enqueue(Ptr< Packet > packet, Mac48Address to)
Definition wifi-mac.cc:1753
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, 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:1640
void DoInitialize() override
Initialize() implementation.
Definition wifi-mac.cc:418
bool TidMappedOnLink(Mac48Address mldAddr, WifiDirection dir, uint8_t tid, uint8_t linkId) const
Check whether the given TID is mapped on the given link in the given direction for the given MLD.
Definition wifi-mac.cc:1339
Ssid GetSsid() const
Definition wifi-mac.cc:534
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition wifi-mac.cc:1435
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition wifi-mac.cc:640
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition wifi-mac.cc:484
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition wifi-mac.cc:1397
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition wifi-mac.cc:2033
bool GetHeSupported() const
Return whether the device supports HE.
Definition wifi-mac.cc:2027
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition wifi-mac.cc:2222
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:1158
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:1512
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition wifi-mac.cc:2006
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition wifi-mac.cc:2019
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, 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:1594
Ptr< MacTxMiddle > m_txMiddle
TX middle (aggregation etc.).
Definition wifi-mac.h:1030
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:389
Ptr< HtConfiguration > GetHtConfiguration() const
Definition wifi-mac.cc:1988
virtual Ptr< Txop > GetTxopFor(AcIndex ac) const
Get the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed, or a null pointer,...
Definition wifi-mac.cc:671
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:1289
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition wifi-mac.cc:2214
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:2421
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:664
bool GetShortSlotTimeSupported() const
Definition wifi-mac.cc:1479
void NotifyRxDrop(Ptr< const Packet > packet)
Definition wifi-mac.cc:748
virtual void SetLinkUpCallback(Callback< void > linkUp)
Definition wifi-mac.cc:1498
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition wifi-mac.cc:1099
const std::set< uint8_t > & GetLinkIds() const
Definition wifi-mac.cc:1132
Mac48Address GetLocalAddress(const Mac48Address &remoteAddr) const
Get the local MAC address used to communicate with a remote STA.
Definition wifi-mac.cc:1891
bool GetHtSupported(uint8_t linkId) const
Return whether the device supports HT on the given link.
Definition wifi-mac.cc:2012
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition wifi-mac.cc:1829
bool Is6GhzBand(uint8_t linkId) const
Indicate if a given link is on the 6 GHz band.
Definition wifi-mac.cc:1281
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:1836
Mac48Address GetAddress() const
Definition wifi-mac.cc:521
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition wifi-mac.cc:2456
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition wifi-mac.cc:1117
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition wifi-mac.cc:2357
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition wifi-mac.cc:618
void DoDispose() override
Destructor implementation.
Definition wifi-mac.cc:442
bool GetDsssSupported(uint8_t linkId) const
Return whether the device supports DSSS on the given link.
Definition wifi-mac.cc:1459
represent a single transmission mode
Definition wifi-mode.h:38
const std::string & GetUniqueName() const
Definition wifi-mode.cc:136
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:110
uint8_t GetMcsValue() const
Definition wifi-mode.cc:151
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1574
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< AttributeChecker > MakeAttributeContainerChecker()
Make uninitialized AttributeContainerChecker using explicit types.
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, Sep, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
Ptr< const AttributeAccessor > MakeAttributeContainerAccessor(T1 a1)
Make AttributeContainerAccessor using explicit types.
Ptr< AttributeChecker > MakePairChecker(const PairValue< A, B > &value)
Make a PairChecker from a PairValue.
Definition pair.h:272
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:250
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:273
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:690
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:492
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1307
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1324
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiContainerQueueId MakeWifiUnicastQueueId(WifiContainerQueueType type, Mac48Address addr1, std::optional< tid_t > tid=std::nullopt)
Helper function to create WifiContainerQueueId for unicast queues.
WifiMacDropReason
The reason why an MPDU was dropped.
Definition wifi-mac.h:71
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition qos-utils.cc:123
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:64
@ AP
Definition wifi-mac.h:60
@ WIFI_STANDARD_80211ax
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_MOD_CLASS_HR_DSSS
HR/DSSS (Clause 16).
@ WIFI_MOD_CLASS_HT
HT (Clause 19).
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36).
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22).
@ WIFI_MOD_CLASS_HE
HE (Clause 27).
@ AC_BE_NQOS
Non-QoS.
Definition qos-utils.h:74
@ AC_BE
Best Effort.
Definition qos-utils.h:66
@ AC_VO
Voice.
Definition qos-utils.h:72
@ AC_VI
Video.
Definition qos-utils.h:70
@ AC_BK
Background.
Definition qos-utils.h:68
@ AC_BEACON
Beacon queue.
Definition qos-utils.h:76
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:501
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
const Time WIFI_TU
Wi-Fi Time Unit value in microseconds (see IEEE 802.11-2020 sec.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1376
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
std::variant< std::reference_wrapper< MgtAssocRequestHeader >, std::reference_wrapper< MgtReassocRequestHeader > > AssocReqRefVariant
variant holding a reference to a (Re)Association Request
Definition ap-wifi-mac.h:47
@ NO_PROTECTION
@ MIXED_MODE_PROTECTION
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:181
bool IsGroupcast(const Mac48Address &adr)
Check whether a MAC destination address corresponds to a groupcast transmission.
Time DEFAULT_BEACON_INTERVAL()
Default Beacon interval.
const std::list< AcIndex > edcaAcIndices
List of the Access Categories corresponding to the four EDCA functions.
Definition qos-utils.h:203
constexpr uint8_t WIFI_EHT_MAX_MCS_INDEX
IEEE 802.11be D2.0 Figure 9-1002ai.
WifiMacType
Combination of valid MAC header type/subtype.
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_DISASSOCIATION
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
@ WIFI_MAC_MGT_REASSOCIATION_REQUEST
@ WIFI_MAC_MGT_PROBE_RESPONSE
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping &dlLinkMapping, const WifiTidLinkMapping &ulLinkMapping)
Check if the given TID-to-Link Mappings are valid for a negotiation type of 1.
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:650
std::map< tid_t, std::set< linkId_t > > WifiTidLinkMapping
TID-indexed map of the link set to which the TID is mapped.
Definition wifi-utils.h:77
static constexpr uint8_t WIFI_LINKID_UNDEFINED
Invalid link identifier.
Definition wifi-utils.h:298
std::pair< Mac48Address, uint8_t > WifiAddressTidPair
(MAC address, TID) pair
Definition qos-utils.h:27
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
uint8_t linkId_t
IEEE 802.11be D7.0 Figure 9-207e—Link ID Info field format.
Definition wifi-utils.h:74
static constexpr uint16_t MIN_AID
The minimum value for the association ID (Sec. 9.4.1.8 of 802.11-2020).
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU).
double Watt_u
Watt weak type.
Definition wifi-units.h:25
static constexpr uint16_t MAX_AID
The maximum value for the association ID (Sec. 9.4.1.8 of 802.11-2020).
static constexpr uint16_t EHT_MAX_AID
The maximum value for the association ID updated since 802.11be (Sec. 9.4.1.8 of 802....
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1396
Struct containing all supported rates.
void SetBasicRate(uint64_t bs)
Set the given rate to basic 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.
void SetMediumSyncDelayTimer(Time delay)
Set the Medium Synchronization Duration subfield of the Medium Synchronization Delay Information in t...
EHT Operation Information subfield IEEE 802.11be D2.0 Figure 9-1002c.
uint8_t grpBuExp
Group Addressed BU Indication Exponent.
uint8_t opInfoPresent
EHT Operation Information Present.
FD Capability subfield of FILS Discovery Information field.
6 GHz Operation Information field
uint8_t m_chCntrFreqSeg0
Channel center frequency segment 0.
uint8_t m_chWid
Channel Width.
uint8_t m_chCntrFreqSeg1
Channel center frequency segment 1.
uint8_t m_primCh
Primary Channel.
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
typedef for union of different ActionValues
Declaration of default values used across wifi module.