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-phy.h"
26
27#include "ns3/ap-emlsr-manager.h"
28#include "ns3/eht-configuration.h"
29#include "ns3/eht-frame-exchange-manager.h"
30#include "ns3/he-configuration.h"
31#include "ns3/ht-configuration.h"
32#include "ns3/log.h"
33#include "ns3/packet.h"
34#include "ns3/pointer.h"
35#include "ns3/random-variable-stream.h"
36#include "ns3/simulator.h"
37#include "ns3/string.h"
38
39namespace ns3
40{
41
42NS_LOG_COMPONENT_DEFINE("ApWifiMac");
43
45
46TypeId
48{
49 static TypeId tid =
50 TypeId("ns3::ApWifiMac")
52 .SetGroupName("Wifi")
53 .AddConstructor<ApWifiMac>()
54 .AddAttribute(
55 "BeaconInterval",
56 "Delay between two beacons",
57 TimeValue(MicroSeconds(102400)),
60 .AddAttribute("BeaconJitter",
61 "A uniform random variable to cause the initial beacon starting time "
62 "(after simulation time 0) "
63 "to be distributed between 0 and the BeaconInterval.",
64 StringValue("ns3::UniformRandomVariable"),
67 .AddAttribute("EnableBeaconJitter",
68 "If beacons are enabled, whether to jitter the initial send event.",
69 BooleanValue(true),
72 .AddAttribute("BeaconGeneration",
73 "Whether or not beacons are generated.",
74 BooleanValue(true),
77 .AddAttribute("FdBeaconInterval6GHz",
78 "Time between a Beacon frame and a FILS Discovery (FD) frame or between "
79 "two FD frames to be sent on a 6GHz link. A value of zero disables the "
80 "transmission of FD frames.",
81 TimeValue(Time{0}),
84 .AddAttribute("FdBeaconIntervalNon6GHz",
85 "Time between a Beacon frame and a FILS Discovery (FD) frame or between "
86 "two FD frames to be sent on a non-6GHz link. A value of zero disables "
87 "the transmission of FD frames.",
88 TimeValue(Time{0}),
91 .AddAttribute("SendUnsolProbeResp",
92 "Send unsolicited broadcast Probe Response instead of FILS Discovery",
93 BooleanValue(false),
96 .AddAttribute("EnableNonErpProtection",
97 "Whether or not protection mechanism should be used when non-ERP STAs "
98 "are present within the BSS."
99 "This parameter is only used when ERP is supported by the AP.",
100 BooleanValue(true),
103 .AddAttribute("BsrLifetime",
104 "Lifetime of Buffer Status Reports received from stations.",
108 .AddAttribute(
109 "CwMinsForSta",
110 "The CW min values that the AP advertises in EDCA Parameter Set elements and the "
111 "associated stations will use. The value of this attribute is an AC-indexed map "
112 "containing the CW min values for given ACs for all the links (sorted in "
113 "increasing order of link ID). If no values are provided for an AC, the same "
114 "values used by the AP are advertised. In case a string is used to set this "
115 "attribute, the string shall contain the pairs separated by a semicolon (;); "
116 "in every pair, the AC index and the list of values are separated by a blank "
117 "space, and the values of a list are separated by a comma (,) without spaces. "
118 "E.g. \"BE 31,31,31; VI 15,15,15\" defines the CW min values for AC BE and AC VI "
119 "for an AP MLD having three links.",
120 StringValue(""),
124 .AddAttribute(
125 "CwMaxsForSta",
126 "The CW max values that the AP advertises in EDCA Parameter Set elements and the "
127 "associated stations will use. The value of this attribute is an AC-indexed map "
128 "containing the CW max values for given ACs for all the links (sorted in "
129 "increasing order of link ID). If no values are provided for an AC, the same "
130 "values used by the AP are advertised. In case a string is used to set this "
131 "attribute, the string shall contain the pairs separated by a semicolon (;); "
132 "in every pair, the AC index and the list of values are separated by a blank "
133 "space, and the values of a list are separated by a comma (,) without spaces. "
134 "E.g. \"BE 31,31,31; VI 15,15,15\" defines the CW max values for AC BE and AC VI "
135 "for an AP MLD having three links.",
136 StringValue(""),
140 .AddAttribute(
141 "AifsnsForSta",
142 "The AIFSN values that the AP advertises in EDCA Parameter Set elements and the "
143 "associated stations will use. The value of this attribute is an AC-indexed map "
144 "containing the AIFSN values for given ACs for all the links (sorted in "
145 "increasing order of link ID). If no values are provided for an AC, the same "
146 "values used by the AP are advertised. In case a string is used to set this "
147 "attribute, the string shall contain the pairs separated by a semicolon (;); "
148 "in every pair, the AC index and the list of values are separated by a blank "
149 "space, and the values of a list are separated by a comma (,) without spaces. "
150 "E.g. \"BE 3,3,3; VI 2,2,2\" defines the AIFSN values for AC BE and AC VI "
151 "for an AP MLD having three links.",
152 StringValue(""),
156 .AddAttribute(
157 "TxopLimitsForSta",
158 "The TXOP limit values that the AP advertises in EDCA Parameter Set elements and "
159 "the associated stations will use. The value of this attribute is an AC-indexed "
160 "map containing the TXOP limit values for given ACs for all the links (sorted in "
161 "increasing order of link ID). If no values are provided for an AC, the same "
162 "values used by the AP are advertised. In case a string is used to set this "
163 "attribute, the string shall contain the pairs separated by a semicolon (;); "
164 "in every pair, the AC index and the list of values are separated by a blank "
165 "space, and the values of a list are separated by a comma (,) without spaces. "
166 "E.g. \"BE 3200us,3200us,3200us; VI 2400us,2400us,2400us\" defines the TXOP limit "
167 "values for AC BE and AC VI for an AP MLD having three links.",
168 StringValue(""),
172 .AddAttribute("GcrManager",
173 "The GCR manager object.",
175 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
176 PointerValue(),
179 .AddTraceSource("AssociatedSta",
180 "A station associated with this access point.",
182 "ns3::ApWifiMac::AssociationCallback")
183 .AddTraceSource("DeAssociatedSta",
184 "A station lost association with this access point.",
186 "ns3::ApWifiMac::AssociationCallback");
187 return tid;
188}
189
190template <class T>
201
210
212 : m_enableBeaconGeneration(false)
213{
214 NS_LOG_FUNCTION(this);
217
218 // Let the lower layers know that we are acting as an AP.
220}
221
226
227void
229{
230 NS_LOG_FUNCTION(this);
232 m_beaconTxop = nullptr;
235 {
236 m_apEmlsrManager->Dispose();
237 }
238 m_apEmlsrManager = nullptr;
239 if (m_gcrManager)
240 {
241 m_gcrManager->Dispose();
242 }
243 m_gcrManager = nullptr;
245}
246
252
253std::unique_ptr<WifiMac::LinkEntity>
255{
256 return std::make_unique<ApLinkEntity>();
257}
258
260ApWifiMac::GetLink(uint8_t linkId) const
261{
262 return static_cast<ApLinkEntity&>(WifiMac::GetLink(linkId));
263}
264
265void
267{
268 NS_LOG_FUNCTION(this << apEmlsrManager);
269 m_apEmlsrManager = apEmlsrManager;
270 m_apEmlsrManager->SetWifiMac(this);
271}
272
275{
276 return m_apEmlsrManager;
277}
278
279void
281{
282 NS_LOG_FUNCTION(this << gcrManager);
283 m_gcrManager = gcrManager;
284 m_gcrManager->SetWifiMac(this);
285}
286
289{
290 return m_gcrManager;
291}
292
293bool
295{
296 if (!hdr.IsQosData())
297 {
298 return false;
299 }
300
301 if (!IsGroupcast(hdr.GetAddr1()))
302 {
303 return false;
304 }
305
306 if (!m_gcrManager)
307 {
308 return false;
309 }
310
311 if (m_gcrManager->GetRetransmissionPolicy() ==
313 {
314 return false;
315 }
316
317 /*
318 * 802.11-2020 11.21.16.3.4 (GCR operation):
319 * An AP or mesh STA shall transmit a frame belonging to a group address
320 * via the GCR service if any associated STA or peer mesh STA has a GCR
321 * agreement for the group address and, otherwise, does not transmit the
322 * frame via the GCR service.
323 */
324 if (m_gcrManager->GetMemberStasForGroupAddress(hdr.GetAddr1()).empty())
325 {
326 return false;
327 }
328
329 return true;
330}
331
332void
334{
335 NS_LOG_FUNCTION(this);
337 // DCF behavior may be edited here; the default is PIFS access with zero backoff
338 m_beaconTxop->SetAifsns(std::vector<uint8_t>(GetNLinks(), 1));
339 m_beaconTxop->SetMinCws(std::vector<uint32_t>(GetNLinks(), 0));
340 m_beaconTxop->SetMaxCws(std::vector<uint32_t>(GetNLinks(), 0));
341 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
342 {
344 }
345}
346
349{
350 if (ac == AC_BEACON)
351 {
353 }
354 return WifiMac::GetTxopQueue(ac);
355}
356
357void
359{
360 NS_LOG_FUNCTION(this << enable);
361 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
362 {
363 if (!enable)
364 {
365 GetLink(linkId).beaconEvent.Cancel();
366 }
367 else if (!m_enableBeaconGeneration)
368 {
369 GetLink(linkId).beaconEvent =
371 }
372 }
374}
375
376Time
378{
379 NS_LOG_FUNCTION(this);
380 return m_beaconInterval;
381}
382
383void
385{
386 NS_LOG_FUNCTION(this << &linkUp);
388
389 // The approach taken here is that, from the point of view of an AP,
390 // the link is always up, so we immediately invoke the callback if
391 // one is set
392 linkUp();
393}
394
395void
397{
398 NS_LOG_FUNCTION(this << interval);
399 if ((interval.GetMicroSeconds() % 1024) != 0)
400 {
401 NS_FATAL_ERROR("beacon interval should be multiple of 1024us (802.11 time unit), see IEEE "
402 "Std. 802.11-2012");
403 }
404 if (interval.GetMicroSeconds() > (1024 * 65535))
405 {
407 "beacon interval should be smaller then or equal to 65535 * 1024us (802.11 time unit)");
408 }
409 m_beaconInterval = interval;
410}
411
412int64_t
414{
415 NS_LOG_FUNCTION(this << stream);
416 m_beaconJitter->SetStream(stream);
417 auto currentStream = stream + 1;
418 currentStream += m_beaconTxop->AssignStreams(currentStream);
419 currentStream += WifiMac::AssignStreams(currentStream);
420 return (currentStream - stream);
421}
422
423void
425{
426 NS_LOG_FUNCTION(this << +linkId);
427 auto& link = GetLink(linkId);
428 if (GetErpSupported(linkId) && GetShortSlotTimeSupported() && (link.numNonErpStations == 0))
429 {
430 for (const auto& sta : link.staList)
431 {
432 if (!GetWifiRemoteStationManager(linkId)->GetShortSlotTimeSupported(sta.second))
433 {
434 link.shortSlotTimeEnabled = false;
435 return;
436 }
437 }
438 link.shortSlotTimeEnabled = true;
439 }
440 else
441 {
442 link.shortSlotTimeEnabled = false;
443 }
444}
445
446void
448{
449 NS_LOG_FUNCTION(this << +linkId);
450 auto& link = GetLink(linkId);
451 if (GetErpSupported(linkId) && GetWifiPhy(linkId)->GetShortPhyPreambleSupported())
452 {
453 for (const auto& sta : link.staList)
454 {
455 if (!GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(sta.second) ||
456 !GetWifiRemoteStationManager(linkId)->GetShortPreambleSupported(sta.second))
457 {
458 link.shortPreambleEnabled = false;
459 return;
460 }
461 }
462 link.shortPreambleEnabled = true;
463 }
464 else
465 {
466 link.shortPreambleEnabled = false;
467 }
468}
469
470bool
472{
473 return (to.IsGroup() || IsAssociated(to));
474}
475
476void
478{
479 NS_LOG_FUNCTION(this << *mpdu << to << from);
480
481 std::list<Mac48Address> addr2Set;
482 if (to.IsGroup())
483 {
484 // broadcast frames are transmitted on all the links
485 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
486 {
487 addr2Set.push_back(GetFrameExchangeManager(linkId)->GetAddress());
488 }
489 }
490 else
491 {
492 // the Transmitter Address (TA) is the MLD address only for non-broadcast data frames
493 // exchanged between two MLDs
494 addr2Set = {GetAddress()};
495 auto linkId = IsAssociated(to);
496 NS_ASSERT_MSG(linkId, "Station " << to << "is not associated, cannot send it a frame");
497 if (GetNLinks() == 1 || !GetWifiRemoteStationManager(*linkId)->GetMldAddress(to))
498 {
499 addr2Set = {GetFrameExchangeManager(*linkId)->GetAddress()};
500 }
501 }
502
503 for (auto addr2 = addr2Set.cbegin(); addr2 != addr2Set.cend(); ++addr2)
504 {
505 auto& hdr = mpdu->GetHeader();
506
507 hdr.SetAddr1(to);
508 hdr.SetAddr2(*addr2);
509 hdr.SetAddr3(from);
510 hdr.SetDsFrom();
511 hdr.SetDsNotTo();
512
513 auto txop = hdr.IsQosData() ? StaticCast<Txop>(GetQosTxop(hdr.GetQosTid())) : GetTxop();
514 NS_ASSERT(txop);
515 txop->Queue(mpdu);
516
517 // create another MPDU if needed
518 if (std::next(addr2) != addr2Set.cend())
519 {
520 mpdu = Create<WifiMpdu>(mpdu->GetPacket()->Copy(), hdr);
521 }
522 }
523}
524
525bool
527{
528 NS_LOG_FUNCTION(this);
529 return true;
530}
531
533ApWifiMac::GetSupportedRates(uint8_t linkId) const
534{
535 NS_LOG_FUNCTION(this << +linkId);
536 AllSupportedRates rates;
537 // Send the set of supported rates and make sure that we indicate
538 // the Basic Rate set in this set of supported rates.
539 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
540 {
541 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
542 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
543 rates.AddSupportedRate(modeDataRate);
544 // Add rates that are part of the BSSBasicRateSet (manufacturer dependent!)
545 // here we choose to add the mandatory rates to the BSSBasicRateSet,
546 // except for 802.11b where we assume that only the non HR-DSSS rates are part of the
547 // BSSBasicRateSet
548 if (mode.IsMandatory() && (mode.GetModulationClass() != WIFI_MOD_CLASS_HR_DSSS))
549 {
550 NS_LOG_DEBUG("Adding basic mode " << mode.GetUniqueName());
551 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
552 }
553 }
554 // set the basic rates
555 for (uint8_t j = 0; j < GetWifiRemoteStationManager(linkId)->GetNBasicModes(); j++)
556 {
557 WifiMode mode = GetWifiRemoteStationManager(linkId)->GetBasicMode(j);
558 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
559 NS_LOG_DEBUG("Setting basic rate " << mode.GetUniqueName());
560 rates.SetBasicRate(modeDataRate);
561 }
562 // If it is a HT AP, then add the BSSMembershipSelectorSet
563 // The standard says that the BSSMembershipSelectorSet
564 // must have its MSB set to 1 (must be treated as a Basic Rate)
565 // Also the standard mentioned that at least 1 element should be included in the SupportedRates
566 // the rest can be in the ExtendedSupportedRates
567 if (GetHtSupported(linkId))
568 {
569 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
570 {
571 rates.AddBssMembershipSelectorRate(selector);
572 }
573 }
574 return rates;
575}
576
579{
580 NS_LOG_FUNCTION(this << +linkId);
582 DsssParameterSet dsssParameters;
583 dsssParameters.SetCurrentChannel(GetWifiPhy(linkId)->GetChannelNumber());
584 return dsssParameters;
585}
586
588ApWifiMac::GetCapabilities(uint8_t linkId) const
589{
590 NS_LOG_FUNCTION(this << +linkId);
591 CapabilityInformation capabilities;
592 capabilities.SetShortPreamble(GetLink(linkId).shortPreambleEnabled);
593 capabilities.SetShortSlotTime(GetLink(linkId).shortSlotTimeEnabled);
594 capabilities.SetEss();
595 return capabilities;
596}
597
599ApWifiMac::GetErpInformation(uint8_t linkId) const
600{
601 NS_LOG_FUNCTION(this << +linkId);
602 NS_ASSERT(GetErpSupported(linkId));
603 ErpInformation information;
604
605 information.SetNonErpPresent(GetLink(linkId).numNonErpStations > 0);
606 information.SetUseProtection(GetUseNonErpProtection(linkId));
607 if (GetLink(linkId).shortPreambleEnabled)
608 {
609 information.SetBarkerPreambleMode(0);
610 }
611 else
612 {
613 information.SetBarkerPreambleMode(1);
614 }
615
616 return information;
617}
618
621{
622 NS_LOG_FUNCTION(this << +linkId);
624 EdcaParameterSet edcaParameters;
625
626 Ptr<QosTxop> edca;
627 Time txopLimit;
628
629 edca = GetQosTxop(AC_BE);
630 edcaParameters.SetBeAci(0);
631 edcaParameters.SetBeCWmin(m_cwMinsForSta.contains(AC_BE) ? m_cwMinsForSta.at(AC_BE).at(linkId)
632 : edca->GetMinCw(linkId));
633 edcaParameters.SetBeCWmax(m_cwMaxsForSta.contains(AC_BE) ? m_cwMaxsForSta.at(AC_BE).at(linkId)
634 : edca->GetMaxCw(linkId));
635 edcaParameters.SetBeAifsn(m_aifsnsForSta.contains(AC_BE) ? m_aifsnsForSta.at(AC_BE).at(linkId)
636 : edca->GetAifsn(linkId));
637 txopLimit = m_txopLimitsForSta.contains(AC_BE) ? m_txopLimitsForSta.at(AC_BE).at(linkId)
638 : edca->GetTxopLimit(linkId);
639 edcaParameters.SetBeTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
640
641 edca = GetQosTxop(AC_BK);
642 edcaParameters.SetBkAci(1);
643 edcaParameters.SetBkCWmin(m_cwMinsForSta.contains(AC_BK) ? m_cwMinsForSta.at(AC_BK).at(linkId)
644 : edca->GetMinCw(linkId));
645 edcaParameters.SetBkCWmax(m_cwMaxsForSta.contains(AC_BK) ? m_cwMaxsForSta.at(AC_BK).at(linkId)
646 : edca->GetMaxCw(linkId));
647 edcaParameters.SetBkAifsn(m_aifsnsForSta.contains(AC_BK) ? m_aifsnsForSta.at(AC_BK).at(linkId)
648 : edca->GetAifsn(linkId));
649 txopLimit = m_txopLimitsForSta.contains(AC_BK) ? m_txopLimitsForSta.at(AC_BK).at(linkId)
650 : edca->GetTxopLimit(linkId);
651 edcaParameters.SetBkTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
652
653 edca = GetQosTxop(AC_VI);
654 edcaParameters.SetViAci(2);
655 edcaParameters.SetViCWmin(m_cwMinsForSta.contains(AC_VI) ? m_cwMinsForSta.at(AC_VI).at(linkId)
656 : edca->GetMinCw(linkId));
657 edcaParameters.SetViCWmax(m_cwMaxsForSta.contains(AC_VI) ? m_cwMaxsForSta.at(AC_VI).at(linkId)
658 : edca->GetMaxCw(linkId));
659 edcaParameters.SetViAifsn(m_aifsnsForSta.contains(AC_VI) ? m_aifsnsForSta.at(AC_VI).at(linkId)
660 : edca->GetAifsn(linkId));
661 txopLimit = m_txopLimitsForSta.contains(AC_VI) ? m_txopLimitsForSta.at(AC_VI).at(linkId)
662 : edca->GetTxopLimit(linkId);
663 edcaParameters.SetViTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
664
665 edca = GetQosTxop(AC_VO);
666 edcaParameters.SetVoAci(3);
667 edcaParameters.SetVoCWmin(m_cwMinsForSta.contains(AC_VO) ? m_cwMinsForSta.at(AC_VO).at(linkId)
668 : edca->GetMinCw(linkId));
669 edcaParameters.SetVoCWmax(m_cwMaxsForSta.contains(AC_VO) ? m_cwMaxsForSta.at(AC_VO).at(linkId)
670 : edca->GetMaxCw(linkId));
671 edcaParameters.SetVoAifsn(m_aifsnsForSta.contains(AC_VO) ? m_aifsnsForSta.at(AC_VO).at(linkId)
672 : edca->GetAifsn(linkId));
673 txopLimit = m_txopLimitsForSta.contains(AC_VO) ? m_txopLimitsForSta.at(AC_VO).at(linkId)
674 : edca->GetTxopLimit(linkId);
675 edcaParameters.SetVoTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
676
677 edcaParameters.SetQosInfo(0);
678
679 return edcaParameters;
680}
681
682std::optional<MuEdcaParameterSet>
684{
685 NS_LOG_FUNCTION(this);
687
688 Ptr<HeConfiguration> heConfiguration = GetHeConfiguration();
689 NS_ASSERT(heConfiguration);
690
691 MuEdcaParameterSet muEdcaParameters;
692 muEdcaParameters.SetQosInfo(0);
693
694 muEdcaParameters.SetMuAifsn(AC_BE, heConfiguration->m_muBeAifsn);
695 muEdcaParameters.SetMuCwMin(AC_BE, heConfiguration->m_muBeCwMin);
696 muEdcaParameters.SetMuCwMax(AC_BE, heConfiguration->m_muBeCwMax);
697 muEdcaParameters.SetMuEdcaTimer(AC_BE, heConfiguration->m_beMuEdcaTimer);
698
699 muEdcaParameters.SetMuAifsn(AC_BK, heConfiguration->m_muBkAifsn);
700 muEdcaParameters.SetMuCwMin(AC_BK, heConfiguration->m_muBkCwMin);
701 muEdcaParameters.SetMuCwMax(AC_BK, heConfiguration->m_muBkCwMax);
702 muEdcaParameters.SetMuEdcaTimer(AC_BK, heConfiguration->m_bkMuEdcaTimer);
703
704 muEdcaParameters.SetMuAifsn(AC_VI, heConfiguration->m_muViAifsn);
705 muEdcaParameters.SetMuCwMin(AC_VI, heConfiguration->m_muViCwMin);
706 muEdcaParameters.SetMuCwMax(AC_VI, heConfiguration->m_muViCwMax);
707 muEdcaParameters.SetMuEdcaTimer(AC_VI, heConfiguration->m_viMuEdcaTimer);
708
709 muEdcaParameters.SetMuAifsn(AC_VO, heConfiguration->m_muVoAifsn);
710 muEdcaParameters.SetMuCwMin(AC_VO, heConfiguration->m_muVoCwMin);
711 muEdcaParameters.SetMuCwMax(AC_VO, heConfiguration->m_muVoCwMax);
712 muEdcaParameters.SetMuEdcaTimer(AC_VO, heConfiguration->m_voMuEdcaTimer);
713
714 // The timers of the MU EDCA Parameter Set must be either all zero or all
715 // non-zero. The information element is advertised if all timers are non-zero
716 auto timerNotNull = [&muEdcaParameters](uint8_t aci) {
717 return !muEdcaParameters.GetMuEdcaTimer(aci).IsZero();
718 };
719 auto aci = {0, 1, 2, 3};
720 if (std::all_of(aci.begin(), aci.end(), timerNotNull))
721 {
722 return muEdcaParameters;
723 }
724
725 NS_ABORT_MSG_UNLESS(std::none_of(aci.begin(), aci.end(), timerNotNull),
726 "MU EDCA Timers must be all zero if the IE is not advertised.");
727
728 return std::nullopt;
729}
730
731std::optional<ReducedNeighborReport>
733{
734 NS_LOG_FUNCTION(this << +linkId);
735
736 if (GetNLinks() <= 1)
737 {
738 return std::nullopt;
739 }
740
743
744 for (uint8_t index = 0; index < GetNLinks(); ++index)
745 {
746 if (index != linkId) // all links but the one used to send this Beacon frame
747 {
748 rnr.AddNbrApInfoField();
749 std::size_t nbrId = rnr.GetNNbrApInfoFields() - 1;
751 rnr.AddTbttInformationField(nbrId);
752 rnr.SetBssid(nbrId, 0, GetLink(index).feManager->GetAddress());
753 rnr.SetShortSsid(nbrId, 0, 0);
754 rnr.SetBssParameters(nbrId, 0, 0);
755 rnr.SetPsd20MHz(nbrId, 0, 0);
756 rnr.SetMldParameters(nbrId, 0, {0, index, 0, 0, 0});
757 }
758 }
759 return rnr;
760}
761
764 WifiMacType frameType,
765 const Mac48Address& to,
766 const std::optional<MultiLinkElement>& mlProbeReqMle)
767{
768 NS_LOG_FUNCTION(this << +linkId << frameType << to);
769 NS_ABORT_IF(GetNLinks() == 1);
770 NS_ABORT_MSG_IF(mlProbeReqMle.has_value() && frameType != WIFI_MAC_MGT_PROBE_RESPONSE,
771 "ML Probe Request Multi-Link Element cannot be provided for frame type "
772 << frameType);
773
776 mle.SetLinkIdInfo(linkId);
778
779 auto ehtConfiguration = GetEhtConfiguration();
780 NS_ASSERT(ehtConfiguration);
781
782 if (ehtConfiguration->m_emlsrActivated)
783 {
784 mle.SetEmlsrSupported(true);
785 // When the EMLSR Padding Delay subfield is included in a frame sent by an AP affiliated
786 // with an AP MLD, the EMLSR Padding Delay subfield is reserved.
787 // When the EMLSR Transition Delay subfield is included in a frame sent by an AP affiliated
788 // with an AP MLD, the EMLSR Transition Delay subfield is reserved. (Sec. 9.4.2.312.2.3
789 // of 802.11be D2.3)
790 TimeValue time;
791 mle.SetTransitionTimeout(ehtConfiguration->m_transitionTimeout);
792
793 // An AP affiliated with an AP MLD may include the Medium Synchronization Delay Information
794 // subfield in the Common Info field of the Basic Multi-Link element carried in transmitted
795 // (Re)Association Response or Multi-Link Probe Response frames to provide medium
796 // synchronization information used by the AP MLD. (Section 35.3.16.8.2 of 802.11be D3.1)
797 if (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE)
798 {
799 auto& commonInfo = mle.GetCommonInfoBasic();
800 commonInfo.SetMediumSyncDelayTimer(ehtConfiguration->m_mediumSyncDuration);
801 commonInfo.SetMediumSyncOfdmEdThreshold(ehtConfiguration->m_msdOfdmEdThreshold);
802 commonInfo.SetMediumSyncMaxNTxops(ehtConfiguration->m_msdMaxNTxops);
803 }
804 }
805
806 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
807 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
808 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
809 if (frameType == WIFI_MAC_MGT_BEACON || frameType == WIFI_MAC_MGT_PROBE_RESPONSE ||
813 {
814 auto& mldCapabilities = mle.GetCommonInfoBasic().m_mldCapabilities;
815 mldCapabilities.emplace();
816 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
817 mldCapabilities->srsSupport = 0;
818 mldCapabilities->tidToLinkMappingSupport =
819 static_cast<uint8_t>(ehtConfiguration->m_tidLinkMappingSupport);
820 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
821 mldCapabilities->aarSupport = 0; // not supported yet
822 }
823
824 // if the Multi-Link Element is being inserted in a (Re)Association Response frame
825 // and the remote station is affiliated with an MLD, try multi-link setup
826 if (auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
827 (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE ||
829 staMldAddress.has_value())
830 {
831 for (uint8_t i = 0; i < GetNLinks(); i++)
832 {
833 auto remoteStationManager = GetWifiRemoteStationManager(i);
834 if (auto staAddress = remoteStationManager->GetAffiliatedStaAddress(*staMldAddress);
835 i != linkId && staAddress.has_value() &&
836 (remoteStationManager->IsWaitAssocTxOk(*staAddress) ||
837 remoteStationManager->IsAssocRefused(*staAddress)))
838 {
839 // For each requested link in addition to the link on which the
840 // (Re)Association Response frame is transmitted, the Link Info field
841 // of the Basic Multi-Link element carried in the (Re)Association
842 // Response frame shall contain the corresponding Per-STA Profile
843 // subelement(s) (Sec. 35.3.5.4 of 802.11be D2.0)
845 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
846 // The Link ID subfield of the STA Control field of the Per-STA Profile
847 // subelement for the AP corresponding to a link is set to the link ID
848 // of the AP affiliated with the AP MLD that is operating on that link.
849 perStaProfile.SetLinkId(i);
850 perStaProfile.SetCompleteProfile();
851 // For each Per-STA Profile subelement included in the Link Info field,
852 // the Complete Profile subfield of the STA Control field shall be set to 1
853 perStaProfile.SetStaMacAddress(GetFrameExchangeManager(i)->GetAddress());
854 perStaProfile.SetAssocResponse(GetAssocResp(*staAddress, i));
855 }
856 }
857 }
858
859 if (!mlProbeReqMle.has_value())
860 {
861 return mle; // not a multi-link probe request
862 }
863
864 auto reqVar = mlProbeReqMle->GetVariant();
866 "Invalid MLE variant " << reqVar);
867
868 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
869 // If either the Address 1 field or the Address 3 field of the multi-link probe request is set
870 // to the MAC address of the responding AP that operates on the same link where the multi-link
871 // probe request is sent, then the AP MLD ID subfield shall be present in the Probe Request
872 // Multi-Link element of the multi-link probe request value and targeted AP MLD is identified by
873 // AP MLD ID subfield, which is set to the same AP MLD ID as the one used by the AP that is
874 // addressed by the multi-link probe request to identify the AP MLD
875 // in the Beacon and Probe Response frames that it transmits.
876 auto apMldId = mlProbeReqMle->GetApMldId();
877 NS_ASSERT_MSG(apMldId.has_value(), "AP MLD ID subfield missing");
878
879 // IEEE 802.11be D6.0 9.4.2.169.2 Neighbor AP Information field
880 // If the reported AP is affiliated with the same MLD as the reporting AP sending the frame
881 // carrying this element, the AP MLD ID subfield is set to 0. AP MLD ID value advertised in
882 // Beacons and Probe Responses is 0. Multi-BSSID feature not supported.
883 NS_ASSERT_MSG(*apMldId == 0, "AP MLD ID expected value is 0. value = " << +apMldId.value());
884
885 // Using set to handle case of multiple Per-STA Profiles including same link ID
886 std::set<uint8_t> respLinkIds{}; // Set of Link IDs to include in Probe Response
887 if (const auto nProfiles = mlProbeReqMle->GetNPerStaProfileSubelements(); nProfiles == 0)
888 {
889 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
890 // If the Probe Request Multi-link element in the multi-link probe request does not include
891 // any per-STA profile, then all APs affiliated with the same AP MLD as the AP identified in
892 // the Address 1 or Address 3 field or AP MLD ID shall be requested APs.
893 for (std::size_t i = 0; i < GetNLinks(); ++i)
894 {
895 if (i != linkId)
896 {
897 respLinkIds.insert(i);
898 }
899 }
900 }
901
902 for (std::size_t i = 0; i < mlProbeReqMle->GetNPerStaProfileSubelements(); ++i)
903 {
904 // IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
905 // If the Probe Request Multi-Link element in the multi-link probe request includes one or
906 // more per-STA profiles, then only APs affiliated with the same AP MLD whose link ID is
907 // equal to the value in the Link ID Field in a per-STA profile in the Probe Request
908 // Multi-link element shall be requested APs.
909 const auto& perStaProfile = mlProbeReqMle->GetPerStaProfile(i);
910 auto currLinkId = perStaProfile.GetLinkId();
911 if ((currLinkId < GetNLinks()) && (currLinkId != linkId))
912 {
913 respLinkIds.insert(currLinkId); // Only consider valid link IDs
914 }
915 }
916
917 auto setPerStaProfile = [&](uint8_t id) -> void {
919 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
920 perStaProfile.SetLinkId(id);
921 // Current support limited to Complete Profile request per link ID
922 // TODO: Add support for Partial Per-STA Profile request
923 perStaProfile.SetProbeResponse(GetProbeRespProfile(id));
924 perStaProfile.SetCompleteProfile();
925 };
926
927 std::for_each(respLinkIds.begin(), respLinkIds.end(), setPerStaProfile);
928 return mle;
929}
930
932ApWifiMac::GetHtOperation(uint8_t linkId) const
933{
934 NS_LOG_FUNCTION(this << +linkId);
935 NS_ASSERT(GetHtSupported(linkId));
936 HtOperation operation;
937 auto phy = GetWifiPhy(linkId);
938 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
939
940 operation.SetPrimaryChannel(phy->GetPrimaryChannelNumber(MHz_u{20}));
941 operation.SetRifsMode(false);
942 operation.SetNonGfHtStasPresent(true);
943 if (phy->GetChannelWidth() > MHz_u{20})
944 {
945 operation.SetSecondaryChannelOffset(1);
946 operation.SetStaChannelWidth(1);
947 }
948 if (GetLink(linkId).numNonHtStations == 0)
949 {
951 }
952 else
953 {
955 }
956 uint64_t maxSupportedRate = 0; // in bit/s
957 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HT))
958 {
959 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
960 NS_ASSERT(nss > 0 && nss < 5);
961 uint64_t dataRate =
962 mcs.GetDataRate(phy->GetChannelWidth(),
963 NanoSeconds(GetHtConfiguration()->m_sgiSupported ? 400 : 800),
964 nss);
965 if (dataRate > maxSupportedRate)
966 {
967 maxSupportedRate = dataRate;
968 NS_LOG_DEBUG("Updating maxSupportedRate to " << maxSupportedRate);
969 }
970 }
971 uint8_t maxSpatialStream = phy->GetMaxSupportedTxSpatialStreams();
972 auto mcsList = phy->GetMcsList(WIFI_MOD_CLASS_HT);
973 uint8_t nMcs = mcsList.size();
974 for (const auto& sta : GetLink(linkId).staList)
975 {
976 if (remoteStationManager->GetHtSupported(sta.second) ||
977 remoteStationManager->GetStationHe6GhzCapabilities(sta.second))
978 {
979 uint64_t maxSupportedRateByHtSta = 0; // in bit/s
980 auto itMcs = mcsList.begin();
981 for (uint8_t j = 0;
982 j < (std::min(nMcs, remoteStationManager->GetNMcsSupported(sta.second)));
983 j++)
984 {
985 WifiMode mcs = *itMcs++;
986 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
987 NS_ASSERT(nss > 0 && nss < 5);
988 uint64_t dataRate = mcs.GetDataRate(
989 remoteStationManager->GetChannelWidthSupported(sta.second),
990 NanoSeconds(remoteStationManager->GetShortGuardIntervalSupported(sta.second)
991 ? 400
992 : 800),
993 nss);
994 if (dataRate > maxSupportedRateByHtSta)
995 {
996 maxSupportedRateByHtSta = dataRate;
997 }
998 }
999 if (maxSupportedRateByHtSta < maxSupportedRate)
1000 {
1001 maxSupportedRate = maxSupportedRateByHtSta;
1002 }
1003 if (remoteStationManager->GetNMcsSupported(sta.second) < nMcs)
1004 {
1005 nMcs = remoteStationManager->GetNMcsSupported(sta.second);
1006 }
1007 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1008 {
1009 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1010 }
1011 }
1012 }
1014 static_cast<uint16_t>(maxSupportedRate / 1e6)); // in Mbit/s
1015 operation.SetTxMcsSetDefined(nMcs > 0);
1016 operation.SetTxMaxNSpatialStreams(maxSpatialStream);
1017 // To be filled in once supported
1018 operation.SetObssNonHtStasPresent(0);
1019 operation.SetDualBeacon(0);
1020 operation.SetDualCtsProtection(0);
1021 operation.SetStbcBeacon(0);
1023 operation.SetPcoActive(0);
1024 operation.SetPhase(0);
1025 operation.SetRxMcsBitmask(0);
1026 operation.SetTxRxMcsSetUnequal(0);
1027 operation.SetTxUnequalModulation(0);
1028
1029 return operation;
1030}
1031
1033ApWifiMac::GetVhtOperation(uint8_t linkId) const
1034{
1035 NS_LOG_FUNCTION(this << +linkId);
1036 NS_ASSERT(GetVhtSupported(linkId));
1037 VhtOperation operation;
1038 auto phy = GetWifiPhy(linkId);
1039 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1040
1041 const auto bssBandwidth = phy->GetChannelWidth();
1042 // Set to 0 for 20 MHz or 40 MHz BSS bandwidth.
1043 // Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS bandwidth.
1044 operation.SetChannelWidth((bssBandwidth > MHz_u{40}) ? 1 : 0);
1045 // For 20, 40, or 80 MHz BSS bandwidth, indicates the channel center frequency
1046 // index for the 20, 40, or 80 MHz channel on which the VHT BSS operates.
1047 // For 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
1048 // indicates the channel center frequency index of the 80 MHz channel
1049 // segment that contains the primary channel.
1050 // For 80+80 MHz BSS bandwidth and the Channel Width subfield equal to 1 or 3,
1051 // indicates the channel center frequency index for the primary 80 MHz channel of the VHT BSS.
1052 operation.SetChannelCenterFrequencySegment0((bssBandwidth == MHz_u{160})
1053 ? phy->GetPrimaryChannelNumber(MHz_u{80})
1054 : phy->GetChannelNumber());
1055 // For a 20, 40, or 80 MHz BSS bandwidth, this subfield is set to 0.
1056 // For a 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
1057 // indicates the channel center frequency index of the 160 MHz channel on
1058 // which the VHT BSS operates.
1059 // For an 80+80 MHz BSS bandwidth and the Channel Width subfield equal to 1 or 3,
1060 // indicates the channel center frequency index of the secondary 80 MHz channel of the VHT BSS.
1061 const auto& operatingChannel = phy->GetOperatingChannel();
1062 const auto is80Plus80 =
1063 operatingChannel.GetWidthType() == WifiChannelWidthType::CW_80_PLUS_80MHZ;
1064 operation.SetChannelCenterFrequencySegment1((bssBandwidth == MHz_u{160})
1065 ? is80Plus80 ? operatingChannel.GetNumber(1)
1066 : phy->GetChannelNumber()
1067 : 0);
1068 uint8_t maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
1069 for (const auto& sta : GetLink(linkId).staList)
1070 {
1071 if (remoteStationManager->GetVhtSupported(sta.second))
1072 {
1073 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1074 {
1075 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1076 }
1077 }
1078 }
1079 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
1080 {
1081 uint8_t maxMcs =
1082 9; // TBD: hardcode to 9 for now since we assume all MCS values are supported
1083 operation.SetMaxVhtMcsPerNss(nss, maxMcs);
1084 }
1085
1086 return operation;
1087}
1088
1090ApWifiMac::GetHeOperation(uint8_t linkId) const
1091{
1092 NS_LOG_FUNCTION(this << +linkId);
1094 HeOperation operation;
1095 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1096
1097 uint8_t maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
1098 for (const auto& sta : GetLink(linkId).staList)
1099 {
1100 if (remoteStationManager->GetHeSupported(sta.second))
1101 {
1102 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1103 {
1104 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1105 }
1106 }
1107 }
1108 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
1109 {
1110 operation.SetMaxHeMcsPerNss(
1111 nss,
1112 11); // TBD: hardcode to 11 for now since we assume all MCS values are supported
1113 }
1114 operation.m_bssColorInfo.m_bssColor = GetHeConfiguration()->m_bssColor;
1115
1116 if (auto phy = GetWifiPhy(linkId); phy && phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ)
1117 {
1119 const auto bw = phy->GetChannelWidth();
1120 const auto ch = phy->GetOperatingChannel();
1121 op6Ghz.m_chWid = (bw == MHz_u{20}) ? 0 : (bw == MHz_u{40}) ? 1 : (bw == MHz_u{80}) ? 2 : 3;
1122 op6Ghz.m_primCh = ch.GetPrimaryChannelNumber(MHz_u{20}, WIFI_STANDARD_80211ax);
1123 op6Ghz.m_chCntrFreqSeg0 = (bw == MHz_u{160})
1124 ? ch.GetPrimaryChannelNumber(MHz_u{80}, WIFI_STANDARD_80211ax)
1125 : ch.GetNumber();
1126 // TODO: for 80+80 MHz channels, set this field to the secondary 80 MHz segment number
1127 op6Ghz.m_chCntrFreqSeg1 = (bw == MHz_u{160}) ? ch.GetNumber() : 0;
1128
1129 operation.m_6GHzOpInfo = op6Ghz;
1130 }
1131
1132 return operation;
1133}
1134
1135EhtOperation
1136ApWifiMac::GetEhtOperation(uint8_t linkId) const
1137{
1138 NS_LOG_FUNCTION(this << +linkId);
1140 EhtOperation operation;
1141 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1142
1143 auto maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
1144 for (const auto& sta : GetLink(linkId).staList)
1145 {
1146 if (remoteStationManager->GetEhtSupported(sta.second))
1147 {
1148 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1149 {
1150 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1151 }
1152 }
1153 }
1154 operation.SetMaxRxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1155 operation.SetMaxTxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1156 return operation;
1157}
1158
1159void
1161 Mac48Address to,
1162 uint8_t linkId)
1163{
1164 NS_LOG_FUNCTION(this << to << +linkId);
1166 hdr.SetAddr1(to);
1167 hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
1168 hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
1169 hdr.SetDsNotFrom();
1170 hdr.SetDsNotTo();
1171 Ptr<Packet> packet = Create<Packet>();
1172 packet->AddHeader(probeResp);
1173
1174 if (!GetQosSupported())
1175 {
1176 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1177 }
1178 // "A QoS STA that transmits a Management frame determines access category used
1179 // for medium access in transmission of the Management frame as follows
1180 // (If dot11QMFActivated is false or not present)
1181 // — If the Management frame is individually addressed to a non-QoS STA, category
1182 // AC_BE should be selected.
1183 // — If category AC_BE was not selected by the previous step, category AC_VO
1184 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1185 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1186 {
1187 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1188 }
1189 else
1190 {
1191 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1192 }
1193}
1194
1197{
1199 probe.Get<Ssid>() = GetSsid();
1200 auto supportedRates = GetSupportedRates(linkId);
1201 probe.Get<SupportedRates>() = supportedRates.rates;
1202 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1203 probe.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
1204 probe.Capabilities() = GetCapabilities(linkId);
1205 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(
1206 GetLink(linkId).shortPreambleEnabled);
1207 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1208 GetLink(linkId).shortSlotTimeEnabled);
1209 if (GetDsssSupported(linkId))
1210 {
1211 probe.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1212 }
1213 if (GetErpSupported(linkId))
1214 {
1215 probe.Get<ErpInformation>() = GetErpInformation(linkId);
1216 }
1217 if (GetQosSupported())
1218 {
1219 probe.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1220 }
1221 if (GetHtSupported(linkId))
1222 {
1224 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1225 probe.Get<HtOperation>() = GetHtOperation(linkId);
1226 }
1227 if (GetVhtSupported(linkId))
1228 {
1229 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1230 probe.Get<VhtOperation>() = GetVhtOperation(linkId);
1231 }
1232 if (GetHeSupported())
1233 {
1234 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1235 probe.Get<HeOperation>() = GetHeOperation(linkId);
1236 if (auto muEdcaParameterSet = GetMuEdcaParameterSet())
1237 {
1238 probe.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1239 }
1240 if (Is6GhzBand(linkId))
1241 {
1243 }
1244 }
1245 if (GetEhtSupported())
1246 {
1247 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1248 probe.Get<EhtOperation>() = GetEhtOperation(linkId);
1249 }
1250
1251 return probe;
1252}
1253
1255ApWifiMac::GetProbeResp(uint8_t linkId, const std::optional<MultiLinkElement>& reqMle)
1256{
1257 NS_LOG_FUNCTION(this << linkId << reqMle.has_value());
1258 NS_ASSERT_MSG(linkId < GetNLinks(), "Invalid link ID = " << +linkId);
1259
1260 auto probeResp = GetProbeRespProfile(linkId);
1261
1262 if (GetNLinks() > 1)
1263 {
1264 /*
1265 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1266 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1267 * include a TBTT Information field in a Reduced Neighbor Report element with the
1268 * TBTT Information Length field set to 16 or higher, for each of the other APs
1269 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1270 */
1271 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1272 {
1273 probeResp.Get<ReducedNeighborReport>() = std::move(*rnr);
1274 }
1275 /*
1276 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1277 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1278 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1279 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1280 * channel switching, extended channel switching, and channel quieting) are
1281 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1282 */
1283 probeResp.Get<MultiLinkElement>() = GetMultiLinkElement(linkId,
1286 reqMle);
1287 }
1288 return probeResp;
1289}
1290
1293{
1295 StatusCode code;
1296 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1297 if (remoteStationManager->IsWaitAssocTxOk(to))
1298 {
1299 code.SetSuccess();
1300 }
1301 else
1302 {
1303 NS_ABORT_IF(!remoteStationManager->IsAssocRefused(to));
1304 // reset state
1305 remoteStationManager->RecordDisassociated(to);
1306 code.SetFailure();
1307 }
1308 auto supportedRates = GetSupportedRates(linkId);
1309 assoc.Get<SupportedRates>() = supportedRates.rates;
1310 assoc.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1311 assoc.SetStatusCode(code);
1312 assoc.Capabilities() = GetCapabilities(linkId);
1313 if (GetQosSupported())
1314 {
1315 assoc.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1316 }
1317 if (GetHtSupported(linkId))
1318 {
1320 assoc.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1321 assoc.Get<HtOperation>() = GetHtOperation(linkId);
1322 }
1323 if (GetVhtSupported(linkId))
1324 {
1325 assoc.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1326 assoc.Get<VhtOperation>() = GetVhtOperation(linkId);
1327 }
1328 if (GetHeSupported())
1329 {
1330 assoc.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1331 assoc.Get<HeOperation>() = GetHeOperation(linkId);
1332 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1333 {
1334 assoc.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1335 }
1336 if (Is6GhzBand(linkId))
1337 {
1339 }
1340 }
1341 if (GetEhtSupported())
1342 {
1343 assoc.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1344 assoc.Get<EhtOperation>() = GetEhtOperation(linkId);
1345 // The AP MLD that accepts the requested TID-to-link mapping shall not include in the
1346 // (Re)Association Response frame the TID-to-link Mapping element.
1347 // (Sec. 35.3.7.1.8 of 802.11be D3.1).
1348 // For now, we assume that AP MLDs always accept requested TID-to-link mappings.
1349 }
1350 return assoc;
1351}
1352
1355 const Mac48Address& to,
1356 uint8_t linkId)
1357{
1358 // find all the links to setup (i.e., those for which status code is success)
1359 std::map<uint8_t /* link ID */, Mac48Address> linkIdStaAddrMap;
1360
1361 if (assoc.GetStatusCode().IsSuccess())
1362 {
1363 linkIdStaAddrMap[linkId] = to;
1364 }
1365
1366 if (const auto& mle = assoc.Get<MultiLinkElement>())
1367 {
1368 const auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1369 NS_ABORT_MSG_IF(!staMldAddress.has_value(),
1370 "Sending a Multi-Link Element to a single link device");
1371 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1372 {
1373 auto& perStaProfile = mle->GetPerStaProfile(idx);
1374 if (perStaProfile.HasAssocResponse() &&
1375 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1376 {
1377 uint8_t otherLinkId = perStaProfile.GetLinkId();
1378 auto staAddress = GetWifiRemoteStationManager(otherLinkId)
1379 ->GetAffiliatedStaAddress(*staMldAddress);
1380 NS_ABORT_MSG_IF(!staAddress.has_value(),
1381 "No STA to associate with on link " << +otherLinkId);
1382 const auto [it, inserted] = linkIdStaAddrMap.insert({otherLinkId, *staAddress});
1383 NS_ABORT_MSG_IF(!inserted,
1384 "More than one Association Response to MLD "
1385 << *staMldAddress << " on link ID " << +otherLinkId);
1386 }
1387 }
1388 }
1389
1390 return linkIdStaAddrMap;
1391}
1392
1393void
1395{
1396 if (linkIdStaAddrMap.empty())
1397 {
1398 // no link to setup, nothing to do
1399 return;
1400 }
1401
1402 const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
1403 const auto addr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1404
1405 // check if an AID is already allocated to the device that is associating
1406 std::set<uint16_t> aids;
1407
1408 for (const auto& [id, link] : GetLinks())
1409 {
1410 if (const auto aid = link->stationManager->GetAssociationId(addr); aid != SU_STA_ID)
1411 {
1412 aids.insert(aid);
1413 }
1414 }
1415
1416 NS_ABORT_MSG_IF(aids.size() > 1, addr << " cannot have more than one AID assigned");
1417
1418 const auto aid = aids.empty() ? GetNextAssociationId() : *aids.cbegin();
1419
1420 // store the MLD or link address in the AID-to-address map
1421 const auto [it, inserted] = m_aidToMldOrLinkAddress.emplace(aid, addr);
1422
1423 NS_ABORT_MSG_IF(!inserted, "AID " << aid << " already present, cannot be assigned to " << addr);
1424
1425 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1426 {
1427 auto& link = GetLink(id);
1428
1429 if (const auto [it, inserted] = link.staList.emplace(aid, staAddr); inserted)
1430 {
1431 // the STA on this link had no AID assigned
1432 link.stationManager->SetAssociationId(staAddr, aid);
1433
1434 if (link.stationManager->GetDsssSupported(staAddr) &&
1435 !link.stationManager->GetErpOfdmSupported(staAddr))
1436 {
1437 link.numNonErpStations++;
1438 }
1439 if (!link.stationManager->GetHtSupported(staAddr) &&
1440 !link.stationManager->GetStationHe6GhzCapabilities(staAddr))
1441 {
1442 link.numNonHtStations++;
1443 }
1446 }
1447 else
1448 {
1449 // the STA on this link had an AID assigned
1450 NS_ABORT_MSG_IF(it->first != aid,
1451 "AID " << it->first << " already assigned to " << staAddr
1452 << ", could not assign " << aid);
1453 }
1454
1455 if (auto extendedCapabilities =
1456 GetWifiRemoteStationManager(linkId)->GetStationExtendedCapabilities(staAddr);
1458 {
1459 const auto isGcrCapable =
1460 extendedCapabilities && extendedCapabilities->m_robustAvStreaming;
1461 m_gcrManager->NotifyStaAssociated(staAddr, isGcrCapable);
1462 }
1463 }
1464
1465 // set the AID in all the Association Responses. NOTE that the Association
1466 // Responses included in the Per-STA Profile Subelements of the Multi-Link
1467 // Element must not contain the AID field. We set the AID field in such
1468 // Association Responses anyway, in order to ease future implementation of
1469 // the inheritance mechanism.
1470 if (assoc.GetStatusCode().IsSuccess())
1471 {
1472 assoc.SetAssociationId(aid);
1473 }
1474 if (const auto& mle = assoc.Get<MultiLinkElement>())
1475 {
1476 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1477 {
1478 if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1479 perStaProfile.HasAssocResponse() &&
1480 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1481 {
1482 perStaProfile.GetAssocResponse().SetAssociationId(aid);
1483 }
1484 }
1485 }
1486}
1487
1488void
1489ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1490{
1491 NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1492 WifiMacHeader hdr;
1495 hdr.SetAddr1(to);
1496 hdr.SetAddr2(GetFrameExchangeManager(linkId)->GetAddress());
1497 hdr.SetAddr3(GetFrameExchangeManager(linkId)->GetAddress());
1498 hdr.SetDsNotFrom();
1499 hdr.SetDsNotTo();
1500
1501 MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1502
1503 // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1504 // Request frame that carries a Basic Multi-Link element shall include a Basic
1505 // Multi-Link element in the (Re)Association Response frame that it transmits
1506 // (Sec. 35.3.5.4 of 802.11be D2.0)
1507 // If the STA included a Multi-Link Element in the (Re)Association Request, we
1508 // stored its MLD address in the remote station manager
1509 if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1510 {
1511 assoc.Get<MultiLinkElement>() = GetMultiLinkElement(linkId, hdr.GetType(), to);
1512 }
1513
1514 auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1515 SetAid(assoc, linkIdStaAddrMap);
1516
1517 Ptr<Packet> packet = Create<Packet>();
1518 packet->AddHeader(assoc);
1519
1520 if (!GetQosSupported())
1521 {
1522 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1523 }
1524 // "A QoS STA that transmits a Management frame determines access category used
1525 // for medium access in transmission of the Management frame as follows
1526 // (If dot11QMFActivated is false or not present)
1527 // — If the Management frame is individually addressed to a non-QoS STA, category
1528 // AC_BE should be selected.
1529 // — If category AC_BE was not selected by the previous step, category AC_VO
1530 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1531 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1532 {
1533 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1534 }
1535 else
1536 {
1537 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1538 }
1539}
1540
1541void
1543{
1544 NS_LOG_FUNCTION(this << +linkId);
1545 auto& link = GetLink(linkId);
1546 WifiMacHeader hdr;
1549 hdr.SetAddr2(link.feManager->GetAddress());
1550 hdr.SetAddr3(link.feManager->GetAddress());
1551 hdr.SetDsNotFrom();
1552 hdr.SetDsNotTo();
1553 Ptr<Packet> packet = Create<Packet>();
1554 MgtBeaconHeader beacon;
1555 beacon.Get<Ssid>() = GetSsid();
1556 auto supportedRates = GetSupportedRates(linkId);
1557 beacon.Get<SupportedRates>() = supportedRates.rates;
1558 beacon.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1559 beacon.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
1560 beacon.Capabilities() = GetCapabilities(linkId);
1561 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1562 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1563 if (GetDsssSupported(linkId))
1564 {
1565 beacon.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1566 }
1567 if (GetErpSupported(linkId))
1568 {
1569 beacon.Get<ErpInformation>() = GetErpInformation(linkId);
1570 }
1571 if (GetQosSupported())
1572 {
1573 beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1574 }
1575 if (GetHtSupported(linkId))
1576 {
1578 beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1579 beacon.Get<HtOperation>() = GetHtOperation(linkId);
1580 }
1581 if (GetVhtSupported(linkId))
1582 {
1583 beacon.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1584 beacon.Get<VhtOperation>() = GetVhtOperation(linkId);
1585 }
1586 if (GetHeSupported())
1587 {
1588 beacon.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1589 beacon.Get<HeOperation>() = GetHeOperation(linkId);
1590 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1591 {
1592 beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1593 }
1594 if (Is6GhzBand(linkId))
1595 {
1596 beacon.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
1597 }
1598 }
1599 if (GetEhtSupported())
1600 {
1601 beacon.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1602 beacon.Get<EhtOperation>() = GetEhtOperation(linkId);
1603
1604 if (GetNLinks() > 1)
1605 {
1606 /*
1607 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1608 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1609 * include a TBTT Information field in a Reduced Neighbor Report element with the
1610 * TBTT Information Length field set to 16 or higher, for each of the other APs
1611 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1612 */
1613 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1614 {
1615 beacon.Get<ReducedNeighborReport>() = std::move(*rnr);
1616 }
1617 /*
1618 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1619 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1620 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1621 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1622 * channel switching, extended channel switching, and channel quieting) are
1623 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1624 */
1626 }
1627 }
1628 packet->AddHeader(beacon);
1629
1630 NS_LOG_INFO("Generating beacon from " << link.feManager->GetAddress() << " linkID " << +linkId);
1631 // The beacon has it's own special queue, so we load it in there
1632 m_beaconTxop->Queue(Create<WifiMpdu>(packet, hdr));
1633 link.beaconEvent =
1635
1637
1638 // If a STA that does not support Short Slot Time associates,
1639 // the AP shall use long slot time beginning at the first Beacon
1640 // subsequent to the association of the long slot time STA.
1641 if (GetErpSupported(linkId))
1642 {
1643 if (link.shortSlotTimeEnabled)
1644 {
1645 // Enable short slot time
1646 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1647 }
1648 else
1649 {
1650 // Disable short slot time
1651 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1652 }
1653 }
1654}
1655
1657ApWifiMac::GetFilsDiscovery(uint8_t linkId) const
1658{
1661 auto& link = GetLink(linkId);
1662 hdr.SetAddr2(link.feManager->GetAddress());
1663 hdr.SetAddr3(link.feManager->GetAddress());
1664 hdr.SetDsNotFrom();
1665 hdr.SetDsNotTo();
1666
1667 WifiActionHeader actionHdr;
1669 action.publicAction = WifiActionHeader::FILS_DISCOVERY;
1670 actionHdr.SetAction(WifiActionHeader::PUBLIC, action);
1671
1672 FilsDiscHeader fils;
1673 fils.SetSsid(GetSsid().PeekString());
1674 fils.m_beaconInt = (m_beaconInterval / WIFI_TU).GetHigh();
1675
1677 fils.m_fdCap->SetOpChannelWidth(link.phy->GetChannelWidth());
1678 fils.m_fdCap->SetMaxNss(std::min(link.phy->GetMaxSupportedTxSpatialStreams(),
1679 link.phy->GetMaxSupportedRxSpatialStreams()));
1680 fils.m_fdCap->SetStandard(link.phy->GetStandard());
1681
1682 fils.SetLengthSubfield();
1683 fils.m_rnr = GetReducedNeighborReport(linkId);
1684
1685 auto packet = Create<Packet>();
1686 packet->AddHeader(fils);
1687 packet->AddHeader(actionHdr);
1688
1689 return Create<WifiMpdu>(packet, hdr);
1690}
1691
1692void
1694{
1695 NS_LOG_FUNCTION(this << linkId);
1696 auto phy = GetLink(linkId).phy;
1697
1698 auto fdBeaconInterval = (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) ? m_fdBeaconInterval6GHz
1700
1701 if (!fdBeaconInterval.IsStrictlyPositive())
1702 {
1703 NS_LOG_DEBUG("Sending FILS Discovery/unsolicited Probe Response disabled");
1704 return;
1705 }
1706
1707 // Schedule FD or unsolicited Probe Response frames (IEEE Std 802.11ax-2021 26.17.2.3.2)
1708 for (uint8_t count = 1; count < (m_beaconInterval / fdBeaconInterval).GetHigh(); ++count)
1709 {
1711 {
1712 Simulator::Schedule(fdBeaconInterval * count,
1714 this,
1715 GetProbeResp(linkId, std::nullopt),
1717 linkId);
1718 }
1719 else
1720 {
1721 Simulator::Schedule(fdBeaconInterval * count,
1722 [=, this]() { m_beaconTxop->Queue(GetFilsDiscovery(linkId)); });
1723 }
1724 }
1725}
1726
1727void
1729{
1730 NS_LOG_FUNCTION(this << *mpdu);
1731 const WifiMacHeader& hdr = mpdu->GetHeader();
1732
1733 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1734 {
1735 MgtAssocResponseHeader assocResp;
1736 mpdu->GetPacket()->PeekHeader(assocResp);
1737 auto aid = assocResp.GetAssociationId();
1738
1739 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1740 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1741
1742 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1743 {
1744 NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
1745 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxOk(hdr.GetAddr1());
1746 m_assocLogger(aid, hdr.GetAddr1());
1747 }
1748
1749 if (auto staMldAddress =
1750 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1751 staMldAddress.has_value())
1752 {
1753 /**
1754 * The STA is affiliated with an MLD. From Sec. 35.3.7.1.4 of 802.11be D3.0:
1755 * When a link becomes enabled for a non-AP STA that is affiliated with a non-AP MLD
1756 * after successful association with an AP MLD with (Re)Association Request/Response
1757 * frames transmitted on another link [...], the power management mode of the non-AP
1758 * STA, immediately after the acknowledgement of the (Re)Association Response frame
1759 * [...], is power save mode, and its power state is doze.
1760 *
1761 * Thus, STAs operating on all the links but the link used to establish association
1762 * transition to power save mode.
1763 */
1764 for (uint8_t i = 0; i < GetNLinks(); i++)
1765 {
1766 auto stationManager = GetWifiRemoteStationManager(i);
1767 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1768 staAddress.has_value() && i != *linkId &&
1769 stationManager->IsWaitAssocTxOk(*staAddress))
1770 {
1772 << " associated with STA=" << *staAddress);
1773 stationManager->RecordGotAssocTxOk(*staAddress);
1774 m_assocLogger(aid, *staAddress);
1775 StaSwitchingToPsMode(*staAddress, i);
1776 }
1777 }
1778
1779 // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
1781 }
1782 }
1783 else if (hdr.IsAction())
1784 {
1785 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
1786 category == WifiActionHeader::PROTECTED_EHT &&
1787 action.protectedEhtAction ==
1789 {
1790 // the EMLSR client acknowledged the EML Operating Mode Notification frame;
1791 // we can stop the timer and enforce the configuration deriving from the
1792 // EML Notification frame sent by the EMLSR client
1793 if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
1794 eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsPending())
1795 {
1796 // no need to wait until the expiration of the transition timeout
1797 eventIt->second.PeekEventImpl()->Invoke();
1798 eventIt->second.Cancel();
1799 }
1800 }
1801 }
1802}
1803
1804void
1806{
1807 NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
1808 const WifiMacHeader& hdr = mpdu->GetHeader();
1809
1810 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1811 {
1812 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1813 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1814
1815 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1816 {
1817 NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
1818 << " association failed with STA=" << hdr.GetAddr1());
1819 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxFailed(hdr.GetAddr1());
1820 }
1821
1822 if (auto staMldAddress =
1823 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1824 staMldAddress.has_value())
1825 {
1826 // the STA is affiliated with an MLD
1827 for (uint8_t i = 0; i < GetNLinks(); i++)
1828 {
1829 auto stationManager = GetWifiRemoteStationManager(i);
1830 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1831 staAddress.has_value() && i != *linkId &&
1832 stationManager->IsWaitAssocTxOk(*staAddress))
1833 {
1835 << " association failed with STA=" << *staAddress);
1836 stationManager->RecordGotAssocTxFailed(*staAddress);
1837 }
1838 }
1839 }
1840
1841 // free the assigned AID
1842 MgtAssocResponseHeader assocResp;
1843 mpdu->GetPacket()->PeekHeader(assocResp);
1844 auto aid = assocResp.GetAssociationId();
1845 m_aidToMldOrLinkAddress.erase(aid);
1846 for (const auto& [id, lnk] : GetLinks())
1847 {
1848 auto& link = GetLink(id);
1849 link.staList.erase(aid);
1850 }
1851 }
1852}
1853
1854void
1856{
1857 NS_LOG_FUNCTION(this << *mpdu << linkId);
1858
1859 Mac48Address staAddr = mpdu->GetHeader().GetAddr2();
1860 bool staInPsMode = GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr);
1861
1862 if (!staInPsMode && mpdu->GetHeader().IsPowerManagement())
1863 {
1864 // the sending STA is switching to Power Save mode
1865 StaSwitchingToPsMode(staAddr, linkId);
1866 }
1867 else if (staInPsMode && !mpdu->GetHeader().IsPowerManagement())
1868 {
1869 // the sending STA is switching back to Active mode
1871 }
1872}
1873
1874void
1875ApWifiMac::StaSwitchingToPsMode(const Mac48Address& staAddr, uint8_t linkId)
1876{
1877 NS_LOG_FUNCTION(this << staAddr << linkId);
1878
1879 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, true);
1880
1881 // Block frames addressed to the STA in PS mode
1882 NS_LOG_DEBUG("Block destination " << staAddr << " on link " << +linkId);
1883 auto staMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1885}
1886
1887void
1889{
1890 NS_LOG_FUNCTION(this << staAddr << linkId);
1891
1892 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, false);
1893
1894 if (GetWifiRemoteStationManager(linkId)->IsAssociated(staAddr))
1895 {
1896 // the station is still associated, unblock its frames
1897 NS_LOG_DEBUG("Unblock destination " << staAddr << " on link " << +linkId);
1898 auto staMldAddr =
1899 GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1901 }
1902}
1903
1904std::optional<uint8_t>
1906{
1907 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
1908 {
1909 if (GetWifiRemoteStationManager(linkId)->IsAssociated(address))
1910 {
1911 return linkId;
1912 }
1913 }
1914 NS_LOG_DEBUG(address << " is not associated");
1915 return std::nullopt;
1916}
1917
1920{
1921 auto linkId = IsAssociated(remoteAddr);
1922 NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
1923 return GetFrameExchangeManager(*linkId)->GetAddress();
1924}
1925
1926std::optional<Mac48Address>
1928{
1929 if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
1930 staIt != m_aidToMldOrLinkAddress.cend())
1931 {
1932 return staIt->second;
1933 }
1934 return std::nullopt;
1935}
1936
1937void
1939{
1940 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1941 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1942 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1943 Ptr<const Packet> packet = mpdu->GetPacket();
1944 Mac48Address from = hdr->GetAddr2();
1945 if (hdr->IsData())
1946 {
1947 std::optional<uint8_t> apLinkId;
1948 if (!hdr->IsFromDs() && hdr->IsToDs() &&
1949 (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
1950 mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
1951 {
1952 // this MPDU is being acknowledged by the AP, so we can process
1953 // the Power Management flag
1954 ProcessPowerManagementFlag(mpdu, *apLinkId);
1955
1956 Mac48Address to = hdr->GetAddr3();
1957 // Address3 can be our MLD address (e.g., this is an MPDU containing a single MSDU
1958 // addressed to us) or a BSSID (e.g., this is an MPDU containing an A-MSDU)
1959 if (to == GetAddress() ||
1960 (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
1961 {
1962 NS_LOG_DEBUG("frame for me from=" << from);
1963 if (hdr->IsQosData())
1964 {
1965 if (hdr->IsQosAmsdu())
1966 {
1967 NS_LOG_DEBUG("Received A-MSDU from=" << from
1968 << ", size=" << packet->GetSize());
1970 packet = nullptr;
1971 }
1972 else if (hdr->HasData())
1973 {
1974 ForwardUp(packet, from, GetAddress());
1975 }
1976 }
1977 else if (hdr->HasData())
1978 {
1979 ForwardUp(packet, from, GetAddress());
1980 }
1981 }
1982 else if (to.IsGroup() || IsAssociated(to))
1983 {
1984 NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
1985 Ptr<Packet> copy = packet->Copy();
1986
1987 // If the frame we are forwarding is of type QoS Data,
1988 // then we need to preserve the UP in the QoS control
1989 // header...
1990 if (hdr->IsQosData())
1991 {
1992 WifiMac::Enqueue(copy, to, from, hdr->GetQosTid());
1993 }
1994 else
1995 {
1996 WifiMac::Enqueue(copy, to, from);
1997 }
1998 ForwardUp(packet, from, to);
1999 }
2000 else if (hdr->HasData())
2001 {
2002 ForwardUp(packet, from, to);
2003 }
2004 }
2005 // NOLINTBEGIN(bugprone-branch-clone)
2006 else if (hdr->IsFromDs() && hdr->IsToDs())
2007 {
2008 // this is an AP-to-AP frame
2009 // we ignore for now.
2010 NotifyRxDrop(packet);
2011 }
2012 // NOLINTEND(bugprone-branch-clone)
2013 else
2014 {
2015 // we can ignore these frames since
2016 // they are not targeted at the AP
2017 NotifyRxDrop(packet);
2018 }
2019 return;
2020 }
2021 else if (hdr->IsMgt())
2022 {
2023 if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress() &&
2025 {
2026 // this MPDU is being acknowledged by the AP, so we can process
2027 // the Power Management flag
2028 ProcessPowerManagementFlag(mpdu, linkId);
2029 }
2030 if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
2031 hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
2032 {
2033 // In the case where the Address 1 field contains a group address, the
2034 // Address 3 field also is validated to verify that the group addressed
2035 // frame originated from a STA in the BSS of which the receiving STA is
2036 // a member (Section 9.3.3.1 of 802.11-2020)
2037 if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
2038 hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
2039 {
2040 // not addressed to us
2041 return;
2042 }
2043 MgtProbeRequestHeader probeRequestHeader;
2044 packet->PeekHeader(probeRequestHeader);
2045 const auto& ssid = probeRequestHeader.Get<Ssid>();
2046 if (ssid == GetSsid() || ssid->IsBroadcast())
2047 {
2048 NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
2049 const auto isReqBcast = hdr->GetAddr1().IsGroup() && hdr->GetAddr3().IsBroadcast();
2050 // not an ML Probe Request if ADDR1 and ADDR3 are broadcast
2051 const auto probeResp = GetProbeResp(
2052 linkId,
2053 isReqBcast ? std::nullopt : probeRequestHeader.Get<MultiLinkElement>());
2054 EnqueueProbeResp(probeResp, from, linkId);
2055 }
2056 return;
2057 }
2058 else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
2059 {
2060 switch (hdr->GetType())
2061 {
2064 NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
2065 << " request received from " << from
2066 << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
2067
2068 MgtAssocRequestHeader assocReq;
2069 MgtReassocRequestHeader reassocReq;
2070 AssocReqRefVariant frame = assocReq;
2071 if (hdr->IsAssocReq())
2072 {
2073 packet->PeekHeader(assocReq);
2074 }
2075 else
2076 {
2077 packet->PeekHeader(reassocReq);
2078 frame = reassocReq;
2079 }
2080 if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
2081 {
2082 ParseReportedStaInfo(frame, from, linkId);
2083 }
2084 SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
2085 return;
2086 }
2088 NS_LOG_DEBUG("Disassociation received from " << from);
2089 GetWifiRemoteStationManager(linkId)->RecordDisassociated(from);
2090 auto& staList = GetLink(linkId).staList;
2091 for (auto it = staList.begin(); it != staList.end(); ++it)
2092 {
2093 if (it->second == from)
2094 {
2095 staList.erase(it);
2096 m_deAssocLogger(it->first, it->second);
2097 if (GetWifiRemoteStationManager(linkId)->GetDsssSupported(from) &&
2098 !GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(from))
2099 {
2100 GetLink(linkId).numNonErpStations--;
2101 }
2102 if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from) &&
2103 !GetWifiRemoteStationManager(linkId)->GetStationHe6GhzCapabilities(
2104 from))
2105 {
2106 GetLink(linkId).numNonHtStations--;
2107 }
2111 if (m_gcrManager)
2112 {
2113 m_gcrManager->NotifyStaDeassociated(from);
2114 }
2115 break;
2116 }
2117 }
2118 return;
2119 }
2120 case WIFI_MAC_MGT_ACTION: {
2121 auto pkt = mpdu->GetPacket()->Copy();
2122 auto [category, action] = WifiActionHeader::Remove(pkt);
2123 if (category == WifiActionHeader::PROTECTED_EHT &&
2124 action.protectedEhtAction ==
2126 IsAssociated(hdr->GetAddr2()))
2127 {
2128 // received an EML Operating Mode Notification frame from an associated station
2129 MgtEmlOmn frame;
2130 pkt->RemoveHeader(frame);
2131 ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
2132 return;
2133 }
2134 break;
2135 }
2136 default:;
2137 // do nothing
2138 }
2139 }
2140 }
2141
2142 // Invoke the receive handler of our parent class to deal with any other frames
2143 WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
2144}
2145
2146bool
2148 const Mac48Address& from,
2149 uint8_t linkId)
2150{
2151 NS_LOG_FUNCTION(this << from << +linkId);
2152
2153 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
2154
2155 auto failure = [&](const std::string& msg) -> bool {
2156 NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
2157 remoteStationManager->RecordAssocRefused(from);
2158 return false;
2159 };
2160
2161 // lambda to process received (Re)Association Request
2162 auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
2163 const auto& frame = frameRefWrapper.get();
2164
2165 // first, verify that the the station's supported
2166 // rate set is compatible with our Basic Rate set
2167 const CapabilityInformation& capabilities = frame.Capabilities();
2168 remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
2169 NS_ASSERT(frame.template Get<SupportedRates>());
2170 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
2171 frame.template Get<ExtendedSupportedRatesIE>()};
2172
2173 if (rates.GetNRates() == 0)
2174 {
2175 return failure("STA's supported rate set not compatible with our Basic Rate set");
2176 }
2177
2178 if (GetHtSupported(linkId))
2179 {
2180 // check whether the HT STA supports all MCSs in Basic MCS Set
2181 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2182 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
2183 {
2184 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2185 {
2186 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2187 if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
2188 {
2189 return failure("HT STA does not support all MCSs in Basic MCS Set");
2190 }
2191 }
2192 }
2193 }
2194 if (GetVhtSupported(linkId))
2195 {
2196 // check whether the VHT STA supports all MCSs in Basic MCS Set
2197 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2198 if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
2199 {
2200 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2201 {
2202 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2203 if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2204 {
2205 return failure("VHT STA does not support all MCSs in Basic MCS Set");
2206 }
2207 }
2208 }
2209 }
2210 if (GetHeSupported())
2211 {
2212 // check whether the HE STA supports all MCSs in Basic MCS Set
2213 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2214 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2215 {
2216 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2217 {
2218 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2219 if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2220 {
2221 return failure("HE STA does not support all MCSs in Basic MCS Set");
2222 }
2223 }
2224 }
2225 if (Is6GhzBand(linkId))
2226 {
2227 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
2228 {
2229 remoteStationManager->AddStationHe6GhzCapabilities(from, *he6GhzCapabilities);
2230 }
2231 }
2232 }
2233 if (GetEhtSupported())
2234 {
2235 // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
2236 auto ehtConfig = GetEhtConfiguration();
2237 NS_ASSERT(ehtConfig);
2238
2239 if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
2240 !tidLinkMapping.empty())
2241 {
2242 // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
2243 // We refuse association if we do not support TID-to-Link mapping negotiation
2244 // or the non-AP MLD included more than two TID-to-Link Mapping IEs
2245 // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
2246 // or there is some TID that is not mapped to any link
2247 // or the direction(s) is/are not set properly
2248 if (tidLinkMapping.size() > 2)
2249 {
2250 return failure("More than two TID-to-Link Mapping IEs");
2251 }
2252
2253 // if only one Tid-to-Link Mapping element is present, it must be valid for
2254 // both directions
2255 bool bothDirIfOneTlm =
2256 tidLinkMapping.size() != 1 ||
2257 tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
2258 // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
2259 // Request frame or a (Re)Association Response frame shall set the Direction
2260 // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
2261 // subfield in the other TID-To- Link Mapping element to 1.
2262 // (Sec. 35.3.7.1.8 of 802.11be D3.1)
2263 bool distinctDirsIfTwoTlms =
2264 tidLinkMapping.size() != 2 ||
2265 (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2266 tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2267 tidLinkMapping[0].m_control.direction !=
2268 tidLinkMapping[1].m_control.direction);
2269
2270 if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
2271 {
2272 return failure("Incorrect directions in TID-to-Link Mapping IEs");
2273 }
2274
2275 if (ehtConfig->m_tidLinkMappingSupport ==
2277 {
2278 return failure("TID-to-Link Mapping negotiation not supported");
2279 }
2280
2281 auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
2282 if (tlmIe.m_control.defaultMapping)
2283 {
2284 return;
2285 }
2286 for (uint8_t tid = 0; tid < 8; tid++)
2287 {
2288 if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
2289 {
2290 mapping.emplace(tid, std::move(linkSet));
2291 }
2292 }
2293 };
2294
2295 WifiTidLinkMapping dlMapping;
2296 WifiTidLinkMapping ulMapping;
2297
2298 switch (tidLinkMapping[0].m_control.direction)
2299 {
2301 getMapping(tidLinkMapping.at(0), dlMapping);
2302 ulMapping = dlMapping;
2303 break;
2305 getMapping(tidLinkMapping.at(0), dlMapping);
2306 getMapping(tidLinkMapping.at(1), ulMapping);
2307 break;
2309 getMapping(tidLinkMapping.at(0), ulMapping);
2310 getMapping(tidLinkMapping.at(1), dlMapping);
2311 break;
2312 }
2313
2314 if (ehtConfig->m_tidLinkMappingSupport ==
2316 !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
2317 {
2318 return failure("Mapping TIDs to distinct link sets is incompatible with "
2319 "negotiation support of 1");
2320 }
2321
2322 // otherwise, we accept the TID-to-link Mapping and store it
2323 const auto& mle = frame.template Get<MultiLinkElement>();
2324 NS_ASSERT_MSG(mle,
2325 "Multi-Link Element not present in an Association Request including "
2326 "TID-to-Link Mapping element(s)");
2327 auto mldAddr = mle->GetMldMacAddress();
2328
2329 // The requested link mappings are valid and can be accepted; store them.
2331 UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
2332 }
2333 }
2334
2335 // The association request from the station can be accepted.
2336 // Record all its supported modes in its associated WifiRemoteStation
2337 auto phy = GetWifiPhy(linkId);
2338
2339 for (const auto& mode : phy->GetModeList())
2340 {
2341 if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
2342 {
2343 remoteStationManager->AddSupportedMode(from, mode);
2344 }
2345 }
2346 if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
2347 capabilities.IsShortSlotTime())
2348 {
2349 remoteStationManager->AddSupportedErpSlotTime(from, true);
2350 }
2351 if (GetHtSupported(linkId))
2352 {
2353 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2354 if (htCapabilities.has_value())
2355 {
2356 remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
2357 }
2358 const auto& extendedCapabilities = frame.template Get<ExtendedCapabilities>();
2359 if (extendedCapabilities.has_value())
2360 {
2361 remoteStationManager->AddStationExtendedCapabilities(from, *extendedCapabilities);
2362 }
2363 }
2364 if (GetVhtSupported(linkId))
2365 {
2366 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2367 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
2368 // to check whether it supports VHT
2369 if (vhtCapabilities.has_value() &&
2370 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
2371 {
2372 remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
2373 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
2374 {
2375 if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2376 {
2377 remoteStationManager->AddSupportedMcs(from, mcs);
2378 // here should add a control to add basic MCS when it is implemented
2379 }
2380 }
2381 }
2382 }
2383 if (GetHeSupported())
2384 {
2385 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2386 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2387 {
2388 remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
2389 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
2390 {
2391 if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2392 {
2393 remoteStationManager->AddSupportedMcs(from, mcs);
2394 // here should add a control to add basic MCS when it is implemented
2395 }
2396 }
2397 }
2398 }
2399 if (GetEhtSupported())
2400 {
2401 if (const auto& ehtCapabilities = frame.template Get<EhtCapabilities>())
2402 {
2403 remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
2404 }
2405 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
2406 {
2407 // TODO: Add check whether MCS is supported from the capabilities
2408 remoteStationManager->AddSupportedMcs(from, mcs);
2409 // here should add a control to add basic MCS when it is implemented
2410 }
2411 }
2412
2413 NS_LOG_DEBUG("Association Request from " << from << " accepted");
2414 remoteStationManager->RecordWaitAssocTxOk(from);
2415 return true;
2416 };
2417
2418 return std::visit(recvAssocRequest, assoc);
2419}
2420
2421void
2423{
2424 NS_LOG_FUNCTION(this << from << +linkId);
2425
2426 // lambda to process received Multi-Link Element
2427 auto recvMle = [&](auto&& frame) {
2428 const auto& mle = frame.get().template Get<MultiLinkElement>();
2429
2430 if (!mle.has_value())
2431 {
2432 return;
2433 }
2434
2435 auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
2436 GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
2437
2438 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
2439 {
2440 auto& perStaProfile = mle->GetPerStaProfile(i);
2441 if (!perStaProfile.HasStaMacAddress())
2442 {
2443 NS_LOG_DEBUG("[i=" << i
2444 << "] Cannot setup a link if the STA MAC address is missing");
2445 continue;
2446 }
2447 uint8_t newLinkId = perStaProfile.GetLinkId();
2448 if (newLinkId == linkId || newLinkId >= GetNLinks())
2449 {
2450 NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
2451 continue;
2452 }
2453 if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
2454 {
2455 NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
2456 continue;
2457 }
2458
2459 ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
2460 perStaProfile.GetStaMacAddress(),
2461 newLinkId);
2462 GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
2463 perStaProfile.GetStaMacAddress(),
2464 mleCommonInfo);
2465 }
2466 };
2467
2468 std::visit(recvMle, assoc);
2469}
2470
2471void
2472ApWifiMac::ReceiveEmlOmn(MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
2473{
2474 NS_LOG_FUNCTION(this << frame << sender << linkId);
2475
2476 auto ehtConfiguration = GetEhtConfiguration();
2477
2478 if (!ehtConfiguration || !ehtConfiguration->m_emlsrActivated)
2479 {
2481 "Received an EML Operating Mode Notification frame but EMLSR is not activated");
2482 return;
2483 }
2484
2486 {
2488 auto emlCapabilities =
2489 GetWifiRemoteStationManager(linkId)->GetStationEmlCapabilities(sender);
2490 NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
2491
2492 // update values stored in remote station manager
2493 emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
2494 emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
2495 }
2496
2497 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
2498 NS_ASSERT_MSG(mldAddress, "No MLD address stored for STA " << sender);
2499 auto emlsrLinks =
2500 frame.m_emlControl.emlsrMode == 1 ? frame.GetLinkBitmap() : std::list<uint8_t>{};
2501
2502 // The AP MLD has to consider the changes carried by the received EML Notification frame
2503 // as effective at the same time as the non-AP MLD. Therefore, we need to start a time
2504 // when the transmission of the Ack following the received EML Notification frame is
2505 // completed. For this purpose, we connect a callback to the PHY TX begin trace to catch
2506 // the Ack transmitted after the EML Notification frame.
2508 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
2509 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
2510 psduMap.begin()->second->GetHeader(0).IsAck(),
2511 "Expected a Normal Ack after EML Notification frame");
2512
2513 auto ackDuration =
2514 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
2515
2517 ackDuration + ehtConfiguration->m_transitionTimeout,
2518 [=, this]() {
2519 for (uint8_t id = 0; id < GetNLinks(); id++)
2520 {
2521 auto linkAddress =
2522 GetWifiRemoteStationManager(id)->GetAffiliatedStaAddress(*mldAddress);
2523 if (!linkAddress)
2524 {
2525 // this link has not been setup by the non-AP MLD
2526 continue;
2527 }
2528
2529 if (!emlsrLinks.empty())
2530 {
2531 // the non-AP MLD is enabling EMLSR mode
2532 /**
2533 * After the successful transmission of the EML Operating Mode
2534 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
2535 * the non-AP MLD shall operate in the EMLSR mode and the other non-AP
2536 * STAs operating on the corresponding EMLSR links shall transition to
2537 * active mode after the transition delay indicated in the Transition
2538 * Timeout subfield in the EML Capabilities subfield of the Basic
2539 * Multi-Link element or immediately after receiving an EML Operating
2540 * Mode Notification frame from one of the APs operating on the EMLSR
2541 * links and affiliated with the AP MLD (Sec. 35.3.17 of 802.11be D3.0)
2542 */
2543 auto enabled = std::find(emlsrLinks.cbegin(), emlsrLinks.cend(), id) !=
2544 emlsrLinks.cend();
2545 if (enabled)
2546 {
2547 StaSwitchingToActiveModeOrDeassociated(*linkAddress, id);
2548 }
2549 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, enabled);
2550 }
2551 else
2552 {
2553 // the non-AP MLD is disabling EMLSR mode
2554 /**
2555 * After the successful transmission of the EML Operating Mode
2556 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
2557 * the non-AP MLD shall disable the EMLSR mode and the other non-AP
2558 * STAs operating on the corresponding EMLSR links shall transition to
2559 * power save mode after the transition delay indicated in the
2560 * Transition Timeout subfield in the EML Capabilities subfield of the
2561 * Basic Multi-Link element or immediately after receiving an EML
2562 * Operating Mode Notification frame from one of the APs operating on
2563 * the EMLSR links and affiliated with the AP MLD. (Sec. 35.3.17 of
2564 * 802.11be D3.0)
2565 */
2566 if (id != linkId &&
2567 GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*linkAddress))
2568 {
2569 StaSwitchingToPsMode(*linkAddress, id);
2570 }
2571 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, false);
2572 }
2573 }
2574 });
2575 });
2576
2577 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
2578 // after its transmission begins
2579 auto phy = GetLink(linkId).phy;
2580 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
2581 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
2582 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
2583
2584 // An AP MLD with dot11EHTEMLSROptionActivated equal to true sets the EMLSR Mode subfield
2585 // to the value obtained from the EMLSR Mode subfield of the received EML Operating Mode
2586 // Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2587
2588 // When included in a frame sent by an AP affiliated with an AP MLD, the EMLSR Parameter
2589 // Update Control subfield is set to 0. (Sec. 9.6.35.8 of 802.11be D3.0)
2590 frame.m_emlControl.emlsrParamUpdateCtrl = 0;
2591
2592 // An AP MLD with dot11EHTEMLSROptionImplemented equal to true sets the EMLSR Link Bitmap
2593 // subfield to the value obtained from the EMLSR Link Bitmap subfield of the received
2594 // EML Operating Mode Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2595
2596 // The EMLSR Parameter Update field [..] is present if [..] the Action frame is sent by
2597 // a non-AP STA affiliated with a non-AP MLD (Sec. 9.6.35.8 of 802.11be D3.0)
2598 frame.m_emlsrParamUpdate.reset();
2599
2600 auto ehtFem = StaticCast<EhtFrameExchangeManager>(GetFrameExchangeManager(linkId));
2601 ehtFem->SendEmlOmn(sender, frame);
2602}
2603
2604void
2606{
2607 NS_LOG_FUNCTION(this << *mpdu);
2608 for (auto& i : *PeekPointer(mpdu))
2609 {
2610 auto from = i.second.GetSourceAddr();
2611 auto to = i.second.GetDestinationAddr();
2612
2613 if (to.IsGroup() || IsAssociated(to))
2614 {
2615 NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
2616 WifiMac::Enqueue(i.first->Copy(), to, from, mpdu->GetHeader().GetQosTid());
2617 }
2618
2619 ForwardUp(i.first, from, to);
2620 }
2621}
2622
2623void
2625{
2626 NS_LOG_FUNCTION(this);
2628
2629 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
2630 {
2631 GetLink(linkId).beaconEvent.Cancel();
2633 {
2634 uint64_t jitterUs =
2636 ? static_cast<uint64_t>(m_beaconJitter->GetValue(0, 1) *
2638 : 0);
2639 NS_LOG_DEBUG("Scheduling initial beacon for access point "
2640 << GetAddress() << " at time " << jitterUs << "us");
2643 this,
2644 linkId);
2645 }
2648 }
2649
2650 if (m_gcrManager)
2651 {
2652 m_gcrManager->Initialize();
2653 }
2654
2659}
2660
2661bool
2663{
2664 bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
2665 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
2666 return useProtection;
2667}
2668
2669uint16_t
2671{
2672 const auto& links = GetLinks();
2673
2674 // Return the first AID value between 1 and 2007 that is free for all the links
2675 for (uint16_t nextAid = 1; nextAid <= 2007; ++nextAid)
2676 {
2677 if (std::none_of(links.cbegin(), links.cend(), [&](auto&& idLinkPair) {
2678 return GetStaList(idLinkPair.first).contains(nextAid);
2679 }))
2680 {
2681 return nextAid;
2682 }
2683 }
2684 NS_FATAL_ERROR("No free association ID available!");
2685 return 0;
2686}
2687
2688const std::map<uint16_t, Mac48Address>&
2689ApWifiMac::GetStaList(uint8_t linkId) const
2690{
2691 return GetLink(linkId).staList;
2692}
2693
2694uint16_t
2696{
2697 return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
2698}
2699
2700uint8_t
2701ApWifiMac::GetBufferStatus(uint8_t tid, Mac48Address address) const
2702{
2703 auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
2704 if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
2705 {
2706 return 255;
2707 }
2708 return it->second.value;
2709}
2710
2711void
2712ApWifiMac::SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
2713{
2714 if (size == 255)
2715 {
2716 // no point in storing an unspecified size
2717 m_bufferStatus.erase(WifiAddressTidPair(address, tid));
2718 }
2719 else
2720 {
2721 m_bufferStatus[WifiAddressTidPair(address, tid)] = {size, Simulator::Now()};
2722 }
2723}
2724
2725uint8_t
2727{
2728 uint8_t maxSize = 0;
2729 bool found = false;
2730
2731 for (uint8_t tid = 0; tid < 8; tid++)
2732 {
2733 uint8_t size = GetBufferStatus(tid, address);
2734 if (size != 255)
2735 {
2736 maxSize = std::max(maxSize, size);
2737 found = true;
2738 }
2739 }
2740
2741 if (found)
2742 {
2743 return maxSize;
2744 }
2745 return 255;
2746}
2747
2748bool
2750 uint8_t tid) const
2751{
2753 return GetQosTxop(tid)->GetBaManager()->IsGcrAgreementEstablished(
2754 groupAddress,
2755 tid,
2756 m_gcrManager->GetMemberStasForGroupAddress(groupAddress));
2757}
2758
2759} // namespace ns3
Wi-Fi AP state machine.
Definition ap-wifi-mac.h:60
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.
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.
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< UniformRandomVariable > m_beaconJitter
UniformRandomVariable used to randomize the time of the first beacon.
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.
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.
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 deassociates or switches from powersave mode to ac...
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....
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.
static Ptr< const AttributeChecker > GetTimeAccessParamsChecker()
Get a checker for the TxopLimitsForSta attribute, which can be used to deserialize an ACI-indexed map...
bool m_enableBeaconGeneration
Flag whether beacons are being generated.
Time m_beaconInterval
Beacon interval.
Ptr< GcrManager > GetGcrManager() const
MultiLinkElement GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac48Address &to=Mac48Address::GetBroadcast(), const std::optional< MultiLinkElement > &mlProbeReqMle=std::nullopt)
Return the Multi-Link Element that the current AP includes in the management frames of the given type...
bool m_enableBeaconJitter
Flag whether the first beacon should be generated at random time.
std::unordered_map< WifiAddressTidPair, BsrType, WifiAddressTidHash > m_bufferStatus
Per (MAC address, TID) buffer status reports.
DsssParameterSet GetDsssParameterSet(uint8_t linkId) const
Return the DSSS Parameter Set that we support on the given link.
TracedCallback< uint16_t, Mac48Address > m_assocLogger
association logger
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,...
void ReceiveEmlOmn(MgtEmlOmn &frame, const Mac48Address &sender, uint8_t linkId)
Take necessary actions upon receiving the given EML Operating Mode Notification frame from the given ...
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.
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...
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
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.
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.
Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const override
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
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 switches from active mode 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:344
Callback template class.
Definition callback.h:422
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.
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.
CapabilityInformation & Capabilities()
StatusCode GetStatusCode()
Return the status code.
void SetStatusCode(StatusCode code)
Set the status code.
void SetAssociationId(uint16_t aid)
Set the association ID.
uint16_t GetAssociationId() const
Return the association ID.
Implement the header for management frames of type beacon.
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.
void SetBeaconIntervalUs(uint64_t us)
Set the beacon interval in microseconds unit.
CapabilityInformation & Capabilities()
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.
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition object.cc:203
void Dispose()
Dispose of this Object.
Definition object.cc:247
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition qos-txop.cc:285
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:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
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.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:402
AttributeValue implementation for Time.
Definition nstime.h:1431
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Definition txop.cc:697
void SetMaxCws(const std::vector< uint32_t > &maxCws)
Set the maximum contention window size for each link.
Definition txop.cc:319
void SetAifsns(const std::vector< uint8_t > &aifsns)
Set the number of slots that make up an AIFS for each link.
Definition txop.cc:453
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition txop.cc:264
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the wifi MAC this Txop is associated to.
Definition txop.cc:242
virtual void Queue(Ptr< WifiMpdu > mpdu)
Definition txop.cc:635
void SetTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set MacTxMiddle this Txop is associated to.
Definition txop.cc:235
void SetMinCws(const std::vector< uint32_t > &minCws)
Set the minimum contention window size for each link.
Definition txop.cc:276
a unique identifier for an interface.
Definition type-id.h:49
@ ATTR_GET
The attribute can be read.
Definition type-id.h:54
@ ATTR_CONSTRUCT
The attribute can be written at construction-time.
Definition type-id.h:56
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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 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.
base class for all MAC-level wifi objects.
Definition wifi-mac.h:90
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:1014
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:1858
Ptr< HeConfiguration > GetHeConfiguration() const
Definition wifi-mac.cc:1980
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition wifi-mac.cc:1091
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:2261
bool GetQosSupported() const
Return whether the device supports QoS.
Definition wifi-mac.cc:1409
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition wifi-mac.cc:1106
void Enqueue(Ptr< Packet > packet, Mac48Address to)
Definition wifi-mac.cc:1733
void DoInitialize() override
Initialize() implementation.
Definition wifi-mac.cc:418
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Definition wifi-mac.cc:1620
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:1415
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:1377
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Definition wifi-mac.cc:1574
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition wifi-mac.cc:2013
bool GetHeSupported() const
Return whether the device supports HE.
Definition wifi-mac.cc:2007
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition wifi-mac.cc:2202
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:1138
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:1492
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition wifi-mac.cc:1986
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition wifi-mac.cc:1999
Ptr< MacTxMiddle > m_txMiddle
TX middle (aggregation etc.)
Definition wifi-mac.h:969
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:1968
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:1269
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition wifi-mac.cc:2194
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:2397
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition wifi-mac.cc:664
bool GetShortSlotTimeSupported() const
Definition wifi-mac.cc:1459
void NotifyRxDrop(Ptr< const Packet > packet)
Definition wifi-mac.cc:738
virtual void SetLinkUpCallback(Callback< void > linkUp)
Definition wifi-mac.cc:1478
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition wifi-mac.cc:1079
bool GetHtSupported(uint8_t linkId) const
Return whether the device supports HT on the given link.
Definition wifi-mac.cc:1992
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition wifi-mac.cc:1809
bool Is6GhzBand(uint8_t linkId) const
Indicate if a given link is on the 6 GHz band.
Definition wifi-mac.cc:1261
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:1816
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:2432
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition wifi-mac.cc:1097
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition wifi-mac.cc:2341
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:1439
represent a single transmission mode
Definition wifi-mode.h:40
const std::string & GetUniqueName() const
Definition wifi-mode.cc:137
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:111
uint8_t GetMcsValue() const
Definition wifi-mode.cc:152
std::list< uint8_t > GetBssMembershipSelectorList() const
The WifiPhy::BssMembershipSelector() method is used (e.g., by a WifiRemoteStationManager) to determin...
Definition wifi-phy.cc:1402
uint8_t GetMaxSupportedRxSpatialStreams() const
Definition wifi-phy.cc:1396
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition wifi-phy.cc:835
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1099
std::list< WifiMode > GetModeList() const
The WifiPhy::GetModeList() method is used (e.g., by a WifiRemoteStationManager) to determine the set ...
Definition wifi-phy.cc:2064
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition wifi-phy.cc:1081
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< 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()
Make a PairChecker without abscissa and ordinate AttributeCheckers.
Definition pair.h:289
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:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
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:1432
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1452
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
#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:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:264
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:436
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1368
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
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
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
@ 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
Best Effort.
Definition qos-utils.h:64
@ AC_VO
Voice.
Definition qos-utils.h:70
@ AC_VI
Video.
Definition qos-utils.h:68
@ AC_BK
Background.
Definition qos-utils.h:66
@ AC_BEACON
Beacon queue.
Definition qos-utils.h:74
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
const Time WIFI_TU
Wi-Fi Time Unit (see IEEE 802.11-2020 sec. 3.1)
Definition wifi-utils.cc:24
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:684
@ NO_PROTECTION
@ MIXED_MODE_PROTECTION
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:179
bool IsGroupcast(const Mac48Address &adr)
Check whether a MAC destination address corresponds to a groupcast transmission.
std::map< uint8_t, std::set< uint8_t > > WifiTidLinkMapping
TID-indexed map of the link set to which the TID is mapped.
Definition wifi-utils.h:67
constexpr uint8_t WIFI_EHT_MAX_MCS_INDEX
IEEE 802.11be D2.0 Figure 9-1002ai.
WifiMacType
Combination of valid MAC header type/subtype.
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_DISASSOCIATION
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
@ WIFI_MAC_MGT_REASSOCIATION_REQUEST
@ WIFI_MAC_MGT_PROBE_RESPONSE
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping &dlLinkMapping, const WifiTidLinkMapping &ulLinkMapping)
Check if the given TID-to-Link Mappings are valid for a negotiation type of 1.
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
std::pair< Mac48Address, uint8_t > WifiAddressTidPair
(MAC address, TID) pair
Definition qos-utils.h:25
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
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:45
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
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...
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_primCh
Primary Channel.
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
typedef for union of different ActionValues