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 {
623 address,
624 std::nullopt);
625 return GetTxopQueue(AC_BE_NQOS)->PeekByQueueId(queueId);
626 }
627
628 const auto singleLink = !GetMldAddress(address).has_value();
629
630 for (uint8_t tid = 0; tid < 8; ++tid)
631 {
632 auto mpdu = GetTxopQueue(QosUtilsMapTidToAc(tid))->PeekByTidAndAddress(tid, address);
633
634 if (!mpdu)
635 {
636 continue; // queue empty, look for another TID
637 }
638
639 if (linkId != WIFI_LINKID_UNDEFINED && !singleLink &&
640 !TidMappedOnLink(address, WifiDirection::DOWNLINK, tid, linkId))
641 {
642 continue; // this TID is not mapped on the link for which we want a buffered unit
643 }
644
645 // (Sec. 35.3.12.4 802.11be D6.0) An AP MLD shall buffer a BU with a TID at the AP MLD if
646 // the TID is not mapped to any link on which the corresponding non-AP STA affiliated with
647 // a non-AP MLD is in active mode
648 if (std::none_of(GetLinks().cbegin(), GetLinks().cend(), [=, this](const auto& pair) {
649 const auto lnkId = pair.first;
650 const auto& link = pair.second;
651 // return true if the STA operating on this link is in active mode and the TID is
652 // mapped on this link (or the STA is a single link device)
653 return link->stationManager->IsAssociated(address) &&
654 !link->stationManager->IsInPsMode(address) &&
655 (singleLink ||
656 TidMappedOnLink(address, WifiDirection::DOWNLINK, tid, lnkId));
657 }))
658 {
659 NS_LOG_DEBUG("Found BU: " << *mpdu << " for STA " << address << " and TID=" << +tid);
660 return mpdu;
661 }
662 }
663 return nullptr;
664}
665
667ApWifiMac::GetBufferedMmpduFor(Mac48Address address, uint8_t linkId) const
668{
669 // TODO: 802.11be specs (Sec. 35.3.12.4 of D6.0) allow an AP MLD to avoid buffering an
670 // MMPDU if a non-AP STA is in active mode, even if the non-AP STA is not the intended
671 // receiver of the MMPDU. In case the MMPDU is sent on a link other than the one on which
672 // the intended receiver is operating, the MMPDU shall carry the MLO Link Info element.
673 // Until this mechanism is supported, an MMPDU is buffered if the intended receiver is
674 // in powersave mode
675 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
676 const auto linkIds = (linkId == WIFI_LINKID_UNDEFINED ? GetLinkIds() : std::set{linkId});
677
678 for (const auto& id : linkIds)
679 {
680 auto& link = GetLink(id);
681 if (!link.stationManager->IsInPsMode(address))
682 {
683 continue; // STA on this link is not in PS mode
684 }
685 for (const auto& aci : acList)
686 {
687 WifiContainerQueueId queueId(
690 link.stationManager->GetAffiliatedStaAddress(address).value_or(address),
691 std::nullopt);
692
693 if (auto mpdu = GetTxopQueue(aci)->PeekByQueueId(queueId))
694 {
695 NS_LOG_DEBUG("Found MMPDU: " << *mpdu << " for STA " << address << " on link "
696 << +id);
697 return mpdu;
698 }
699 }
700 }
701 return nullptr;
702}
703
704bool
706{
707 auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
708
709 const auto blocked =
710 GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(linkId,
713
714 if (blocked)
715 {
716 // temporarily unblock queues with group addressed frames, otherwise buffered group
717 // addressed frames will not be detected
719 {linkId},
721 }
722
723 const auto found = std::any_of(acList.cbegin(), acList.cend(), [=, this](const auto aci) {
724 auto queueId = m_scheduler->GetNext(aci, linkId);
725
726 while (queueId)
727 {
728 if (const auto addrType = std::get<1>(*queueId);
729 addrType == WifiRcvAddr::BROADCAST || addrType == WifiRcvAddr::GROUPCAST)
730 {
731 NS_LOG_DEBUG("Found some group addressed frames for link " << +linkId);
732 return true;
733 }
734 queueId = m_scheduler->GetNext(aci, linkId, *queueId);
735 }
736 return false;
737 });
738
739 if (blocked)
740 {
742 {linkId},
744 }
745
746 return found;
747}
748
749Tim
750ApWifiMac::GetTim(uint8_t linkId) const
751{
752 NS_LOG_FUNCTION(this << linkId);
753
754 Tim tim;
755 tim.m_dtimCount = GetLink(linkId).beaconDtimCount;
757
758 // Iterate over the list of associated non-AP STAs or MLDs
759 for (const auto& [aid, address] : m_aidToMldOrLinkAddress)
760 {
761 if (GetStaList(linkId).contains(aid) &&
762 (GetBufferedDataFor(address) || GetBufferedMmpduFor(address)))
763 {
764 tim.AddAid(aid);
765 }
766 }
767
768 // Check for group addressed frames, but only if this is a DTIM
769 if (tim.m_dtimCount == 0)
770 {
771 if (GetLink(linkId).nStationsInPsMode > 0)
772 {
774 }
775
776 /**
777 * Sec. 35.3.15.1 of 802.11be D7.0:
778 * The bits 1 to N of the bitmap in the Partial Virtual Bitmap field are for the AP MLD
779 * where N is equal to 2^(Group Addressed BU Indication Exponent + 1) – 1.
780 * The first n bits of N bits are used to indicate that one or more group addressed frames
781 * are buffered for each AP of the other AP(s) that are affiliated with the same AP MLD by
782 * setting the corresponding bit value to 1 in an increasing order of their link IDs. The
783 * remaining (N – n) bits are set to 0.
784 */
785 if (GetNLinks() > 1)
786 {
787 uint16_t aid = MIN_AID;
788 for (uint8_t id = 0; id < GetNLinks(); ++id)
789 {
790 if (id == linkId || GetLink(id).nStationsInPsMode == 0)
791 {
792 continue;
793 }
794 if (HasBufferedGroupcast(id))
795 {
796 tim.AddAid(aid);
797 }
798 ++aid;
799 }
800 }
801 }
802
803 return tim;
804}
805
806bool
808{
809 NS_LOG_FUNCTION(this << *mpdu << linkId);
810
811 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
812 const auto& hdr = mpdu->GetHeader();
813 const auto addr1 = hdr.GetAddr1();
814
815 if (addr1.IsGroup())
816 {
817 NS_ASSERT_MSG(GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(
818 linkId,
821 "Expected unicast transmissions to be blocked");
822
823 return std::any_of(acList.cbegin(), acList.cend(), [=, this](const auto aci) {
824 auto item = mpdu->IsQueued() && mpdu->GetQueueAc() == aci ? mpdu : nullptr;
825 return GetTxopQueue(aci)->PeekFirstAvailable(linkId, item) != nullptr;
826 });
827 }
828
829 // Sec. 9.2.4.1.8 802.11be D6.0:
830 // A non-DMG and non-S1G STA uses the More Data subfield to indicate to a STA that is not
831 // affiliated with a non-AP MLD and in PS mode that more BUs are buffered for that STA at
832 // the AP.
833 // For a non-AP MLD, an AP affiliated with an AP MLD uses the More Data subfield to indicate to
834 // a non-AP STA in PS mode affiliated with the non-AP MLD that more BUs, corresponding to Data
835 // frames with TIDs that are mapped to this link [...] or bufferable Management frames are
836 // buffered for the non-AP MLD at the AP MLD
837
838 const auto receiver = GetLink(linkId).stationManager->GetMldAddress(addr1).value_or(addr1);
839 const auto isSingleLink = (addr1 == receiver);
840
841 // look for buffered data frames
842 if (!GetQosSupported())
843 {
846 receiver,
847 std::nullopt);
848 auto start = hdr.IsData() ? mpdu : nullptr;
849 if (auto bu = GetTxopQueue(AC_BE_NQOS)->PeekByQueueId(queueId, start))
850 {
851 NS_LOG_DEBUG("Found a buffered unit: " << *bu);
852 return true;
853 }
854 }
855 else
856 {
857 for (uint8_t tid = 0; tid < 8; ++tid)
858 {
859 if (!isSingleLink && !TidMappedOnLink(receiver, WifiDirection::DOWNLINK, tid, linkId))
860 {
861 continue; // this TID is not mapped on this link
862 }
863
864 auto start =
865 (hdr.IsQosData() && hdr.GetQosTid() == tid) ? mpdu->GetOriginal() : nullptr;
866
867 if (auto bu = GetTxopQueue(QosUtilsMapTidToAc(tid))
868 ->PeekByTidAndAddress(tid, receiver, start))
869 {
870 NS_LOG_DEBUG("Found a buffered unit: " << *bu);
871 return true;
872 }
873 }
874 }
875
876 // look for buffered management frames
877 for (const auto aci : acList)
878 {
881 addr1,
882 std::nullopt);
883 auto start = (hdr.IsMgt() && mpdu->GetQueueAc() == aci) ? mpdu : nullptr;
884
885 if (auto bu = GetTxopQueue(aci)->PeekByQueueId(queueId, start))
886 {
887 NS_LOG_DEBUG("Found a buffered unit: " << *bu);
888 return true;
889 }
890 }
891
892 return false;
893}
894
896ApWifiMac::GetErpInformation(uint8_t linkId) const
897{
898 NS_LOG_FUNCTION(this << +linkId);
899 NS_ASSERT(GetErpSupported(linkId));
900 ErpInformation information;
901
902 information.SetNonErpPresent(GetLink(linkId).numNonErpStations > 0);
903 information.SetUseProtection(GetUseNonErpProtection(linkId));
904 if (GetLink(linkId).shortPreambleEnabled)
905 {
906 information.SetBarkerPreambleMode(0);
907 }
908 else
909 {
910 information.SetBarkerPreambleMode(1);
911 }
912
913 return information;
914}
915
918{
919 NS_LOG_FUNCTION(this << +linkId);
921 EdcaParameterSet edcaParameters;
922
923 Ptr<QosTxop> edca;
924 Time txopLimit;
925
926 edca = GetQosTxop(AC_BE);
927 edcaParameters.SetBeAci(0);
928 edcaParameters.SetBeCWmin(m_cwMinsForSta.contains(AC_BE) ? m_cwMinsForSta.at(AC_BE).at(linkId)
929 : edca->GetMinCw(linkId));
930 edcaParameters.SetBeCWmax(m_cwMaxsForSta.contains(AC_BE) ? m_cwMaxsForSta.at(AC_BE).at(linkId)
931 : edca->GetMaxCw(linkId));
932 edcaParameters.SetBeAifsn(m_aifsnsForSta.contains(AC_BE) ? m_aifsnsForSta.at(AC_BE).at(linkId)
933 : edca->GetAifsn(linkId));
934 txopLimit = m_txopLimitsForSta.contains(AC_BE) ? m_txopLimitsForSta.at(AC_BE).at(linkId)
935 : edca->GetTxopLimit(linkId);
936 edcaParameters.SetBeTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
937
938 edca = GetQosTxop(AC_BK);
939 edcaParameters.SetBkAci(1);
940 edcaParameters.SetBkCWmin(m_cwMinsForSta.contains(AC_BK) ? m_cwMinsForSta.at(AC_BK).at(linkId)
941 : edca->GetMinCw(linkId));
942 edcaParameters.SetBkCWmax(m_cwMaxsForSta.contains(AC_BK) ? m_cwMaxsForSta.at(AC_BK).at(linkId)
943 : edca->GetMaxCw(linkId));
944 edcaParameters.SetBkAifsn(m_aifsnsForSta.contains(AC_BK) ? m_aifsnsForSta.at(AC_BK).at(linkId)
945 : edca->GetAifsn(linkId));
946 txopLimit = m_txopLimitsForSta.contains(AC_BK) ? m_txopLimitsForSta.at(AC_BK).at(linkId)
947 : edca->GetTxopLimit(linkId);
948 edcaParameters.SetBkTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
949
950 edca = GetQosTxop(AC_VI);
951 edcaParameters.SetViAci(2);
952 edcaParameters.SetViCWmin(m_cwMinsForSta.contains(AC_VI) ? m_cwMinsForSta.at(AC_VI).at(linkId)
953 : edca->GetMinCw(linkId));
954 edcaParameters.SetViCWmax(m_cwMaxsForSta.contains(AC_VI) ? m_cwMaxsForSta.at(AC_VI).at(linkId)
955 : edca->GetMaxCw(linkId));
956 edcaParameters.SetViAifsn(m_aifsnsForSta.contains(AC_VI) ? m_aifsnsForSta.at(AC_VI).at(linkId)
957 : edca->GetAifsn(linkId));
958 txopLimit = m_txopLimitsForSta.contains(AC_VI) ? m_txopLimitsForSta.at(AC_VI).at(linkId)
959 : edca->GetTxopLimit(linkId);
960 edcaParameters.SetViTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
961
962 edca = GetQosTxop(AC_VO);
963 edcaParameters.SetVoAci(3);
964 edcaParameters.SetVoCWmin(m_cwMinsForSta.contains(AC_VO) ? m_cwMinsForSta.at(AC_VO).at(linkId)
965 : edca->GetMinCw(linkId));
966 edcaParameters.SetVoCWmax(m_cwMaxsForSta.contains(AC_VO) ? m_cwMaxsForSta.at(AC_VO).at(linkId)
967 : edca->GetMaxCw(linkId));
968 edcaParameters.SetVoAifsn(m_aifsnsForSta.contains(AC_VO) ? m_aifsnsForSta.at(AC_VO).at(linkId)
969 : edca->GetAifsn(linkId));
970 txopLimit = m_txopLimitsForSta.contains(AC_VO) ? m_txopLimitsForSta.at(AC_VO).at(linkId)
971 : edca->GetTxopLimit(linkId);
972 edcaParameters.SetVoTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
973
974 edcaParameters.SetQosInfo(0);
975
976 return edcaParameters;
977}
978
979std::optional<MuEdcaParameterSet>
981{
982 NS_LOG_FUNCTION(this);
984
985 Ptr<HeConfiguration> heConfiguration = GetHeConfiguration();
986 NS_ASSERT(heConfiguration);
987
988 MuEdcaParameterSet muEdcaParameters;
989 muEdcaParameters.SetQosInfo(0);
990
991 muEdcaParameters.SetMuAifsn(AC_BE, heConfiguration->m_muBeAifsn);
992 muEdcaParameters.SetMuCwMin(AC_BE, heConfiguration->m_muBeCwMin);
993 muEdcaParameters.SetMuCwMax(AC_BE, heConfiguration->m_muBeCwMax);
994 muEdcaParameters.SetMuEdcaTimer(AC_BE, heConfiguration->m_beMuEdcaTimer);
995
996 muEdcaParameters.SetMuAifsn(AC_BK, heConfiguration->m_muBkAifsn);
997 muEdcaParameters.SetMuCwMin(AC_BK, heConfiguration->m_muBkCwMin);
998 muEdcaParameters.SetMuCwMax(AC_BK, heConfiguration->m_muBkCwMax);
999 muEdcaParameters.SetMuEdcaTimer(AC_BK, heConfiguration->m_bkMuEdcaTimer);
1000
1001 muEdcaParameters.SetMuAifsn(AC_VI, heConfiguration->m_muViAifsn);
1002 muEdcaParameters.SetMuCwMin(AC_VI, heConfiguration->m_muViCwMin);
1003 muEdcaParameters.SetMuCwMax(AC_VI, heConfiguration->m_muViCwMax);
1004 muEdcaParameters.SetMuEdcaTimer(AC_VI, heConfiguration->m_viMuEdcaTimer);
1005
1006 muEdcaParameters.SetMuAifsn(AC_VO, heConfiguration->m_muVoAifsn);
1007 muEdcaParameters.SetMuCwMin(AC_VO, heConfiguration->m_muVoCwMin);
1008 muEdcaParameters.SetMuCwMax(AC_VO, heConfiguration->m_muVoCwMax);
1009 muEdcaParameters.SetMuEdcaTimer(AC_VO, heConfiguration->m_voMuEdcaTimer);
1010
1011 // The timers of the MU EDCA Parameter Set must be either all zero or all
1012 // non-zero. The information element is advertised if all timers are non-zero
1013 auto timerNotNull = [&muEdcaParameters](uint8_t aci) {
1014 return !muEdcaParameters.GetMuEdcaTimer(aci).IsZero();
1015 };
1016 auto aci = {0, 1, 2, 3};
1017 if (std::all_of(aci.begin(), aci.end(), timerNotNull))
1018 {
1019 return muEdcaParameters;
1020 }
1021
1022 NS_ABORT_MSG_UNLESS(std::none_of(aci.begin(), aci.end(), timerNotNull),
1023 "MU EDCA Timers must be all zero if the IE is not advertised.");
1024
1025 return std::nullopt;
1026}
1027
1028std::optional<ReducedNeighborReport>
1030{
1031 NS_LOG_FUNCTION(this << +linkId);
1032
1033 if (GetNLinks() <= 1)
1034 {
1035 return std::nullopt;
1036 }
1037
1040
1041 for (uint8_t index = 0; index < GetNLinks(); ++index)
1042 {
1043 if (index != linkId) // all links but the one used to send this Beacon frame
1044 {
1045 rnr.AddNbrApInfoField();
1046 std::size_t nbrId = rnr.GetNNbrApInfoFields() - 1;
1047 rnr.SetOperatingChannel(nbrId, GetLink(index).phy->GetOperatingChannel());
1048 rnr.AddTbttInformationField(nbrId);
1049 rnr.SetBssid(nbrId, 0, GetLink(index).feManager->GetAddress());
1050 rnr.SetShortSsid(nbrId, 0, 0);
1051 rnr.SetBssParameters(nbrId, 0, 0);
1052 rnr.SetPsd20MHz(nbrId, 0, 0);
1053 rnr.SetMldParameters(nbrId, 0, {0, index, 0, 0, 0});
1054 }
1055 }
1056 return rnr;
1057}
1058
1061 WifiMacType frameType,
1062 const Mac48Address& to,
1063 const std::optional<MultiLinkElement>& mlProbeReqMle)
1064{
1065 NS_LOG_FUNCTION(this << +linkId << frameType << to);
1066 NS_ABORT_IF(GetNLinks() == 1);
1067 NS_ABORT_MSG_IF(mlProbeReqMle.has_value() && frameType != WIFI_MAC_MGT_PROBE_RESPONSE,
1068 "ML Probe Request Multi-Link Element cannot be provided for frame type "
1069 << frameType);
1070
1073 mle.SetLinkIdInfo(linkId);
1075
1076 auto ehtConfiguration = GetEhtConfiguration();
1077 NS_ASSERT(ehtConfiguration);
1078
1079 if (ehtConfiguration->m_emlsrActivated)
1080 {
1081 mle.SetEmlsrSupported(true);
1082 // When the EMLSR Padding Delay subfield is included in a frame sent by an AP affiliated
1083 // with an AP MLD, the EMLSR Padding Delay subfield is reserved.
1084 // When the EMLSR Transition Delay subfield is included in a frame sent by an AP affiliated
1085 // with an AP MLD, the EMLSR Transition Delay subfield is reserved. (Sec. 9.4.2.312.2.3
1086 // of 802.11be D2.3)
1087 TimeValue time;
1088 mle.SetTransitionTimeout(ehtConfiguration->m_transitionTimeout);
1089
1090 // An AP affiliated with an AP MLD may include the Medium Synchronization Delay Information
1091 // subfield in the Common Info field of the Basic Multi-Link element carried in transmitted
1092 // (Re)Association Response or Multi-Link Probe Response frames to provide medium
1093 // synchronization information used by the AP MLD. (Section 35.3.16.8.2 of 802.11be D3.1)
1094 if (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE)
1095 {
1096 auto& commonInfo = mle.GetCommonInfoBasic();
1097 commonInfo.SetMediumSyncDelayTimer(ehtConfiguration->m_mediumSyncDuration);
1098 commonInfo.SetMediumSyncOfdmEdThreshold(ehtConfiguration->m_msdOfdmEdThreshold);
1099 commonInfo.SetMediumSyncMaxNTxops(ehtConfiguration->m_msdMaxNTxops);
1100 }
1101 }
1102
1103 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
1104 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
1105 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
1106 if (frameType == WIFI_MAC_MGT_BEACON || frameType == WIFI_MAC_MGT_PROBE_RESPONSE ||
1107 frameType == WIFI_MAC_MGT_ASSOCIATION_REQUEST ||
1110 {
1111 auto& mldCapabilities = mle.GetCommonInfoBasic().m_mldCapabilities;
1112 mldCapabilities.emplace();
1113 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
1114 mldCapabilities->srsSupport = 0;
1115 mldCapabilities->tidToLinkMappingSupport =
1116 static_cast<uint8_t>(ehtConfiguration->m_tidLinkMappingSupport);
1117 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
1118 mldCapabilities->aarSupport = 0; // not supported yet
1119 }
1120
1121 // if the Multi-Link Element is being inserted in a (Re)Association Response frame
1122 // and the remote station is affiliated with an MLD, try multi-link setup
1123 if (auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1124 (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE ||
1126 staMldAddress.has_value())
1127 {
1128 for (uint8_t i = 0; i < GetNLinks(); i++)
1129 {
1130 auto remoteStationManager = GetWifiRemoteStationManager(i);
1131 if (auto staAddress = remoteStationManager->GetAffiliatedStaAddress(*staMldAddress);
1132 i != linkId && staAddress.has_value() &&
1133 (remoteStationManager->IsWaitAssocTxOk(*staAddress) ||
1134 remoteStationManager->IsAssocRefused(*staAddress)))
1135 {
1136 // For each requested link in addition to the link on which the
1137 // (Re)Association Response frame is transmitted, the Link Info field
1138 // of the Basic Multi-Link element carried in the (Re)Association
1139 // Response frame shall contain the corresponding Per-STA Profile
1140 // subelement(s) (Sec. 35.3.5.4 of 802.11be D2.0)
1142 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
1143 // The Link ID subfield of the STA Control field of the Per-STA Profile
1144 // subelement for the AP corresponding to a link is set to the link ID
1145 // of the AP affiliated with the AP MLD that is operating on that link.
1146 perStaProfile.SetLinkId(i);
1147 perStaProfile.SetCompleteProfile();
1148 // For each Per-STA Profile subelement included in the Link Info field,
1149 // the Complete Profile subfield of the STA Control field shall be set to 1
1150 perStaProfile.SetStaMacAddress(GetFrameExchangeManager(i)->GetAddress());
1151 perStaProfile.SetAssocResponse(GetAssocResp(*staAddress, i));
1152 }
1153 }
1154 }
1155
1156 if (!mlProbeReqMle.has_value())
1157 {
1158 return mle; // not a multi-link probe request
1159 }
1160
1161 auto reqVar = mlProbeReqMle->GetVariant();
1163 "Invalid MLE variant " << reqVar);
1164
1165 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
1166 // If either the Address 1 field or the Address 3 field of the multi-link probe request is set
1167 // to the MAC address of the responding AP that operates on the same link where the multi-link
1168 // probe request is sent, then the AP MLD ID subfield shall be present in the Probe Request
1169 // Multi-Link element of the multi-link probe request value and targeted AP MLD is identified by
1170 // AP MLD ID subfield, which is set to the same AP MLD ID as the one used by the AP that is
1171 // addressed by the multi-link probe request to identify the AP MLD
1172 // in the Beacon and Probe Response frames that it transmits.
1173 auto apMldId = mlProbeReqMle->GetApMldId();
1174 NS_ASSERT_MSG(apMldId.has_value(), "AP MLD ID subfield missing");
1175
1176 // IEEE 802.11be D6.0 9.4.2.169.2 Neighbor AP Information field
1177 // If the reported AP is affiliated with the same MLD as the reporting AP sending the frame
1178 // carrying this element, the AP MLD ID subfield is set to 0. AP MLD ID value advertised in
1179 // Beacons and Probe Responses is 0. Multi-BSSID feature not supported.
1180 NS_ASSERT_MSG(*apMldId == 0, "AP MLD ID expected value is 0. value = " << +apMldId.value());
1181
1182 // Using set to handle case of multiple Per-STA Profiles including same link ID
1183 std::set<uint8_t> respLinkIds{}; // Set of Link IDs to include in Probe Response
1184 if (const auto nProfiles = mlProbeReqMle->GetNPerStaProfileSubelements(); nProfiles == 0)
1185 {
1186 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
1187 // If the Probe Request Multi-link element in the multi-link probe request does not include
1188 // any per-STA profile, then all APs affiliated with the same AP MLD as the AP identified in
1189 // the Address 1 or Address 3 field or AP MLD ID shall be requested APs.
1190 for (std::size_t i = 0; i < GetNLinks(); ++i)
1191 {
1192 if (i != linkId)
1193 {
1194 respLinkIds.insert(i);
1195 }
1196 }
1197 }
1198
1199 for (std::size_t i = 0; i < mlProbeReqMle->GetNPerStaProfileSubelements(); ++i)
1200 {
1201 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
1202 // If the Probe Request Multi-Link element in the multi-link probe request includes one or
1203 // more per-STA profiles, then only APs affiliated with the same AP MLD whose link ID is
1204 // equal to the value in the Link ID Field in a per-STA profile in the Probe Request
1205 // Multi-link element shall be requested APs.
1206 const auto& perStaProfile = mlProbeReqMle->GetPerStaProfile(i);
1207 auto currLinkId = perStaProfile.GetLinkId();
1208 if ((currLinkId < GetNLinks()) && (currLinkId != linkId))
1209 {
1210 respLinkIds.insert(currLinkId); // Only consider valid link IDs
1211 }
1212 }
1213
1214 auto setPerStaProfile = [&](uint8_t id) -> void {
1216 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
1217 perStaProfile.SetLinkId(id);
1218 // Current support limited to Complete Profile request per link ID
1219 // TODO: Add support for Partial Per-STA Profile request
1220 perStaProfile.SetProbeResponse(GetProbeRespProfile(id));
1221 perStaProfile.SetCompleteProfile();
1222 };
1223
1224 std::for_each(respLinkIds.begin(), respLinkIds.end(), setPerStaProfile);
1225 return mle;
1226}
1227
1229ApWifiMac::GetHtOperation(uint8_t linkId) const
1230{
1231 NS_LOG_FUNCTION(this << +linkId);
1232 NS_ASSERT(GetHtSupported(linkId));
1233 HtOperation operation;
1234 auto phy = GetWifiPhy(linkId);
1235 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1236
1237 operation.SetPrimaryChannel(phy->GetPrimaryChannelNumber(MHz_u{20}));
1238 operation.SetRifsMode(false);
1239 operation.SetNonGfHtStasPresent(true);
1240 if (phy->GetChannelWidth() > MHz_u{20})
1241 {
1242 operation.SetSecondaryChannelOffset(1);
1243 operation.SetStaChannelWidth(1);
1244 }
1245 if (GetLink(linkId).numNonHtStations == 0)
1246 {
1247 operation.SetHtProtection(NO_PROTECTION);
1248 }
1249 else
1250 {
1252 }
1253 uint64_t maxSupportedRate = 0; // in bit/s
1254 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HT))
1255 {
1256 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
1257 NS_ASSERT(nss > 0 && nss < 5);
1258 uint64_t dataRate =
1259 mcs.GetDataRate(phy->GetChannelWidth(),
1260 NanoSeconds(GetHtConfiguration()->m_sgiSupported ? 400 : 800),
1261 nss);
1262 if (dataRate > maxSupportedRate)
1263 {
1264 maxSupportedRate = dataRate;
1265 NS_LOG_DEBUG("Updating maxSupportedRate to " << maxSupportedRate);
1266 }
1267 }
1268 uint8_t maxSpatialStream = phy->GetMaxSupportedTxSpatialStreams();
1269 auto mcsList = phy->GetMcsList(WIFI_MOD_CLASS_HT);
1270 uint8_t nMcs = mcsList.size();
1271 for (const auto& sta : GetLink(linkId).staList)
1272 {
1273 if (remoteStationManager->GetHtSupported(sta.second) ||
1274 remoteStationManager->GetStationHe6GhzCapabilities(sta.second))
1275 {
1276 uint64_t maxSupportedRateByHtSta = 0; // in bit/s
1277 auto itMcs = mcsList.begin();
1278 for (uint8_t j = 0;
1279 j < (std::min(nMcs, remoteStationManager->GetNMcsSupported(sta.second)));
1280 j++)
1281 {
1282 WifiMode mcs = *itMcs++;
1283 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
1284 NS_ASSERT(nss > 0 && nss < 5);
1285 uint64_t dataRate = mcs.GetDataRate(
1286 remoteStationManager->GetChannelWidthSupported(sta.second),
1287 NanoSeconds(remoteStationManager->GetShortGuardIntervalSupported(sta.second)
1288 ? 400
1289 : 800),
1290 nss);
1291 if (dataRate > maxSupportedRateByHtSta)
1292 {
1293 maxSupportedRateByHtSta = dataRate;
1294 }
1295 }
1296 if (maxSupportedRateByHtSta < maxSupportedRate)
1297 {
1298 maxSupportedRate = maxSupportedRateByHtSta;
1299 }
1300 if (remoteStationManager->GetNMcsSupported(sta.second) < nMcs)
1301 {
1302 nMcs = remoteStationManager->GetNMcsSupported(sta.second);
1303 }
1304 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1305 {
1306 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1307 }
1308 }
1309 }
1311 static_cast<uint16_t>(maxSupportedRate / 1e6)); // in Mbit/s
1312 operation.SetTxMcsSetDefined(nMcs > 0);
1313 operation.SetTxMaxNSpatialStreams(maxSpatialStream);
1314 // To be filled in once supported
1315 operation.SetObssNonHtStasPresent(0);
1316 operation.SetDualBeacon(0);
1317 operation.SetDualCtsProtection(0);
1318 operation.SetStbcBeacon(0);
1320 operation.SetPcoActive(0);
1321 operation.SetPhase(0);
1322 operation.SetRxMcsBitmask(0);
1323 operation.SetTxRxMcsSetUnequal(0);
1324 operation.SetTxUnequalModulation(0);
1325
1326 return operation;
1327}
1328
1330ApWifiMac::GetVhtOperation(uint8_t linkId) const
1331{
1332 NS_LOG_FUNCTION(this << +linkId);
1333 NS_ASSERT(GetVhtSupported(linkId));
1334 VhtOperation operation;
1335 auto phy = GetWifiPhy(linkId);
1336 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1337
1338 const auto bssBandwidth = phy->GetChannelWidth();
1339 // Set to 0 for 20 MHz or 40 MHz BSS bandwidth.
1340 // Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS bandwidth.
1341 operation.SetChannelWidth((bssBandwidth > MHz_u{40}) ? 1 : 0);
1342 // For 20, 40, or 80 MHz BSS bandwidth, indicates the channel center frequency
1343 // index for the 20, 40, or 80 MHz channel on which the VHT BSS operates.
1344 // For 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
1345 // indicates the channel center frequency index of the 80 MHz channel
1346 // segment that contains the primary channel.
1347 // For 80+80 MHz BSS bandwidth and the Channel Width subfield equal to 1 or 3,
1348 // indicates the channel center frequency index for the primary 80 MHz channel of the VHT BSS.
1349 operation.SetChannelCenterFrequencySegment0((bssBandwidth == MHz_u{160})
1350 ? phy->GetPrimaryChannelNumber(MHz_u{80})
1351 : phy->GetChannelNumber());
1352 // For a 20, 40, or 80 MHz BSS bandwidth, this subfield is set to 0.
1353 // For a 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
1354 // indicates the channel center frequency index of the 160 MHz channel on
1355 // which the VHT BSS operates.
1356 // For an 80+80 MHz BSS bandwidth and the Channel Width subfield equal to 1 or 3,
1357 // indicates the channel center frequency index of the secondary 80 MHz channel of the VHT BSS.
1358 const auto& operatingChannel = phy->GetOperatingChannel();
1359 const auto is80Plus80 =
1360 operatingChannel.GetWidthType() == WifiChannelWidthType::CW_80_PLUS_80MHZ;
1361 operation.SetChannelCenterFrequencySegment1((bssBandwidth == MHz_u{160})
1362 ? is80Plus80 ? operatingChannel.GetNumber(1)
1363 : phy->GetChannelNumber()
1364 : 0);
1365 uint8_t maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
1366 for (const auto& sta : GetLink(linkId).staList)
1367 {
1368 if (remoteStationManager->GetVhtSupported(sta.second))
1369 {
1370 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1371 {
1372 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1373 }
1374 }
1375 }
1376 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
1377 {
1378 uint8_t maxMcs =
1379 9; // TBD: hardcode to 9 for now since we assume all MCS values are supported
1380 operation.SetMaxVhtMcsPerNss(nss, maxMcs);
1381 }
1382
1383 return operation;
1384}
1385
1387ApWifiMac::GetHeOperation(uint8_t linkId) const
1388{
1389 NS_LOG_FUNCTION(this << +linkId);
1391 HeOperation operation;
1392 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1393
1394 uint8_t maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
1395 for (const auto& sta : GetLink(linkId).staList)
1396 {
1397 if (remoteStationManager->GetHeSupported(sta.second))
1398 {
1399 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1400 {
1401 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1402 }
1403 }
1404 }
1405 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
1406 {
1407 operation.SetMaxHeMcsPerNss(
1408 nss,
1409 11); // TBD: hardcode to 11 for now since we assume all MCS values are supported
1410 }
1411 operation.m_bssColorInfo.m_bssColor = GetHeConfiguration()->m_bssColor;
1412
1413 if (auto phy = GetWifiPhy(linkId); phy && phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ)
1414 {
1416 const auto bw = phy->GetChannelWidth();
1417 const auto ch = phy->GetOperatingChannel();
1418 op6Ghz.m_chWid = (bw == MHz_u{20}) ? 0 : (bw == MHz_u{40}) ? 1 : (bw == MHz_u{80}) ? 2 : 3;
1419 op6Ghz.m_primCh = ch.GetPrimaryChannelNumber(MHz_u{20}, WIFI_STANDARD_80211ax);
1420 op6Ghz.m_chCntrFreqSeg0 = (bw == MHz_u{160})
1421 ? ch.GetPrimaryChannelNumber(MHz_u{80}, WIFI_STANDARD_80211ax)
1422 : ch.GetNumber();
1423 // TODO: for 80+80 MHz channels, set this field to the secondary 80 MHz segment number
1424 op6Ghz.m_chCntrFreqSeg1 = (bw == MHz_u{160}) ? ch.GetNumber() : 0;
1425
1426 operation.m_6GHzOpInfo = op6Ghz;
1427 }
1428
1429 return operation;
1430}
1431
1433ApWifiMac::GetEhtOperation(uint8_t linkId) const
1434{
1435 NS_LOG_FUNCTION(this << +linkId);
1437 EhtOperation operation;
1438 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1439 const auto phy = GetWifiPhy(linkId);
1440
1441 auto maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
1442 for (const auto& sta : GetLink(linkId).staList)
1443 {
1444 if (remoteStationManager->GetEhtSupported(sta.second))
1445 {
1446 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1447 {
1448 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1449 }
1450 }
1451 }
1452 operation.SetMaxRxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1453 operation.SetMaxTxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1455
1456 if (const auto bw = phy->GetChannelWidth();
1457 (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) && (bw == MHz_u{320}))
1458 {
1459 operation.m_opInfo.emplace(EhtOperation::EhtOpInfo{{.channelWidth = 4}});
1460 operation.m_params.opInfoPresent = 1;
1461 }
1462 return operation;
1463}
1464
1465void
1467 Mac48Address to,
1468 uint8_t linkId)
1469{
1470 NS_LOG_FUNCTION(this << to << +linkId);
1472 hdr.SetAddr1(to);
1473 hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
1474 hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
1475 hdr.SetDsNotFrom();
1476 hdr.SetDsNotTo();
1477 Ptr<Packet> packet = Create<Packet>();
1478 packet->AddHeader(probeResp);
1479
1480 if (!GetQosSupported())
1481 {
1482 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1483 }
1484 // "A QoS STA that transmits a Management frame determines access category used
1485 // for medium access in transmission of the Management frame as follows
1486 // (If dot11QMFActivated is false or not present)
1487 // — If the Management frame is individually addressed to a non-QoS STA, category
1488 // AC_BE should be selected.
1489 // — If category AC_BE was not selected by the previous step, category AC_VO
1490 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1491 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1492 {
1493 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1494 }
1495 else
1496 {
1497 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1498 }
1499}
1500
1503{
1505 probe.Get<Ssid>() = GetSsid();
1506 auto supportedRates = GetSupportedRates(linkId);
1507 probe.Get<SupportedRates>() = supportedRates.rates;
1508 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1510 probe.m_capability = GetCapabilities(linkId);
1511 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(
1512 GetLink(linkId).shortPreambleEnabled);
1513 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1514 GetLink(linkId).shortSlotTimeEnabled);
1515 if (GetDsssSupported(linkId))
1516 {
1517 probe.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1518 }
1519 if (GetErpSupported(linkId))
1520 {
1521 probe.Get<ErpInformation>() = GetErpInformation(linkId);
1522 }
1523 if (GetQosSupported())
1524 {
1525 probe.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1526 }
1527 if (GetHtSupported(linkId))
1528 {
1530 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1531 probe.Get<HtOperation>() = GetHtOperation(linkId);
1532 }
1533 if (GetVhtSupported(linkId))
1534 {
1535 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1536 probe.Get<VhtOperation>() = GetVhtOperation(linkId);
1537 }
1538 if (GetHeSupported())
1539 {
1540 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1541 probe.Get<HeOperation>() = GetHeOperation(linkId);
1542 if (auto muEdcaParameterSet = GetMuEdcaParameterSet())
1543 {
1544 probe.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1545 }
1546 if (Is6GhzBand(linkId))
1547 {
1549 }
1550 }
1551 if (GetEhtSupported())
1552 {
1553 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1554 probe.Get<EhtOperation>() = GetEhtOperation(linkId);
1555 }
1556
1557 return probe;
1558}
1559
1561ApWifiMac::GetProbeResp(uint8_t linkId, const std::optional<MultiLinkElement>& reqMle)
1562{
1563 NS_LOG_FUNCTION(this << linkId << reqMle.has_value());
1564 NS_ASSERT_MSG(linkId < GetNLinks(), "Invalid link ID = " << +linkId);
1565
1566 auto probeResp = GetProbeRespProfile(linkId);
1567
1568 if (GetNLinks() > 1)
1569 {
1570 /*
1571 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1572 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1573 * include a TBTT Information field in a Reduced Neighbor Report element with the
1574 * TBTT Information Length field set to 16 or higher, for each of the other APs
1575 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1576 */
1577 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1578 {
1579 probeResp.Get<ReducedNeighborReport>() = std::move(*rnr);
1580 }
1581 /*
1582 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1583 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1584 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1585 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1586 * channel switching, extended channel switching, and channel quieting) are
1587 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1588 */
1589 probeResp.Get<MultiLinkElement>() = GetMultiLinkElement(linkId,
1592 reqMle);
1593 }
1594 return probeResp;
1595}
1596
1599{
1601 StatusCode code;
1602 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1603 if (remoteStationManager->IsWaitAssocTxOk(to))
1604 {
1605 code.SetSuccess();
1606 }
1607 else
1608 {
1609 NS_ABORT_IF(!remoteStationManager->IsAssocRefused(to));
1610 // reset state
1611 remoteStationManager->RecordDisassociated(to);
1612 code.SetFailure();
1613 }
1614 auto supportedRates = GetSupportedRates(linkId);
1615 assoc.Get<SupportedRates>() = supportedRates.rates;
1616 assoc.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1617 assoc.m_statusCode = code;
1618 assoc.m_capability = GetCapabilities(linkId);
1619 if (GetQosSupported())
1620 {
1621 assoc.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1622 }
1623 if (GetHtSupported(linkId))
1624 {
1626 assoc.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1627 assoc.Get<HtOperation>() = GetHtOperation(linkId);
1628 }
1629 if (GetVhtSupported(linkId))
1630 {
1631 assoc.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1632 assoc.Get<VhtOperation>() = GetVhtOperation(linkId);
1633 }
1634 if (GetHeSupported())
1635 {
1636 assoc.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1637 assoc.Get<HeOperation>() = GetHeOperation(linkId);
1638 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1639 {
1640 assoc.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1641 }
1642 if (Is6GhzBand(linkId))
1643 {
1645 }
1646 }
1647 if (GetEhtSupported())
1648 {
1649 assoc.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1650 assoc.Get<EhtOperation>() = GetEhtOperation(linkId);
1651 // The AP MLD that accepts the requested TID-to-link mapping shall not include in the
1652 // (Re)Association Response frame the TID-to-link Mapping element.
1653 // (Sec. 35.3.7.1.8 of 802.11be D3.1).
1654 // For now, we assume that AP MLDs always accept requested TID-to-link mappings.
1655 }
1656 return assoc;
1657}
1658
1661 const Mac48Address& to,
1662 uint8_t linkId)
1663{
1664 // find all the links to setup (i.e., those for which status code is success)
1665 std::map<uint8_t /* link ID */, Mac48Address> linkIdStaAddrMap;
1666
1667 if (assoc.m_statusCode.IsSuccess())
1668 {
1669 linkIdStaAddrMap[linkId] = to;
1670 }
1671
1672 if (const auto& mle = assoc.Get<MultiLinkElement>())
1673 {
1674 const auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1675 NS_ABORT_MSG_IF(!staMldAddress.has_value(),
1676 "Sending a Multi-Link Element to a single link device");
1677 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1678 {
1679 auto& perStaProfile = mle->GetPerStaProfile(idx);
1680 if (perStaProfile.HasAssocResponse() &&
1681 perStaProfile.GetAssocResponse().m_statusCode.IsSuccess())
1682 {
1683 uint8_t otherLinkId = perStaProfile.GetLinkId();
1684 auto staAddress = GetWifiRemoteStationManager(otherLinkId)
1685 ->GetAffiliatedStaAddress(*staMldAddress);
1686 NS_ABORT_MSG_IF(!staAddress.has_value(),
1687 "No STA to associate with on link " << +otherLinkId);
1688 const auto [it, inserted] = linkIdStaAddrMap.insert({otherLinkId, *staAddress});
1689 NS_ABORT_MSG_IF(!inserted,
1690 "More than one Association Response to MLD "
1691 << *staMldAddress << " on link ID " << +otherLinkId);
1692 }
1693 }
1694 }
1695
1696 return linkIdStaAddrMap;
1697}
1698
1699void
1701{
1702 if (linkIdStaAddrMap.empty())
1703 {
1704 // no link to setup, nothing to do
1705 return;
1706 }
1707
1708 const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
1709 const auto addr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1710
1711 // check if an AID is already allocated to the device that is associating
1712 std::set<uint16_t> aids;
1713
1714 for (const auto& [id, link] : GetLinks())
1715 {
1716 if (const auto aid = link->stationManager->GetAssociationId(addr); aid != SU_STA_ID)
1717 {
1718 aids.insert(aid);
1719 }
1720 }
1721
1722 NS_ABORT_MSG_IF(aids.size() > 1, addr << " cannot have more than one AID assigned");
1723
1724 const auto aid = aids.empty() ? GetNextAssociationId() : *aids.cbegin();
1725
1726 // store the MLD or link address in the AID-to-address map
1727 const auto [it, inserted] = m_aidToMldOrLinkAddress.emplace(aid, addr);
1728
1729 NS_ABORT_MSG_IF(!inserted, "AID " << aid << " already present, cannot be assigned to " << addr);
1730
1731 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1732 {
1733 auto& link = GetLink(id);
1734
1735 if (const auto [it, inserted] = link.staList.emplace(aid, staAddr); inserted)
1736 {
1737 // the STA on this link had no AID assigned
1738 link.stationManager->SetAssociationId(staAddr, aid);
1739
1740 if (link.stationManager->GetDsssSupported(staAddr) &&
1741 !link.stationManager->GetErpOfdmSupported(staAddr))
1742 {
1743 link.numNonErpStations++;
1744 }
1745 if (!link.stationManager->GetHtSupported(staAddr) &&
1746 !link.stationManager->GetStationHe6GhzCapabilities(staAddr))
1747 {
1748 link.numNonHtStations++;
1749 }
1752 }
1753 else
1754 {
1755 // the STA on this link had an AID assigned
1756 NS_ABORT_MSG_IF(it->first != aid,
1757 "AID " << it->first << " already assigned to " << staAddr
1758 << ", could not assign " << aid);
1759 }
1760 }
1761
1762 // set the AID in all the Association Responses. NOTE that the Association
1763 // Responses included in the Per-STA Profile Subelements of the Multi-Link
1764 // Element must not contain the AID field. We set the AID field in such
1765 // Association Responses anyway, in order to ease future implementation of
1766 // the inheritance mechanism.
1767 if (assoc.m_statusCode.IsSuccess())
1768 {
1769 assoc.m_aid = aid;
1770 }
1771 if (const auto& mle = assoc.Get<MultiLinkElement>())
1772 {
1773 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1774 {
1775 if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1776 perStaProfile.HasAssocResponse() &&
1777 perStaProfile.GetAssocResponse().m_statusCode.IsSuccess())
1778 {
1779 perStaProfile.GetAssocResponse().m_aid = aid;
1780 }
1781 }
1782 }
1783}
1784
1785void
1786ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1787{
1788 NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1789 WifiMacHeader hdr;
1792 hdr.SetAddr1(to);
1795 hdr.SetDsNotFrom();
1796 hdr.SetDsNotTo();
1797
1798 MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1799
1800 // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1801 // Request frame that carries a Basic Multi-Link element shall include a Basic
1802 // Multi-Link element in the (Re)Association Response frame that it transmits
1803 // (Sec. 35.3.5.4 of 802.11be D2.0)
1804 // If the STA included a Multi-Link Element in the (Re)Association Request, we
1805 // stored its MLD address in the remote station manager
1806 if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1807 {
1808 assoc.Get<MultiLinkElement>() = GetMultiLinkElement(linkId, hdr.GetType(), to);
1809 }
1810
1811 auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1812 SetAid(assoc, linkIdStaAddrMap);
1813
1814 Ptr<Packet> packet = Create<Packet>();
1815 packet->AddHeader(assoc);
1816
1817 if (!GetQosSupported())
1818 {
1819 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1820 }
1821 // "A QoS STA that transmits a Management frame determines access category used
1822 // for medium access in transmission of the Management frame as follows
1823 // (If dot11QMFActivated is false or not present)
1824 // — If the Management frame is individually addressed to a non-QoS STA, category
1825 // AC_BE should be selected.
1826 // — If category AC_BE was not selected by the previous step, category AC_VO
1827 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1828 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1829 {
1830 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1831 }
1832 else
1833 {
1834 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1835 }
1836}
1837
1838void
1840{
1841 NS_LOG_FUNCTION(this << +linkId);
1842 auto& link = GetLink(linkId);
1843 WifiMacHeader hdr;
1846 hdr.SetAddr2(link.feManager->GetAddress());
1847 hdr.SetAddr3(link.feManager->GetAddress());
1848 hdr.SetDsNotFrom();
1849 hdr.SetDsNotTo();
1850 Ptr<Packet> packet = Create<Packet>();
1851 MgtBeaconHeader beacon;
1852 beacon.Get<Ssid>() = GetSsid();
1853 auto supportedRates = GetSupportedRates(linkId);
1854 beacon.Get<SupportedRates>() = supportedRates.rates;
1855 beacon.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1857 beacon.m_capability = GetCapabilities(linkId);
1858 beacon.Get<Tim>() = GetTim(linkId);
1859 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1860 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1861 if (GetDsssSupported(linkId))
1862 {
1863 beacon.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1864 }
1865 if (GetErpSupported(linkId))
1866 {
1867 beacon.Get<ErpInformation>() = GetErpInformation(linkId);
1868 }
1869 if (GetQosSupported())
1870 {
1871 beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1872 }
1873 if (GetHtSupported(linkId))
1874 {
1876 beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1877 beacon.Get<HtOperation>() = GetHtOperation(linkId);
1878 }
1879 if (GetVhtSupported(linkId))
1880 {
1881 beacon.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1882 beacon.Get<VhtOperation>() = GetVhtOperation(linkId);
1883 }
1884 if (GetHeSupported())
1885 {
1886 beacon.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1887 beacon.Get<HeOperation>() = GetHeOperation(linkId);
1888 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1889 {
1890 beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1891 }
1892 if (Is6GhzBand(linkId))
1893 {
1894 beacon.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
1895 }
1896 }
1897 if (GetEhtSupported())
1898 {
1899 beacon.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1900 beacon.Get<EhtOperation>() = GetEhtOperation(linkId);
1901
1902 if (GetNLinks() > 1)
1903 {
1904 /*
1905 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1906 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1907 * include a TBTT Information field in a Reduced Neighbor Report element with the
1908 * TBTT Information Length field set to 16 or higher, for each of the other APs
1909 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1910 */
1911 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1912 {
1913 beacon.Get<ReducedNeighborReport>() = std::move(*rnr);
1914 }
1915 /*
1916 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1917 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1918 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1919 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1920 * channel switching, extended channel switching, and channel quieting) are
1921 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1922 */
1924 }
1925 }
1926 packet->AddHeader(beacon);
1927
1928 NS_LOG_INFO("Generating beacon from " << link.feManager->GetAddress() << " linkID " << +linkId);
1929 // The beacon has it's own special queue, so we load it in there
1930 m_beaconTxop->Queue(Create<WifiMpdu>(packet, hdr));
1931 link.beaconEvent =
1933
1935
1936 // If a STA that does not support Short Slot Time associates,
1937 // the AP shall use long slot time beginning at the first Beacon
1938 // subsequent to the association of the long slot time STA.
1939 if (GetErpSupported(linkId))
1940 {
1941 if (link.shortSlotTimeEnabled)
1942 {
1943 // Enable short slot time
1944 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1945 }
1946 else
1947 {
1948 // Disable short slot time
1949 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1950 }
1951 }
1952
1953 // Update the DTIM Count
1954 auto& dtimCount = GetLink(linkId).beaconDtimCount;
1955 dtimCount = dtimCount == 0 ? (m_dtimPeriod - 1) : (dtimCount - 1);
1956
1957 const auto& tim = beacon.Get<Tim>();
1958 NS_ASSERT(tim);
1959 if (tim->m_dtimCount == 0 && tim->m_hasMulticastPending)
1960 {
1961 // connect a callback to intercept the transmission of the Beacon frame and start
1962 // transmitting the pending group addressed frames
1963 link.phy->TraceConnectWithoutContext(
1964 "PhyTxPsduBegin",
1966 }
1967}
1968
1969void
1971 WifiConstPsduMap psduMap,
1972 WifiTxVector /* txVector */,
1973 Watt_u /* txPower */)
1974{
1975 NS_LOG_FUNCTION(this << linkId);
1976
1977 if (psduMap.size() > 1 || !psduMap.cbegin()->second->GetHeader(0).IsBeacon())
1978 {
1979 return;
1980 }
1981
1982 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
1983
1984 std::map<AcIndex, bool> hasFramesToTransmit;
1985 for (const auto aci : acList)
1986 {
1987 // save the status of the AC queues before unblocking the queues
1988 hasFramesToTransmit[aci] = GetTxopFor(aci)->HasFramesToTransmit(linkId);
1989 }
1990
1991 NS_LOG_DEBUG("Unblock transmission of group addressed frames on link " << +linkId);
1993 {linkId},
1995
1996 NS_LOG_DEBUG("Block transmission of unicast frames on link " << +linkId);
1998 {linkId},
2000
2001 for (const auto aci : acList)
2002 {
2003 GetTxopFor(aci)->StartAccessAfterEvent(linkId,
2004 hasFramesToTransmit[aci],
2006 }
2007
2008 // the Beacon frame has been intercepted, we can disconnect the callback (right after all
2009 // callbacks connected to the trace source are called)
2010 Simulator::ScheduleNow([=, this]() {
2011 GetLink(linkId).phy->TraceDisconnectWithoutContext(
2012 "PhyTxPsduBegin",
2014 });
2015
2016 // connect another callback to be notified of packets removed from the MAC queues; this is
2017 // needed to detect that all pending group addressed frames have been transmitted
2018 for (const auto aci : acList)
2019 {
2020 GetTxopQueue(aci)->TraceConnectWithoutContext(
2021 "Dequeue",
2023 GetTxopQueue(aci)->TraceConnectWithoutContext(
2024 "Drop",
2026 }
2027
2028 // check that the AP actually has group addressed frames to transmit
2030}
2031
2032void
2034{
2035 NS_LOG_FUNCTION(this << linkId);
2036
2037 if (!GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(
2038 linkId,
2041 {
2042 NS_LOG_DEBUG("Unicast frames are not blocked on link " << +linkId << ", nothing to do");
2043 return;
2044 }
2045
2046 const auto acList = GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
2047
2048 // when this function is called right after sending the Beacon frame, no MPDU is passed
2049 const auto noGroupAddressed =
2050 !mpdu && std::all_of(acList.cbegin(), acList.cend(), [=, this](const auto aci) {
2051 return (GetTxopQueue(aci)->PeekFirstAvailable(linkId) == nullptr);
2052 });
2053 const auto lastGroupAddressed =
2054 mpdu && mpdu->GetHeader().GetAddr1().IsGroup() && !mpdu->GetHeader().IsMoreData();
2055
2056 if (noGroupAddressed || lastGroupAddressed)
2057 {
2058 NS_LOG_DEBUG((noGroupAddressed ? "No group addressed frames queued for link "
2059 : "Sent a group addressed frame with More Data=0 on link ")
2060 << +linkId);
2061
2062 std::map<AcIndex, bool> hasFramesToTransmit;
2063 for (const auto aci : acList)
2064 {
2065 // save the status of the AC queues before unblocking the queues
2066 hasFramesToTransmit[aci] = GetTxopFor(aci)->HasFramesToTransmit(linkId);
2067 }
2068
2070 {linkId},
2073 {linkId},
2075 // do not block transmission of Beacon frames
2077 AC_BEACON,
2080 GetFrameExchangeManager(linkId)->GetAddress());
2081
2082 for (const auto aci : acList)
2083 {
2084 GetTxopFor(aci)->StartAccessAfterEvent(linkId,
2085 hasFramesToTransmit[aci],
2087 }
2088
2089 // disconnect callbacks (right after all callbacks connected to the trace source are called)
2090 Simulator::ScheduleNow([=, this]() {
2091 for (const auto aci : acList)
2092 {
2093 GetTxopQueue(aci)->TraceDisconnectWithoutContext(
2094 "Dequeue",
2096 GetTxopQueue(aci)->TraceDisconnectWithoutContext(
2097 "Drop",
2099 }
2100 });
2101 }
2102}
2103
2105ApWifiMac::GetFilsDiscovery(uint8_t linkId) const
2106{
2109 auto& link = GetLink(linkId);
2110 hdr.SetAddr2(link.feManager->GetAddress());
2111 hdr.SetAddr3(link.feManager->GetAddress());
2112 hdr.SetDsNotFrom();
2113 hdr.SetDsNotTo();
2114
2115 WifiActionHeader actionHdr;
2117 action.publicAction = WifiActionHeader::FILS_DISCOVERY;
2118 actionHdr.SetAction(WifiActionHeader::PUBLIC, action);
2119
2120 FilsDiscHeader fils;
2121 fils.SetSsid(GetSsid().PeekString());
2122 fils.m_beaconInt = (m_beaconInterval / WIFI_TU).GetHigh();
2123
2125 fils.m_fdCap->SetOpChannelWidth(link.phy->GetChannelWidth());
2126 fils.m_fdCap->SetMaxNss(std::min(link.phy->GetMaxSupportedTxSpatialStreams(),
2127 link.phy->GetMaxSupportedRxSpatialStreams()));
2128 fils.m_fdCap->SetStandard(link.phy->GetStandard());
2129
2130 fils.SetLengthSubfield();
2131 fils.m_rnr = GetReducedNeighborReport(linkId);
2132
2133 auto packet = Create<Packet>();
2134 packet->AddHeader(fils);
2135 packet->AddHeader(actionHdr);
2136
2137 return Create<WifiMpdu>(packet, hdr);
2138}
2139
2140void
2142{
2143 NS_LOG_FUNCTION(this << linkId);
2144 auto phy = GetLink(linkId).phy;
2145
2146 auto fdBeaconInterval = (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) ? m_fdBeaconInterval6GHz
2148
2149 if (!fdBeaconInterval.IsStrictlyPositive())
2150 {
2151 NS_LOG_DEBUG("Sending FILS Discovery/unsolicited Probe Response disabled");
2152 return;
2153 }
2154
2155 // Schedule FD or unsolicited Probe Response frames (IEEE Std 802.11ax-2021 26.17.2.3.2)
2156 for (uint8_t count = 1; count < (m_beaconInterval / fdBeaconInterval).GetHigh(); ++count)
2157 {
2159 {
2160 Simulator::Schedule(fdBeaconInterval * count,
2162 this,
2163 GetProbeResp(linkId, std::nullopt),
2165 linkId);
2166 }
2167 else
2168 {
2169 Simulator::Schedule(fdBeaconInterval * count,
2170 [=, this]() { m_beaconTxop->Queue(GetFilsDiscovery(linkId)); });
2171 }
2172 }
2173}
2174
2175void
2177{
2178 NS_LOG_FUNCTION(this << *mpdu);
2179 const WifiMacHeader& hdr = mpdu->GetHeader();
2180
2181 if (hdr.IsAssocResp() || hdr.IsReassocResp())
2182 {
2183 MgtAssocResponseHeader assocResp;
2184 mpdu->GetPacket()->PeekHeader(assocResp);
2185 auto aid = assocResp.m_aid;
2186
2187 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
2188 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
2189
2190 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
2191 {
2192 NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
2193 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxOk(hdr.GetAddr1());
2194 m_assocLogger(aid, hdr.GetAddr1());
2195 }
2196
2197 if (auto staMldAddress =
2198 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
2199 staMldAddress.has_value())
2200 {
2201 /**
2202 * The STA is affiliated with an MLD. From Sec. 35.3.7.1.4 of 802.11be D3.0:
2203 * When a link becomes enabled for a non-AP STA that is affiliated with a non-AP MLD
2204 * after successful association with an AP MLD with (Re)Association Request/Response
2205 * frames transmitted on another link [...], the power management mode of the non-AP
2206 * STA, immediately after the acknowledgement of the (Re)Association Response frame
2207 * [...], is power save mode, and its power state is doze.
2208 *
2209 * Thus, STAs operating on all the links but the link used to establish association
2210 * transition to power save mode.
2211 */
2212 for (uint8_t i = 0; i < GetNLinks(); i++)
2213 {
2214 auto stationManager = GetWifiRemoteStationManager(i);
2215 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
2216 staAddress.has_value() && i != *linkId &&
2217 stationManager->IsWaitAssocTxOk(*staAddress))
2218 {
2220 << " associated with STA=" << *staAddress);
2221 stationManager->RecordGotAssocTxOk(*staAddress);
2222 m_assocLogger(aid, *staAddress);
2223 StaSwitchingToPsMode(*staAddress, i);
2224 }
2225 }
2226
2227 // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
2229 }
2230
2231 if (auto extendedCapabilities =
2232 GetWifiRemoteStationManager(*linkId)->GetStationExtendedCapabilities(
2233 hdr.GetAddr1());
2235 {
2236 const auto isGcrCapable =
2237 extendedCapabilities && extendedCapabilities->m_robustAvStreaming;
2238 m_gcrManager->NotifyStaAssociated(hdr.GetAddr1(), isGcrCapable);
2239 }
2240 }
2241 else if (hdr.IsAction())
2242 {
2243 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
2244 category == WifiActionHeader::PROTECTED_EHT &&
2245 action.protectedEhtAction ==
2247 {
2248 // the EMLSR client acknowledged the EML Operating Mode Notification frame;
2249 // we can stop the timer and enforce the configuration deriving from the
2250 // EML Notification frame sent by the EMLSR client
2251 if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
2252 eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsPending())
2253 {
2254 // no need to wait until the expiration of the transition timeout
2255 eventIt->second.PeekEventImpl()->Invoke();
2256 eventIt->second.Cancel();
2257 }
2258 }
2259 }
2260}
2261
2262void
2264{
2265 NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
2266 const WifiMacHeader& hdr = mpdu->GetHeader();
2267
2268 if (hdr.IsAssocResp() || hdr.IsReassocResp())
2269 {
2270 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
2271 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
2272
2273 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
2274 {
2275 NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
2276 << " association failed with STA=" << hdr.GetAddr1());
2277 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxFailed(hdr.GetAddr1());
2278 }
2279
2280 if (auto staMldAddress =
2281 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
2282 staMldAddress.has_value())
2283 {
2284 // the STA is affiliated with an MLD
2285 for (uint8_t i = 0; i < GetNLinks(); i++)
2286 {
2287 auto stationManager = GetWifiRemoteStationManager(i);
2288 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
2289 staAddress.has_value() && i != *linkId &&
2290 stationManager->IsWaitAssocTxOk(*staAddress))
2291 {
2293 << " association failed with STA=" << *staAddress);
2294 stationManager->RecordGotAssocTxFailed(*staAddress);
2295 }
2296 }
2297 }
2298
2299 // free the assigned AID
2300 MgtAssocResponseHeader assocResp;
2301 mpdu->GetPacket()->PeekHeader(assocResp);
2302 auto aid = assocResp.m_aid;
2303 m_aidToMldOrLinkAddress.erase(aid);
2304 for (const auto& [id, lnk] : GetLinks())
2305 {
2306 auto& link = GetLink(id);
2307 link.staList.erase(aid);
2308 }
2309 }
2310}
2311
2312void
2314{
2315 NS_LOG_FUNCTION(this << *mpdu << linkId);
2316
2317 Mac48Address staAddr = mpdu->GetHeader().GetAddr2();
2318 bool staInPsMode = GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr);
2319
2320 if (!staInPsMode && mpdu->GetHeader().IsPowerManagement())
2321 {
2322 // the sending STA is switching to Power Save mode
2323 StaSwitchingToPsMode(staAddr, linkId);
2324 }
2325 else if (staInPsMode && !mpdu->GetHeader().IsPowerManagement())
2326 {
2327 // the sending STA is switching back to Active mode
2329 }
2330}
2331
2332void
2333ApWifiMac::StaSwitchingToPsMode(const Mac48Address& staAddr, uint8_t linkId)
2334{
2335 NS_LOG_FUNCTION(this << staAddr << linkId);
2336
2337 auto rsm = GetWifiRemoteStationManager(linkId);
2338 if (rsm->IsInPsMode(staAddr))
2339 {
2340 NS_LOG_DEBUG(staAddr << " is already in PS mode, nothing to do");
2341 return;
2342 }
2343
2344 rsm->SetPsMode(staAddr, true);
2345
2346 // Block frames addressed to the STA in PS mode
2347 NS_LOG_DEBUG("Block destination " << staAddr << " on link " << +linkId);
2348 auto staMldAddr = rsm->GetMldAddress(staAddr).value_or(staAddr);
2350
2351 if (GetLink(linkId).nStationsInPsMode++ == 0)
2352 {
2353 // this is the first associated STA switching to PS mode. Group addressed frames shall be
2354 // sent after Beacon frames including a DTIM
2355 NS_LOG_DEBUG("Block transmission of group addressed frames on link " << +linkId);
2357 {linkId},
2359 // do not block transmission of Beacon frames
2361 AC_BEACON,
2364 GetFrameExchangeManager(linkId)->GetAddress());
2365 }
2366}
2367
2368void
2370{
2371 NS_LOG_FUNCTION(this << staAddr << linkId);
2372
2373 if (!GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr))
2374 {
2375 NS_LOG_DEBUG(staAddr << " is already in active mode, nothing to do");
2376 return;
2377 }
2378
2379 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, false);
2380
2381 // unblock transmissions to the station
2382 NS_LOG_DEBUG("Unblock destination " << staAddr << " on link " << +linkId);
2383 auto staMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
2385
2386 if (--GetLink(linkId).nStationsInPsMode == 0)
2387 {
2388 // the last STA in PS mode switched back to active mode or deassociated. No need to
2389 // keep blocking group addressed frames
2390 NS_LOG_DEBUG("Unblock transmission of group addressed frames on link " << +linkId);
2392 {linkId},
2394 }
2395}
2396
2397std::size_t
2399{
2400 return GetLink(linkId).nStationsInPsMode;
2401}
2402
2403std::optional<uint8_t>
2405{
2406 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
2407 {
2408 if (GetWifiRemoteStationManager(linkId)->IsAssociated(address))
2409 {
2410 return linkId;
2411 }
2412 }
2413 NS_LOG_DEBUG(address << " is not associated");
2414 return std::nullopt;
2415}
2416
2419{
2420 auto linkId = IsAssociated(remoteAddr);
2421 NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
2422 return GetFrameExchangeManager(*linkId)->GetAddress();
2423}
2424
2425std::optional<Mac48Address>
2427{
2428 if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
2429 staIt != m_aidToMldOrLinkAddress.cend())
2430 {
2431 return staIt->second;
2432 }
2433 return std::nullopt;
2434}
2435
2436void
2438{
2439 NS_LOG_FUNCTION(this << *mpdu << +linkId);
2440 // consider the MAC header of the original MPDU (makes a difference for data frames only)
2441 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
2442 Ptr<const Packet> packet = mpdu->GetPacket();
2443 Mac48Address from = hdr->GetAddr2();
2444 if (hdr->IsData())
2445 {
2446 std::optional<uint8_t> apLinkId;
2447 if (!hdr->IsFromDs() && hdr->IsToDs() &&
2448 (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
2449 mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
2450 {
2451 // this MPDU is being acknowledged by the AP, so we can process
2452 // the Power Management flag
2453 ProcessPowerManagementFlag(mpdu, *apLinkId);
2454
2455 Mac48Address to = hdr->GetAddr3();
2456 // Address3 can be our MLD address (e.g., this is an MPDU containing a single MSDU
2457 // addressed to us) or a BSSID (e.g., this is an MPDU containing an A-MSDU)
2458 if (to == GetAddress() ||
2459 (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
2460 {
2461 NS_LOG_DEBUG("frame for me from=" << from);
2462 if (hdr->IsQosData())
2463 {
2464 if (hdr->IsQosAmsdu())
2465 {
2466 NS_LOG_DEBUG("Received A-MSDU from=" << from
2467 << ", size=" << packet->GetSize());
2469 packet = nullptr;
2470 }
2471 else if (hdr->HasData())
2472 {
2473 ForwardUp(packet, from, GetAddress());
2474 }
2475 }
2476 else if (hdr->HasData())
2477 {
2478 ForwardUp(packet, from, GetAddress());
2479 }
2480 }
2481 else if (to.IsGroup() || IsAssociated(to))
2482 {
2483 NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
2484 Ptr<Packet> copy = packet->Copy();
2485
2486 // If the frame we are forwarding is of type QoS Data,
2487 // then we need to preserve the UP in the QoS control
2488 // header...
2489 if (hdr->IsQosData())
2490 {
2491 WifiMac::Enqueue(copy, to, from, hdr->GetQosTid());
2492 }
2493 else
2494 {
2495 WifiMac::Enqueue(copy, to, from);
2496 }
2497 ForwardUp(packet, from, to);
2498 }
2499 else if (hdr->HasData())
2500 {
2501 ForwardUp(packet, from, to);
2502 }
2503 }
2504 // NOLINTBEGIN(bugprone-branch-clone)
2505 else if (hdr->IsFromDs() && hdr->IsToDs())
2506 {
2507 // this is an AP-to-AP frame
2508 // we ignore for now.
2509 NotifyRxDrop(packet);
2510 }
2511 // NOLINTEND(bugprone-branch-clone)
2512 else
2513 {
2514 // we can ignore these frames since
2515 // they are not targeted at the AP
2516 NotifyRxDrop(packet);
2517 }
2518 return;
2519 }
2520 else if (hdr->IsMgt())
2521 {
2522 if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress() &&
2524 {
2525 // this MPDU is being acknowledged by the AP, so we can process
2526 // the Power Management flag
2527 ProcessPowerManagementFlag(mpdu, linkId);
2528 }
2529 if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
2530 hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
2531 {
2532 // In the case where the Address 1 field contains a group address, the
2533 // Address 3 field also is validated to verify that the group addressed
2534 // frame originated from a STA in the BSS of which the receiving STA is
2535 // a member (Section 9.3.3.1 of 802.11-2020)
2536 if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
2537 hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
2538 {
2539 // not addressed to us
2540 return;
2541 }
2542 MgtProbeRequestHeader probeRequestHeader;
2543 packet->PeekHeader(probeRequestHeader);
2544 const auto& ssid = probeRequestHeader.Get<Ssid>();
2545 if (ssid == GetSsid() || ssid->IsBroadcast())
2546 {
2547 NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
2548 const auto isReqBcast = hdr->GetAddr1().IsGroup() && hdr->GetAddr3().IsBroadcast();
2549 // not an ML Probe Request if ADDR1 and ADDR3 are broadcast
2550 const auto probeResp = GetProbeResp(
2551 linkId,
2552 isReqBcast ? std::nullopt : probeRequestHeader.Get<MultiLinkElement>());
2553 EnqueueProbeResp(probeResp, from, linkId);
2554 }
2555 return;
2556 }
2557 else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
2558 {
2559 switch (hdr->GetType())
2560 {
2563 NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
2564 << " request received from " << from
2565 << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
2566
2567 MgtAssocRequestHeader assocReq;
2568 MgtReassocRequestHeader reassocReq;
2569 AssocReqRefVariant frame = assocReq;
2570 if (hdr->IsAssocReq())
2571 {
2572 packet->PeekHeader(assocReq);
2573 }
2574 else
2575 {
2576 packet->PeekHeader(reassocReq);
2577 frame = reassocReq;
2578 }
2579 if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
2580 {
2581 ParseReportedStaInfo(frame, from, linkId);
2582 }
2583 SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
2584 return;
2585 }
2587 NS_LOG_DEBUG("Disassociation received from " << from);
2588 const auto aid = GetAssociationId(from, linkId);
2589 if (aid == SU_STA_ID)
2590 {
2591 NS_LOG_DEBUG("Station " << from << " is not associated");
2592 return;
2593 }
2594 const auto address =
2595 GetWifiRemoteStationManager(linkId)->GetMldAddress(from).value_or(from);
2596 m_deAssocLogger(aid, address);
2597 if (m_gcrManager)
2598 {
2599 m_gcrManager->NotifyStaDeassociated(address);
2600 }
2601
2602 for (const auto& [id, lnk] : GetLinks())
2603 {
2604 auto& link = GetLink(id);
2605 auto it = link.staList.find(aid);
2606
2607 if (it == link.staList.cend())
2608 {
2609 continue; // STA has not setup this link
2610 }
2611
2612 // a STA operating on this link is associated with the AP
2614 link.staList.erase(it);
2615 m_aidToMldOrLinkAddress.erase(aid);
2616 GetWifiRemoteStationManager(id)->RecordDisassociated(address);
2618 !GetWifiRemoteStationManager(id)->GetErpOfdmSupported(address))
2619 {
2620 link.numNonErpStations--;
2621 }
2622 if (!GetWifiRemoteStationManager(id)->GetHtSupported(address) &&
2623 !GetWifiRemoteStationManager(id)->GetStationHe6GhzCapabilities(address))
2624 {
2625 link.numNonHtStations--;
2626 }
2629 }
2630 return;
2631 }
2632 case WIFI_MAC_MGT_ACTION: {
2633 auto pkt = mpdu->GetPacket()->Copy();
2634 auto [category, action] = WifiActionHeader::Remove(pkt);
2635 if (category == WifiActionHeader::PROTECTED_EHT &&
2636 action.protectedEhtAction ==
2638 IsAssociated(hdr->GetAddr2()))
2639 {
2640 // received an EML Operating Mode Notification frame from an associated station
2641 MgtEmlOmn frame;
2642 pkt->RemoveHeader(frame);
2643 ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
2644 RespondToEmlOmn(frame, hdr->GetAddr2(), linkId);
2645 return;
2646 }
2647 break;
2648 }
2649 default:;
2650 // do nothing
2651 }
2652 }
2653 }
2654
2655 // Invoke the receive handler of our parent class to deal with any other frames
2656 WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
2657}
2658
2659bool
2661 const Mac48Address& from,
2662 uint8_t linkId)
2663{
2664 NS_LOG_FUNCTION(this << from << +linkId);
2665
2666 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
2667
2668 auto failure = [&](const std::string& msg) -> bool {
2669 NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
2670 remoteStationManager->RecordAssocRefused(from);
2671 return false;
2672 };
2673
2674 // lambda to process received (Re)Association Request
2675 auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
2676 const auto& frame = frameRefWrapper.get();
2677
2678 // first, verify that the the station's supported
2679 // rate set is compatible with our Basic Rate set
2680 const CapabilityInformation& capabilities = frame.m_capability;
2681 remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
2682 NS_ASSERT(frame.template Get<SupportedRates>());
2683 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
2684 frame.template Get<ExtendedSupportedRatesIE>()};
2685
2686 if (rates.GetNRates() == 0)
2687 {
2688 return failure("STA's supported rate set not compatible with our Basic Rate set");
2689 }
2690
2691 if (GetHtSupported(linkId))
2692 {
2693 // check whether the HT STA supports all MCSs in Basic MCS Set
2694 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2695 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
2696 {
2697 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2698 {
2699 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2700 if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
2701 {
2702 return failure("HT STA does not support all MCSs in Basic MCS Set");
2703 }
2704 }
2705 }
2706 }
2707 if (GetVhtSupported(linkId))
2708 {
2709 // check whether the VHT STA supports all MCSs in Basic MCS Set
2710 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2711 if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
2712 {
2713 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2714 {
2715 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2716 if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2717 {
2718 return failure("VHT STA does not support all MCSs in Basic MCS Set");
2719 }
2720 }
2721 }
2722 }
2723 if (GetHeSupported())
2724 {
2725 // check whether the HE STA supports all MCSs in Basic MCS Set
2726 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2727 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2728 {
2729 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2730 {
2731 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2732 if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2733 {
2734 return failure("HE STA does not support all MCSs in Basic MCS Set");
2735 }
2736 }
2737 }
2738 if (Is6GhzBand(linkId))
2739 {
2740 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
2741 {
2742 remoteStationManager->AddStationHe6GhzCapabilities(from, *he6GhzCapabilities);
2743 }
2744 }
2745 }
2746 if (GetEhtSupported())
2747 {
2748 // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
2749 auto ehtConfig = GetEhtConfiguration();
2750 NS_ASSERT(ehtConfig);
2751
2752 if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
2753 !tidLinkMapping.empty())
2754 {
2755 // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
2756 // We refuse association if we do not support TID-to-Link mapping negotiation
2757 // or the non-AP MLD included more than two TID-to-Link Mapping IEs
2758 // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
2759 // or there is some TID that is not mapped to any link
2760 // or the direction(s) is/are not set properly
2761 if (tidLinkMapping.size() > 2)
2762 {
2763 return failure("More than two TID-to-Link Mapping IEs");
2764 }
2765
2766 // if only one Tid-to-Link Mapping element is present, it must be valid for
2767 // both directions
2768 bool bothDirIfOneTlm =
2769 tidLinkMapping.size() != 1 ||
2770 tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
2771 // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
2772 // Request frame or a (Re)Association Response frame shall set the Direction
2773 // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
2774 // subfield in the other TID-To- Link Mapping element to 1.
2775 // (Sec. 35.3.7.1.8 of 802.11be D3.1)
2776 bool distinctDirsIfTwoTlms =
2777 tidLinkMapping.size() != 2 ||
2778 (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2779 tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2780 tidLinkMapping[0].m_control.direction !=
2781 tidLinkMapping[1].m_control.direction);
2782
2783 if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
2784 {
2785 return failure("Incorrect directions in TID-to-Link Mapping IEs");
2786 }
2787
2788 if (ehtConfig->m_tidLinkMappingSupport ==
2790 {
2791 return failure("TID-to-Link Mapping negotiation not supported");
2792 }
2793
2794 auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
2795 if (tlmIe.m_control.defaultMapping)
2796 {
2797 return;
2798 }
2799 for (uint8_t tid = 0; tid < 8; tid++)
2800 {
2801 if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
2802 {
2803 mapping.emplace(tid, std::move(linkSet));
2804 }
2805 }
2806 };
2807
2808 WifiTidLinkMapping dlMapping;
2809 WifiTidLinkMapping ulMapping;
2810
2811 switch (tidLinkMapping[0].m_control.direction)
2812 {
2814 getMapping(tidLinkMapping.at(0), dlMapping);
2815 ulMapping = dlMapping;
2816 break;
2818 getMapping(tidLinkMapping.at(0), dlMapping);
2819 getMapping(tidLinkMapping.at(1), ulMapping);
2820 break;
2822 getMapping(tidLinkMapping.at(0), ulMapping);
2823 getMapping(tidLinkMapping.at(1), dlMapping);
2824 break;
2825 }
2826
2827 if (ehtConfig->m_tidLinkMappingSupport ==
2829 !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
2830 {
2831 return failure("Mapping TIDs to distinct link sets is incompatible with "
2832 "negotiation support of 1");
2833 }
2834
2835 // otherwise, we accept the TID-to-link Mapping and store it
2836 const auto& mle = frame.template Get<MultiLinkElement>();
2837 NS_ASSERT_MSG(mle,
2838 "Multi-Link Element not present in an Association Request including "
2839 "TID-to-Link Mapping element(s)");
2840 auto mldAddr = mle->GetMldMacAddress();
2841
2842 // The requested link mappings are valid and can be accepted; store them.
2844 UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
2845 }
2846 }
2847
2848 // The association request from the station can be accepted.
2849 // Record all its supported modes in its associated WifiRemoteStation
2850 auto phy = GetWifiPhy(linkId);
2851
2852 for (const auto& mode : phy->GetModeList())
2853 {
2854 if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
2855 {
2856 remoteStationManager->AddSupportedMode(from, mode);
2857 }
2858 }
2859 if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
2860 capabilities.IsShortSlotTime())
2861 {
2862 remoteStationManager->AddSupportedErpSlotTime(from, true);
2863 }
2864 if (GetHtSupported(linkId))
2865 {
2866 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2867 if (htCapabilities.has_value())
2868 {
2869 remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
2870 }
2871 const auto& extendedCapabilities = frame.template Get<ExtendedCapabilities>();
2872 if (extendedCapabilities.has_value())
2873 {
2874 remoteStationManager->AddStationExtendedCapabilities(from, *extendedCapabilities);
2875 }
2876 }
2877 if (GetVhtSupported(linkId))
2878 {
2879 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2880 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
2881 // to check whether it supports VHT
2882 if (vhtCapabilities.has_value() &&
2883 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
2884 {
2885 remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
2886 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
2887 {
2888 if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2889 {
2890 remoteStationManager->AddSupportedMcs(from, mcs);
2891 // here should add a control to add basic MCS when it is implemented
2892 }
2893 }
2894 }
2895 }
2896 if (GetHeSupported())
2897 {
2898 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2899 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2900 {
2901 remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
2902 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
2903 {
2904 if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2905 {
2906 remoteStationManager->AddSupportedMcs(from, mcs);
2907 // here should add a control to add basic MCS when it is implemented
2908 }
2909 }
2910 }
2911 }
2912 if (GetEhtSupported())
2913 {
2914 if (const auto& ehtCapabilities = frame.template Get<EhtCapabilities>())
2915 {
2916 remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
2917 }
2918 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
2919 {
2920 // TODO: Add check whether MCS is supported from the capabilities
2921 remoteStationManager->AddSupportedMcs(from, mcs);
2922 // here should add a control to add basic MCS when it is implemented
2923 }
2924 }
2925
2926 NS_LOG_DEBUG("Association Request from " << from << " accepted");
2927 remoteStationManager->RecordWaitAssocTxOk(from);
2928 return true;
2929 };
2930
2931 return std::visit(recvAssocRequest, assoc);
2932}
2933
2934void
2936{
2937 NS_LOG_FUNCTION(this << from << +linkId);
2938
2939 // lambda to process received Multi-Link Element
2940 auto recvMle = [&](auto&& frame) {
2941 const auto& mle = frame.get().template Get<MultiLinkElement>();
2942
2943 if (!mle.has_value())
2944 {
2945 return;
2946 }
2947
2948 auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
2949 GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
2950
2951 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
2952 {
2953 auto& perStaProfile = mle->GetPerStaProfile(i);
2954 if (!perStaProfile.HasStaMacAddress())
2955 {
2956 NS_LOG_DEBUG("[i=" << i
2957 << "] Cannot setup a link if the STA MAC address is missing");
2958 continue;
2959 }
2960 uint8_t newLinkId = perStaProfile.GetLinkId();
2961 if (newLinkId == linkId || newLinkId >= GetNLinks())
2962 {
2963 NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
2964 continue;
2965 }
2966 if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
2967 {
2968 NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
2969 continue;
2970 }
2971
2972 ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
2973 perStaProfile.GetStaMacAddress(),
2974 newLinkId);
2975 GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
2976 perStaProfile.GetStaMacAddress(),
2977 mleCommonInfo);
2978 }
2979 };
2980
2981 std::visit(recvMle, assoc);
2982}
2983
2984void
2985ApWifiMac::ReceiveEmlOmn(const MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
2986{
2987 NS_LOG_FUNCTION(this << frame << sender << linkId);
2988
2989 auto ehtConfiguration = GetEhtConfiguration();
2990
2991 if (!ehtConfiguration || !ehtConfiguration->m_emlsrActivated)
2992 {
2994 "Received an EML Operating Mode Notification frame but EMLSR is not activated");
2995 return;
2996 }
2997
2999 {
3001 auto emlCapabilities =
3002 GetWifiRemoteStationManager(linkId)->GetStationEmlCapabilities(sender);
3003 NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
3004
3005 // update values stored in remote station manager
3006 emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
3007 emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
3008 }
3009}
3010
3011void
3012ApWifiMac::RespondToEmlOmn(MgtEmlOmn frame, const Mac48Address& sender, uint8_t linkId)
3013{
3014 NS_LOG_FUNCTION(this << frame << sender << linkId);
3015
3016 // The AP MLD has to consider the changes carried by the received EML Notification frame
3017 // as effective at the same time as the non-AP MLD. Therefore, we need to start a time
3018 // when the transmission of the Ack following the received EML Notification frame is
3019 // completed. For this purpose, we connect a callback to the PHY TX begin trace to catch
3020 // the Ack transmitted after the EML Notification frame.
3022 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
3023 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
3024 psduMap.begin()->second->GetHeader(0).IsAck(),
3025 "Expected a Normal Ack after EML Notification frame");
3026
3027 auto ackDuration =
3028 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
3029
3031 Simulator::Schedule(ackDuration + GetEhtConfiguration()->m_transitionTimeout,
3033 this,
3034 frame,
3035 sender,
3036 linkId);
3037 });
3038
3039 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
3040 // after its transmission begins
3041 auto phy = GetLink(linkId).phy;
3042 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
3043 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
3044 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
3045
3046 // An AP MLD with dot11EHTEMLSROptionActivated equal to true sets the EMLSR Mode subfield
3047 // to the value obtained from the EMLSR Mode subfield of the received EML Operating Mode
3048 // Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
3049
3050 // When included in a frame sent by an AP affiliated with an AP MLD, the EMLSR Parameter
3051 // Update Control subfield is set to 0. (Sec. 9.6.35.8 of 802.11be D3.0)
3053
3054 // An AP MLD with dot11EHTEMLSROptionImplemented equal to true sets the EMLSR Link Bitmap
3055 // subfield to the value obtained from the EMLSR Link Bitmap subfield of the received
3056 // EML Operating Mode Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
3057
3058 // The EMLSR Parameter Update field [..] is present if [..] the Action frame is sent by
3059 // a non-AP STA affiliated with a non-AP MLD (Sec. 9.6.35.8 of 802.11be D3.0)
3060 frame.m_emlsrParamUpdate.reset();
3061
3063 ehtFem->SendEmlOmn(sender, frame);
3064}
3065
3066void
3068 const Mac48Address& sender,
3069 uint8_t linkId)
3070{
3071 NS_LOG_FUNCTION(this << frame << sender << linkId);
3072
3073 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
3074 NS_ASSERT_MSG(mldAddress, "No MLD address stored for STA " << sender);
3075 auto emlsrLinks =
3076 frame.m_emlControl.emlsrMode == 1 ? frame.GetLinkBitmap() : std::list<uint8_t>{};
3077
3078 for (uint8_t id = 0; id < GetNLinks(); id++)
3079 {
3080 auto linkAddress = GetWifiRemoteStationManager(id)->GetAffiliatedStaAddress(*mldAddress);
3081 if (!linkAddress)
3082 {
3083 // this link has not been setup by the non-AP MLD
3084 continue;
3085 }
3086
3087 if (!emlsrLinks.empty())
3088 {
3089 // the non-AP MLD is enabling EMLSR mode
3090 /**
3091 * After the successful transmission of the EML Operating Mode
3092 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
3093 * the non-AP MLD shall operate in the EMLSR mode and the other non-AP
3094 * STAs operating on the corresponding EMLSR links shall transition to
3095 * active mode after the transition delay indicated in the Transition
3096 * Timeout subfield in the EML Capabilities subfield of the Basic
3097 * Multi-Link element or immediately after receiving an EML Operating
3098 * Mode Notification frame from one of the APs operating on the EMLSR
3099 * links and affiliated with the AP MLD (Sec. 35.3.17 of 802.11be D3.0)
3100 */
3101 auto enabled =
3102 std::find(emlsrLinks.cbegin(), emlsrLinks.cend(), id) != emlsrLinks.cend();
3103 if (enabled)
3104 {
3106 }
3107 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, enabled);
3108 }
3109 else
3110 {
3111 // the non-AP MLD is disabling EMLSR mode
3112 /**
3113 * After the successful transmission of the EML Operating Mode
3114 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
3115 * the non-AP MLD shall disable the EMLSR mode and the other non-AP
3116 * STAs operating on the corresponding EMLSR links shall transition to
3117 * power save mode after the transition delay indicated in the
3118 * Transition Timeout subfield in the EML Capabilities subfield of the
3119 * Basic Multi-Link element or immediately after receiving an EML
3120 * Operating Mode Notification frame from one of the APs operating on
3121 * the EMLSR links and affiliated with the AP MLD. (Sec. 35.3.17 of
3122 * 802.11be D3.0)
3123 */
3124 if (id != linkId && GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*linkAddress))
3125 {
3126 StaSwitchingToPsMode(*linkAddress, id);
3127 }
3128 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, false);
3129 }
3130 }
3131}
3132
3133void
3135{
3136 NS_LOG_FUNCTION(this << *mpdu);
3137 for (auto& i : *PeekPointer(mpdu))
3138 {
3139 auto from = i.second.GetSourceAddr();
3140 auto to = i.second.GetDestinationAddr();
3141
3142 if (to.IsGroup() || IsAssociated(to))
3143 {
3144 NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
3145 WifiMac::Enqueue(i.first->Copy(), to, from, mpdu->GetHeader().GetQosTid());
3146 }
3147
3148 ForwardUp(i.first, from, to);
3149 }
3150}
3151
3152void
3154{
3155 NS_LOG_FUNCTION(this);
3156 m_beaconTxop->Initialize();
3157
3158 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
3159 {
3160 GetLink(linkId).beaconEvent.Cancel();
3162 {
3163 uint64_t jitterUs{0};
3165 {
3166 const auto value = m_beaconJitter->GetValue();
3167 NS_ABORT_MSG_IF(value < 0 || value > 1,
3168 "Jitter (" << value << ") must be between 0 and 1");
3169 jitterUs = static_cast<uint64_t>(value * (GetBeaconInterval().GetMicroSeconds()));
3170 }
3171
3172 NS_LOG_DEBUG("Scheduling initial beacon for access point "
3173 << GetAddress() << " at time " << jitterUs << "us");
3176 this,
3177 linkId);
3178 }
3181 }
3182
3183 if (m_gcrManager)
3184 {
3185 m_gcrManager->Initialize();
3186 }
3187
3192}
3193
3194bool
3196{
3197 bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
3198 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
3199 return useProtection;
3200}
3201
3202uint16_t
3204{
3205 const auto& links = GetLinks();
3206
3207 // if this is an AP MLD, AIDs from 1 to N, where N is 2^(Group_addr_BU_Indic_Exp + 1) - 1
3208 // shall not be allocated (see Section 35.3.15.1 of 802.11be D7.0)
3209 const uint16_t startAid = links.size() == 1 ? MIN_AID : (1 << (m_grpAddrBuIndicExp + 1));
3210
3211 // Return the first AID value between min and max that is free for all the links
3212 const auto maxAid = GetEhtSupported() ? EHT_MAX_AID : MAX_AID;
3213 for (uint16_t nextAid = startAid; nextAid <= maxAid; ++nextAid)
3214 {
3215 if (std::none_of(links.cbegin(), links.cend(), [&](auto&& idLinkPair) {
3216 return GetStaList(idLinkPair.first).contains(nextAid);
3217 }))
3218 {
3219 return nextAid;
3220 }
3221 }
3222 NS_FATAL_ERROR("No free association ID available!");
3223 return 0;
3224}
3225
3226const std::map<uint16_t, Mac48Address>&
3227ApWifiMac::GetStaList(uint8_t linkId) const
3228{
3229 return GetLink(linkId).staList;
3230}
3231
3232uint16_t
3234{
3235 return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
3236}
3237
3238uint8_t
3239ApWifiMac::GetBufferStatus(uint8_t tid, Mac48Address address) const
3240{
3241 auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
3242 if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
3243 {
3244 return 255;
3245 }
3246 return it->second.value;
3247}
3248
3249void
3250ApWifiMac::SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
3251{
3252 if (size == 255)
3253 {
3254 // no point in storing an unspecified size
3255 m_bufferStatus.erase(WifiAddressTidPair(address, tid));
3256 }
3257 else
3258 {
3259 m_bufferStatus[WifiAddressTidPair(address, tid)] = {size, Simulator::Now()};
3260 }
3261}
3262
3263uint8_t
3265{
3266 uint8_t maxSize = 0;
3267 bool found = false;
3268
3269 for (uint8_t tid = 0; tid < 8; tid++)
3270 {
3271 uint8_t size = GetBufferStatus(tid, address);
3272 if (size != 255)
3273 {
3274 maxSize = std::max(maxSize, size);
3275 found = true;
3276 }
3277 }
3278
3279 if (found)
3280 {
3281 return maxSize;
3282 }
3283 return 255;
3284}
3285
3286bool
3288 uint8_t tid) const
3289{
3291 return GetQosTxop(tid)->GetBaManager()->IsGcrAgreementEstablished(
3292 groupAddress,
3293 tid,
3294 m_gcrManager->GetMemberStasForGroupAddress(groupAddress));
3295}
3296
3297} // 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.
PairValue< EnumValue< AcIndex >, AttributeContainerValue< TimeValue, ',', std::vector > > TimeAccessParamsPairValue
AttributeValue type of a pair (ACI, access parameters of type Time).
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...
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.
PairValue< EnumValue< AcIndex >, AttributeContainerValue< UintegerValue, ',', std::vector > > UintAccessParamsPairValue
AttributeValue type of a pair (ACI, access parameters of type unsigned integer).
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.
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.
AttributeValue implementation for Boolean.
Definition boolean.h:26
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
AttributeValue implementation for Time.
Definition nstime.h:1375
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
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< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< 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
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1376
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1396
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
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:454
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.
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.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:463
const Time WIFI_TU
Wi-Fi Time Unit value in microseconds (see IEEE 802.11-2020 sec.
@ 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.
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.
std::tuple< WifiContainerQueueType, WifiRcvAddr, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:612
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
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).
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
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).
const Time DEFAULT_BEACON_INTERVAL
Default Beacon interval.
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....
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.