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
1456 // set the AID in all the Association Responses. NOTE that the Association
1457 // Responses included in the Per-STA Profile Subelements of the Multi-Link
1458 // Element must not contain the AID field. We set the AID field in such
1459 // Association Responses anyway, in order to ease future implementation of
1460 // the inheritance mechanism.
1461 if (assoc.GetStatusCode().IsSuccess())
1462 {
1463 assoc.SetAssociationId(aid);
1464 }
1465 if (const auto& mle = assoc.Get<MultiLinkElement>())
1466 {
1467 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1468 {
1469 if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1470 perStaProfile.HasAssocResponse() &&
1471 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1472 {
1473 perStaProfile.GetAssocResponse().SetAssociationId(aid);
1474 }
1475 }
1476 }
1477}
1478
1479void
1480ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1481{
1482 NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1483 WifiMacHeader hdr;
1486 hdr.SetAddr1(to);
1487 hdr.SetAddr2(GetFrameExchangeManager(linkId)->GetAddress());
1488 hdr.SetAddr3(GetFrameExchangeManager(linkId)->GetAddress());
1489 hdr.SetDsNotFrom();
1490 hdr.SetDsNotTo();
1491
1492 MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1493
1494 // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1495 // Request frame that carries a Basic Multi-Link element shall include a Basic
1496 // Multi-Link element in the (Re)Association Response frame that it transmits
1497 // (Sec. 35.3.5.4 of 802.11be D2.0)
1498 // If the STA included a Multi-Link Element in the (Re)Association Request, we
1499 // stored its MLD address in the remote station manager
1500 if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1501 {
1502 assoc.Get<MultiLinkElement>() = GetMultiLinkElement(linkId, hdr.GetType(), to);
1503 }
1504
1505 auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1506 SetAid(assoc, linkIdStaAddrMap);
1507
1508 Ptr<Packet> packet = Create<Packet>();
1509 packet->AddHeader(assoc);
1510
1511 if (!GetQosSupported())
1512 {
1513 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1514 }
1515 // "A QoS STA that transmits a Management frame determines access category used
1516 // for medium access in transmission of the Management frame as follows
1517 // (If dot11QMFActivated is false or not present)
1518 // — If the Management frame is individually addressed to a non-QoS STA, category
1519 // AC_BE should be selected.
1520 // — If category AC_BE was not selected by the previous step, category AC_VO
1521 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1522 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1523 {
1524 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1525 }
1526 else
1527 {
1528 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1529 }
1530}
1531
1532void
1534{
1535 NS_LOG_FUNCTION(this << +linkId);
1536 auto& link = GetLink(linkId);
1537 WifiMacHeader hdr;
1540 hdr.SetAddr2(link.feManager->GetAddress());
1541 hdr.SetAddr3(link.feManager->GetAddress());
1542 hdr.SetDsNotFrom();
1543 hdr.SetDsNotTo();
1544 Ptr<Packet> packet = Create<Packet>();
1545 MgtBeaconHeader beacon;
1546 beacon.Get<Ssid>() = GetSsid();
1547 auto supportedRates = GetSupportedRates(linkId);
1548 beacon.Get<SupportedRates>() = supportedRates.rates;
1549 beacon.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1550 beacon.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
1551 beacon.Capabilities() = GetCapabilities(linkId);
1552 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1553 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1554 if (GetDsssSupported(linkId))
1555 {
1556 beacon.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1557 }
1558 if (GetErpSupported(linkId))
1559 {
1560 beacon.Get<ErpInformation>() = GetErpInformation(linkId);
1561 }
1562 if (GetQosSupported())
1563 {
1564 beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1565 }
1566 if (GetHtSupported(linkId))
1567 {
1569 beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1570 beacon.Get<HtOperation>() = GetHtOperation(linkId);
1571 }
1572 if (GetVhtSupported(linkId))
1573 {
1574 beacon.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1575 beacon.Get<VhtOperation>() = GetVhtOperation(linkId);
1576 }
1577 if (GetHeSupported())
1578 {
1579 beacon.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1580 beacon.Get<HeOperation>() = GetHeOperation(linkId);
1581 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1582 {
1583 beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1584 }
1585 if (Is6GhzBand(linkId))
1586 {
1587 beacon.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
1588 }
1589 }
1590 if (GetEhtSupported())
1591 {
1592 beacon.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1593 beacon.Get<EhtOperation>() = GetEhtOperation(linkId);
1594
1595 if (GetNLinks() > 1)
1596 {
1597 /*
1598 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1599 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1600 * include a TBTT Information field in a Reduced Neighbor Report element with the
1601 * TBTT Information Length field set to 16 or higher, for each of the other APs
1602 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1603 */
1604 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1605 {
1606 beacon.Get<ReducedNeighborReport>() = std::move(*rnr);
1607 }
1608 /*
1609 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1610 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1611 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1612 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1613 * channel switching, extended channel switching, and channel quieting) are
1614 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1615 */
1617 }
1618 }
1619 packet->AddHeader(beacon);
1620
1621 NS_LOG_INFO("Generating beacon from " << link.feManager->GetAddress() << " linkID " << +linkId);
1622 // The beacon has it's own special queue, so we load it in there
1623 m_beaconTxop->Queue(Create<WifiMpdu>(packet, hdr));
1624 link.beaconEvent =
1626
1628
1629 // If a STA that does not support Short Slot Time associates,
1630 // the AP shall use long slot time beginning at the first Beacon
1631 // subsequent to the association of the long slot time STA.
1632 if (GetErpSupported(linkId))
1633 {
1634 if (link.shortSlotTimeEnabled)
1635 {
1636 // Enable short slot time
1637 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1638 }
1639 else
1640 {
1641 // Disable short slot time
1642 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1643 }
1644 }
1645}
1646
1648ApWifiMac::GetFilsDiscovery(uint8_t linkId) const
1649{
1652 auto& link = GetLink(linkId);
1653 hdr.SetAddr2(link.feManager->GetAddress());
1654 hdr.SetAddr3(link.feManager->GetAddress());
1655 hdr.SetDsNotFrom();
1656 hdr.SetDsNotTo();
1657
1658 WifiActionHeader actionHdr;
1660 action.publicAction = WifiActionHeader::FILS_DISCOVERY;
1661 actionHdr.SetAction(WifiActionHeader::PUBLIC, action);
1662
1663 FilsDiscHeader fils;
1664 fils.SetSsid(GetSsid().PeekString());
1665 fils.m_beaconInt = (m_beaconInterval / WIFI_TU).GetHigh();
1666
1668 fils.m_fdCap->SetOpChannelWidth(link.phy->GetChannelWidth());
1669 fils.m_fdCap->SetMaxNss(std::min(link.phy->GetMaxSupportedTxSpatialStreams(),
1670 link.phy->GetMaxSupportedRxSpatialStreams()));
1671 fils.m_fdCap->SetStandard(link.phy->GetStandard());
1672
1673 fils.SetLengthSubfield();
1674 fils.m_rnr = GetReducedNeighborReport(linkId);
1675
1676 auto packet = Create<Packet>();
1677 packet->AddHeader(fils);
1678 packet->AddHeader(actionHdr);
1679
1680 return Create<WifiMpdu>(packet, hdr);
1681}
1682
1683void
1685{
1686 NS_LOG_FUNCTION(this << linkId);
1687 auto phy = GetLink(linkId).phy;
1688
1689 auto fdBeaconInterval = (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) ? m_fdBeaconInterval6GHz
1691
1692 if (!fdBeaconInterval.IsStrictlyPositive())
1693 {
1694 NS_LOG_DEBUG("Sending FILS Discovery/unsolicited Probe Response disabled");
1695 return;
1696 }
1697
1698 // Schedule FD or unsolicited Probe Response frames (IEEE Std 802.11ax-2021 26.17.2.3.2)
1699 for (uint8_t count = 1; count < (m_beaconInterval / fdBeaconInterval).GetHigh(); ++count)
1700 {
1702 {
1703 Simulator::Schedule(fdBeaconInterval * count,
1705 this,
1706 GetProbeResp(linkId, std::nullopt),
1708 linkId);
1709 }
1710 else
1711 {
1712 Simulator::Schedule(fdBeaconInterval * count,
1713 [=, this]() { m_beaconTxop->Queue(GetFilsDiscovery(linkId)); });
1714 }
1715 }
1716}
1717
1718void
1720{
1721 NS_LOG_FUNCTION(this << *mpdu);
1722 const WifiMacHeader& hdr = mpdu->GetHeader();
1723
1724 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1725 {
1726 MgtAssocResponseHeader assocResp;
1727 mpdu->GetPacket()->PeekHeader(assocResp);
1728 auto aid = assocResp.GetAssociationId();
1729
1730 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1731 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1732
1733 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1734 {
1735 NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
1736 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxOk(hdr.GetAddr1());
1737 m_assocLogger(aid, hdr.GetAddr1());
1738 }
1739
1740 if (auto staMldAddress =
1741 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1742 staMldAddress.has_value())
1743 {
1744 /**
1745 * The STA is affiliated with an MLD. From Sec. 35.3.7.1.4 of 802.11be D3.0:
1746 * When a link becomes enabled for a non-AP STA that is affiliated with a non-AP MLD
1747 * after successful association with an AP MLD with (Re)Association Request/Response
1748 * frames transmitted on another link [...], the power management mode of the non-AP
1749 * STA, immediately after the acknowledgement of the (Re)Association Response frame
1750 * [...], is power save mode, and its power state is doze.
1751 *
1752 * Thus, STAs operating on all the links but the link used to establish association
1753 * transition to power save mode.
1754 */
1755 for (uint8_t i = 0; i < GetNLinks(); i++)
1756 {
1757 auto stationManager = GetWifiRemoteStationManager(i);
1758 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1759 staAddress.has_value() && i != *linkId &&
1760 stationManager->IsWaitAssocTxOk(*staAddress))
1761 {
1763 << " associated with STA=" << *staAddress);
1764 stationManager->RecordGotAssocTxOk(*staAddress);
1765 m_assocLogger(aid, *staAddress);
1766 StaSwitchingToPsMode(*staAddress, i);
1767 }
1768 }
1769
1770 // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
1772 }
1773
1774 if (auto extendedCapabilities =
1775 GetWifiRemoteStationManager(*linkId)->GetStationExtendedCapabilities(
1776 hdr.GetAddr1());
1778 {
1779 const auto isGcrCapable =
1780 extendedCapabilities && extendedCapabilities->m_robustAvStreaming;
1781 m_gcrManager->NotifyStaAssociated(hdr.GetAddr1(), isGcrCapable);
1782 }
1783 }
1784 else if (hdr.IsAction())
1785 {
1786 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
1787 category == WifiActionHeader::PROTECTED_EHT &&
1788 action.protectedEhtAction ==
1790 {
1791 // the EMLSR client acknowledged the EML Operating Mode Notification frame;
1792 // we can stop the timer and enforce the configuration deriving from the
1793 // EML Notification frame sent by the EMLSR client
1794 if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
1795 eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsPending())
1796 {
1797 // no need to wait until the expiration of the transition timeout
1798 eventIt->second.PeekEventImpl()->Invoke();
1799 eventIt->second.Cancel();
1800 }
1801 }
1802 }
1803}
1804
1805void
1807{
1808 NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
1809 const WifiMacHeader& hdr = mpdu->GetHeader();
1810
1811 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1812 {
1813 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1814 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1815
1816 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1817 {
1818 NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
1819 << " association failed with STA=" << hdr.GetAddr1());
1820 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxFailed(hdr.GetAddr1());
1821 }
1822
1823 if (auto staMldAddress =
1824 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1825 staMldAddress.has_value())
1826 {
1827 // the STA is affiliated with an MLD
1828 for (uint8_t i = 0; i < GetNLinks(); i++)
1829 {
1830 auto stationManager = GetWifiRemoteStationManager(i);
1831 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1832 staAddress.has_value() && i != *linkId &&
1833 stationManager->IsWaitAssocTxOk(*staAddress))
1834 {
1836 << " association failed with STA=" << *staAddress);
1837 stationManager->RecordGotAssocTxFailed(*staAddress);
1838 }
1839 }
1840 }
1841
1842 // free the assigned AID
1843 MgtAssocResponseHeader assocResp;
1844 mpdu->GetPacket()->PeekHeader(assocResp);
1845 auto aid = assocResp.GetAssociationId();
1846 m_aidToMldOrLinkAddress.erase(aid);
1847 for (const auto& [id, lnk] : GetLinks())
1848 {
1849 auto& link = GetLink(id);
1850 link.staList.erase(aid);
1851 }
1852 }
1853}
1854
1855void
1857{
1858 NS_LOG_FUNCTION(this << *mpdu << linkId);
1859
1860 Mac48Address staAddr = mpdu->GetHeader().GetAddr2();
1861 bool staInPsMode = GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr);
1862
1863 if (!staInPsMode && mpdu->GetHeader().IsPowerManagement())
1864 {
1865 // the sending STA is switching to Power Save mode
1866 StaSwitchingToPsMode(staAddr, linkId);
1867 }
1868 else if (staInPsMode && !mpdu->GetHeader().IsPowerManagement())
1869 {
1870 // the sending STA is switching back to Active mode
1872 }
1873}
1874
1875void
1876ApWifiMac::StaSwitchingToPsMode(const Mac48Address& staAddr, uint8_t linkId)
1877{
1878 NS_LOG_FUNCTION(this << staAddr << linkId);
1879
1880 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, true);
1881
1882 // Block frames addressed to the STA in PS mode
1883 NS_LOG_DEBUG("Block destination " << staAddr << " on link " << +linkId);
1884 auto staMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1886}
1887
1888void
1890{
1891 NS_LOG_FUNCTION(this << staAddr << linkId);
1892
1893 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, false);
1894
1895 if (GetWifiRemoteStationManager(linkId)->IsAssociated(staAddr))
1896 {
1897 // the station is still associated, unblock its frames
1898 NS_LOG_DEBUG("Unblock destination " << staAddr << " on link " << +linkId);
1899 auto staMldAddr =
1900 GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1902 }
1903}
1904
1905std::optional<uint8_t>
1907{
1908 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
1909 {
1910 if (GetWifiRemoteStationManager(linkId)->IsAssociated(address))
1911 {
1912 return linkId;
1913 }
1914 }
1915 NS_LOG_DEBUG(address << " is not associated");
1916 return std::nullopt;
1917}
1918
1921{
1922 auto linkId = IsAssociated(remoteAddr);
1923 NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
1924 return GetFrameExchangeManager(*linkId)->GetAddress();
1925}
1926
1927std::optional<Mac48Address>
1929{
1930 if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
1931 staIt != m_aidToMldOrLinkAddress.cend())
1932 {
1933 return staIt->second;
1934 }
1935 return std::nullopt;
1936}
1937
1938void
1940{
1941 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1942 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1943 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1944 Ptr<const Packet> packet = mpdu->GetPacket();
1945 Mac48Address from = hdr->GetAddr2();
1946 if (hdr->IsData())
1947 {
1948 std::optional<uint8_t> apLinkId;
1949 if (!hdr->IsFromDs() && hdr->IsToDs() &&
1950 (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
1951 mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
1952 {
1953 // this MPDU is being acknowledged by the AP, so we can process
1954 // the Power Management flag
1955 ProcessPowerManagementFlag(mpdu, *apLinkId);
1956
1957 Mac48Address to = hdr->GetAddr3();
1958 // Address3 can be our MLD address (e.g., this is an MPDU containing a single MSDU
1959 // addressed to us) or a BSSID (e.g., this is an MPDU containing an A-MSDU)
1960 if (to == GetAddress() ||
1961 (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
1962 {
1963 NS_LOG_DEBUG("frame for me from=" << from);
1964 if (hdr->IsQosData())
1965 {
1966 if (hdr->IsQosAmsdu())
1967 {
1968 NS_LOG_DEBUG("Received A-MSDU from=" << from
1969 << ", size=" << packet->GetSize());
1971 packet = nullptr;
1972 }
1973 else if (hdr->HasData())
1974 {
1975 ForwardUp(packet, from, GetAddress());
1976 }
1977 }
1978 else if (hdr->HasData())
1979 {
1980 ForwardUp(packet, from, GetAddress());
1981 }
1982 }
1983 else if (to.IsGroup() || IsAssociated(to))
1984 {
1985 NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
1986 Ptr<Packet> copy = packet->Copy();
1987
1988 // If the frame we are forwarding is of type QoS Data,
1989 // then we need to preserve the UP in the QoS control
1990 // header...
1991 if (hdr->IsQosData())
1992 {
1993 WifiMac::Enqueue(copy, to, from, hdr->GetQosTid());
1994 }
1995 else
1996 {
1997 WifiMac::Enqueue(copy, to, from);
1998 }
1999 ForwardUp(packet, from, to);
2000 }
2001 else if (hdr->HasData())
2002 {
2003 ForwardUp(packet, from, to);
2004 }
2005 }
2006 // NOLINTBEGIN(bugprone-branch-clone)
2007 else if (hdr->IsFromDs() && hdr->IsToDs())
2008 {
2009 // this is an AP-to-AP frame
2010 // we ignore for now.
2011 NotifyRxDrop(packet);
2012 }
2013 // NOLINTEND(bugprone-branch-clone)
2014 else
2015 {
2016 // we can ignore these frames since
2017 // they are not targeted at the AP
2018 NotifyRxDrop(packet);
2019 }
2020 return;
2021 }
2022 else if (hdr->IsMgt())
2023 {
2024 if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress() &&
2026 {
2027 // this MPDU is being acknowledged by the AP, so we can process
2028 // the Power Management flag
2029 ProcessPowerManagementFlag(mpdu, linkId);
2030 }
2031 if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
2032 hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
2033 {
2034 // In the case where the Address 1 field contains a group address, the
2035 // Address 3 field also is validated to verify that the group addressed
2036 // frame originated from a STA in the BSS of which the receiving STA is
2037 // a member (Section 9.3.3.1 of 802.11-2020)
2038 if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
2039 hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
2040 {
2041 // not addressed to us
2042 return;
2043 }
2044 MgtProbeRequestHeader probeRequestHeader;
2045 packet->PeekHeader(probeRequestHeader);
2046 const auto& ssid = probeRequestHeader.Get<Ssid>();
2047 if (ssid == GetSsid() || ssid->IsBroadcast())
2048 {
2049 NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
2050 const auto isReqBcast = hdr->GetAddr1().IsGroup() && hdr->GetAddr3().IsBroadcast();
2051 // not an ML Probe Request if ADDR1 and ADDR3 are broadcast
2052 const auto probeResp = GetProbeResp(
2053 linkId,
2054 isReqBcast ? std::nullopt : probeRequestHeader.Get<MultiLinkElement>());
2055 EnqueueProbeResp(probeResp, from, linkId);
2056 }
2057 return;
2058 }
2059 else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
2060 {
2061 switch (hdr->GetType())
2062 {
2065 NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
2066 << " request received from " << from
2067 << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
2068
2069 MgtAssocRequestHeader assocReq;
2070 MgtReassocRequestHeader reassocReq;
2071 AssocReqRefVariant frame = assocReq;
2072 if (hdr->IsAssocReq())
2073 {
2074 packet->PeekHeader(assocReq);
2075 }
2076 else
2077 {
2078 packet->PeekHeader(reassocReq);
2079 frame = reassocReq;
2080 }
2081 if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
2082 {
2083 ParseReportedStaInfo(frame, from, linkId);
2084 }
2085 SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
2086 return;
2087 }
2089 NS_LOG_DEBUG("Disassociation received from " << from);
2090 GetWifiRemoteStationManager(linkId)->RecordDisassociated(from);
2091 auto& staList = GetLink(linkId).staList;
2092 for (auto it = staList.begin(); it != staList.end(); ++it)
2093 {
2094 if (it->second == from)
2095 {
2096 staList.erase(it);
2097 m_deAssocLogger(it->first, it->second);
2098 if (GetWifiRemoteStationManager(linkId)->GetDsssSupported(from) &&
2099 !GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(from))
2100 {
2101 GetLink(linkId).numNonErpStations--;
2102 }
2103 if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from) &&
2104 !GetWifiRemoteStationManager(linkId)->GetStationHe6GhzCapabilities(
2105 from))
2106 {
2107 GetLink(linkId).numNonHtStations--;
2108 }
2112 if (m_gcrManager)
2113 {
2114 m_gcrManager->NotifyStaDeassociated(from);
2115 }
2116 break;
2117 }
2118 }
2119 return;
2120 }
2121 case WIFI_MAC_MGT_ACTION: {
2122 auto pkt = mpdu->GetPacket()->Copy();
2123 auto [category, action] = WifiActionHeader::Remove(pkt);
2124 if (category == WifiActionHeader::PROTECTED_EHT &&
2125 action.protectedEhtAction ==
2127 IsAssociated(hdr->GetAddr2()))
2128 {
2129 // received an EML Operating Mode Notification frame from an associated station
2130 MgtEmlOmn frame;
2131 pkt->RemoveHeader(frame);
2132 ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
2133 return;
2134 }
2135 break;
2136 }
2137 default:;
2138 // do nothing
2139 }
2140 }
2141 }
2142
2143 // Invoke the receive handler of our parent class to deal with any other frames
2144 WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
2145}
2146
2147bool
2149 const Mac48Address& from,
2150 uint8_t linkId)
2151{
2152 NS_LOG_FUNCTION(this << from << +linkId);
2153
2154 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
2155
2156 auto failure = [&](const std::string& msg) -> bool {
2157 NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
2158 remoteStationManager->RecordAssocRefused(from);
2159 return false;
2160 };
2161
2162 // lambda to process received (Re)Association Request
2163 auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
2164 const auto& frame = frameRefWrapper.get();
2165
2166 // first, verify that the the station's supported
2167 // rate set is compatible with our Basic Rate set
2168 const CapabilityInformation& capabilities = frame.Capabilities();
2169 remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
2170 NS_ASSERT(frame.template Get<SupportedRates>());
2171 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
2172 frame.template Get<ExtendedSupportedRatesIE>()};
2173
2174 if (rates.GetNRates() == 0)
2175 {
2176 return failure("STA's supported rate set not compatible with our Basic Rate set");
2177 }
2178
2179 if (GetHtSupported(linkId))
2180 {
2181 // check whether the HT STA supports all MCSs in Basic MCS Set
2182 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2183 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
2184 {
2185 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2186 {
2187 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2188 if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
2189 {
2190 return failure("HT STA does not support all MCSs in Basic MCS Set");
2191 }
2192 }
2193 }
2194 }
2195 if (GetVhtSupported(linkId))
2196 {
2197 // check whether the VHT STA supports all MCSs in Basic MCS Set
2198 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2199 if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
2200 {
2201 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2202 {
2203 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2204 if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2205 {
2206 return failure("VHT STA does not support all MCSs in Basic MCS Set");
2207 }
2208 }
2209 }
2210 }
2211 if (GetHeSupported())
2212 {
2213 // check whether the HE STA supports all MCSs in Basic MCS Set
2214 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2215 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2216 {
2217 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2218 {
2219 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2220 if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2221 {
2222 return failure("HE STA does not support all MCSs in Basic MCS Set");
2223 }
2224 }
2225 }
2226 if (Is6GhzBand(linkId))
2227 {
2228 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
2229 {
2230 remoteStationManager->AddStationHe6GhzCapabilities(from, *he6GhzCapabilities);
2231 }
2232 }
2233 }
2234 if (GetEhtSupported())
2235 {
2236 // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
2237 auto ehtConfig = GetEhtConfiguration();
2238 NS_ASSERT(ehtConfig);
2239
2240 if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
2241 !tidLinkMapping.empty())
2242 {
2243 // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
2244 // We refuse association if we do not support TID-to-Link mapping negotiation
2245 // or the non-AP MLD included more than two TID-to-Link Mapping IEs
2246 // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
2247 // or there is some TID that is not mapped to any link
2248 // or the direction(s) is/are not set properly
2249 if (tidLinkMapping.size() > 2)
2250 {
2251 return failure("More than two TID-to-Link Mapping IEs");
2252 }
2253
2254 // if only one Tid-to-Link Mapping element is present, it must be valid for
2255 // both directions
2256 bool bothDirIfOneTlm =
2257 tidLinkMapping.size() != 1 ||
2258 tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
2259 // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
2260 // Request frame or a (Re)Association Response frame shall set the Direction
2261 // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
2262 // subfield in the other TID-To- Link Mapping element to 1.
2263 // (Sec. 35.3.7.1.8 of 802.11be D3.1)
2264 bool distinctDirsIfTwoTlms =
2265 tidLinkMapping.size() != 2 ||
2266 (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2267 tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2268 tidLinkMapping[0].m_control.direction !=
2269 tidLinkMapping[1].m_control.direction);
2270
2271 if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
2272 {
2273 return failure("Incorrect directions in TID-to-Link Mapping IEs");
2274 }
2275
2276 if (ehtConfig->m_tidLinkMappingSupport ==
2278 {
2279 return failure("TID-to-Link Mapping negotiation not supported");
2280 }
2281
2282 auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
2283 if (tlmIe.m_control.defaultMapping)
2284 {
2285 return;
2286 }
2287 for (uint8_t tid = 0; tid < 8; tid++)
2288 {
2289 if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
2290 {
2291 mapping.emplace(tid, std::move(linkSet));
2292 }
2293 }
2294 };
2295
2296 WifiTidLinkMapping dlMapping;
2297 WifiTidLinkMapping ulMapping;
2298
2299 switch (tidLinkMapping[0].m_control.direction)
2300 {
2302 getMapping(tidLinkMapping.at(0), dlMapping);
2303 ulMapping = dlMapping;
2304 break;
2306 getMapping(tidLinkMapping.at(0), dlMapping);
2307 getMapping(tidLinkMapping.at(1), ulMapping);
2308 break;
2310 getMapping(tidLinkMapping.at(0), ulMapping);
2311 getMapping(tidLinkMapping.at(1), dlMapping);
2312 break;
2313 }
2314
2315 if (ehtConfig->m_tidLinkMappingSupport ==
2317 !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
2318 {
2319 return failure("Mapping TIDs to distinct link sets is incompatible with "
2320 "negotiation support of 1");
2321 }
2322
2323 // otherwise, we accept the TID-to-link Mapping and store it
2324 const auto& mle = frame.template Get<MultiLinkElement>();
2325 NS_ASSERT_MSG(mle,
2326 "Multi-Link Element not present in an Association Request including "
2327 "TID-to-Link Mapping element(s)");
2328 auto mldAddr = mle->GetMldMacAddress();
2329
2330 // The requested link mappings are valid and can be accepted; store them.
2332 UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
2333 }
2334 }
2335
2336 // The association request from the station can be accepted.
2337 // Record all its supported modes in its associated WifiRemoteStation
2338 auto phy = GetWifiPhy(linkId);
2339
2340 for (const auto& mode : phy->GetModeList())
2341 {
2342 if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
2343 {
2344 remoteStationManager->AddSupportedMode(from, mode);
2345 }
2346 }
2347 if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
2348 capabilities.IsShortSlotTime())
2349 {
2350 remoteStationManager->AddSupportedErpSlotTime(from, true);
2351 }
2352 if (GetHtSupported(linkId))
2353 {
2354 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2355 if (htCapabilities.has_value())
2356 {
2357 remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
2358 }
2359 const auto& extendedCapabilities = frame.template Get<ExtendedCapabilities>();
2360 if (extendedCapabilities.has_value())
2361 {
2362 remoteStationManager->AddStationExtendedCapabilities(from, *extendedCapabilities);
2363 }
2364 }
2365 if (GetVhtSupported(linkId))
2366 {
2367 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2368 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
2369 // to check whether it supports VHT
2370 if (vhtCapabilities.has_value() &&
2371 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
2372 {
2373 remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
2374 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
2375 {
2376 if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2377 {
2378 remoteStationManager->AddSupportedMcs(from, mcs);
2379 // here should add a control to add basic MCS when it is implemented
2380 }
2381 }
2382 }
2383 }
2384 if (GetHeSupported())
2385 {
2386 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2387 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2388 {
2389 remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
2390 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
2391 {
2392 if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2393 {
2394 remoteStationManager->AddSupportedMcs(from, mcs);
2395 // here should add a control to add basic MCS when it is implemented
2396 }
2397 }
2398 }
2399 }
2400 if (GetEhtSupported())
2401 {
2402 if (const auto& ehtCapabilities = frame.template Get<EhtCapabilities>())
2403 {
2404 remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
2405 }
2406 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
2407 {
2408 // TODO: Add check whether MCS is supported from the capabilities
2409 remoteStationManager->AddSupportedMcs(from, mcs);
2410 // here should add a control to add basic MCS when it is implemented
2411 }
2412 }
2413
2414 NS_LOG_DEBUG("Association Request from " << from << " accepted");
2415 remoteStationManager->RecordWaitAssocTxOk(from);
2416 return true;
2417 };
2418
2419 return std::visit(recvAssocRequest, assoc);
2420}
2421
2422void
2424{
2425 NS_LOG_FUNCTION(this << from << +linkId);
2426
2427 // lambda to process received Multi-Link Element
2428 auto recvMle = [&](auto&& frame) {
2429 const auto& mle = frame.get().template Get<MultiLinkElement>();
2430
2431 if (!mle.has_value())
2432 {
2433 return;
2434 }
2435
2436 auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
2437 GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
2438
2439 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
2440 {
2441 auto& perStaProfile = mle->GetPerStaProfile(i);
2442 if (!perStaProfile.HasStaMacAddress())
2443 {
2444 NS_LOG_DEBUG("[i=" << i
2445 << "] Cannot setup a link if the STA MAC address is missing");
2446 continue;
2447 }
2448 uint8_t newLinkId = perStaProfile.GetLinkId();
2449 if (newLinkId == linkId || newLinkId >= GetNLinks())
2450 {
2451 NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
2452 continue;
2453 }
2454 if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
2455 {
2456 NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
2457 continue;
2458 }
2459
2460 ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
2461 perStaProfile.GetStaMacAddress(),
2462 newLinkId);
2463 GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
2464 perStaProfile.GetStaMacAddress(),
2465 mleCommonInfo);
2466 }
2467 };
2468
2469 std::visit(recvMle, assoc);
2470}
2471
2472void
2473ApWifiMac::ReceiveEmlOmn(MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
2474{
2475 NS_LOG_FUNCTION(this << frame << sender << linkId);
2476
2477 auto ehtConfiguration = GetEhtConfiguration();
2478
2479 if (!ehtConfiguration || !ehtConfiguration->m_emlsrActivated)
2480 {
2482 "Received an EML Operating Mode Notification frame but EMLSR is not activated");
2483 return;
2484 }
2485
2487 {
2489 auto emlCapabilities =
2490 GetWifiRemoteStationManager(linkId)->GetStationEmlCapabilities(sender);
2491 NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
2492
2493 // update values stored in remote station manager
2494 emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
2495 emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
2496 }
2497
2498 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
2499 NS_ASSERT_MSG(mldAddress, "No MLD address stored for STA " << sender);
2500 auto emlsrLinks =
2501 frame.m_emlControl.emlsrMode == 1 ? frame.GetLinkBitmap() : std::list<uint8_t>{};
2502
2503 // The AP MLD has to consider the changes carried by the received EML Notification frame
2504 // as effective at the same time as the non-AP MLD. Therefore, we need to start a time
2505 // when the transmission of the Ack following the received EML Notification frame is
2506 // completed. For this purpose, we connect a callback to the PHY TX begin trace to catch
2507 // the Ack transmitted after the EML Notification frame.
2509 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
2510 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
2511 psduMap.begin()->second->GetHeader(0).IsAck(),
2512 "Expected a Normal Ack after EML Notification frame");
2513
2514 auto ackDuration =
2515 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
2516
2518 ackDuration + ehtConfiguration->m_transitionTimeout,
2519 [=, this]() {
2520 for (uint8_t id = 0; id < GetNLinks(); id++)
2521 {
2522 auto linkAddress =
2523 GetWifiRemoteStationManager(id)->GetAffiliatedStaAddress(*mldAddress);
2524 if (!linkAddress)
2525 {
2526 // this link has not been setup by the non-AP MLD
2527 continue;
2528 }
2529
2530 if (!emlsrLinks.empty())
2531 {
2532 // the non-AP MLD is enabling EMLSR mode
2533 /**
2534 * After the successful transmission of the EML Operating Mode
2535 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
2536 * the non-AP MLD shall operate in the EMLSR mode and the other non-AP
2537 * STAs operating on the corresponding EMLSR links shall transition to
2538 * active mode after the transition delay indicated in the Transition
2539 * Timeout subfield in the EML Capabilities subfield of the Basic
2540 * Multi-Link element or immediately after receiving an EML Operating
2541 * Mode Notification frame from one of the APs operating on the EMLSR
2542 * links and affiliated with the AP MLD (Sec. 35.3.17 of 802.11be D3.0)
2543 */
2544 auto enabled = std::find(emlsrLinks.cbegin(), emlsrLinks.cend(), id) !=
2545 emlsrLinks.cend();
2546 if (enabled)
2547 {
2548 StaSwitchingToActiveModeOrDeassociated(*linkAddress, id);
2549 }
2550 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, enabled);
2551 }
2552 else
2553 {
2554 // the non-AP MLD is disabling EMLSR mode
2555 /**
2556 * After the successful transmission of the EML Operating Mode
2557 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
2558 * the non-AP MLD shall disable the EMLSR mode and the other non-AP
2559 * STAs operating on the corresponding EMLSR links shall transition to
2560 * power save mode after the transition delay indicated in the
2561 * Transition Timeout subfield in the EML Capabilities subfield of the
2562 * Basic Multi-Link element or immediately after receiving an EML
2563 * Operating Mode Notification frame from one of the APs operating on
2564 * the EMLSR links and affiliated with the AP MLD. (Sec. 35.3.17 of
2565 * 802.11be D3.0)
2566 */
2567 if (id != linkId &&
2568 GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*linkAddress))
2569 {
2570 StaSwitchingToPsMode(*linkAddress, id);
2571 }
2572 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, false);
2573 }
2574 }
2575 });
2576 });
2577
2578 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
2579 // after its transmission begins
2580 auto phy = GetLink(linkId).phy;
2581 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
2582 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
2583 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
2584
2585 // An AP MLD with dot11EHTEMLSROptionActivated equal to true sets the EMLSR Mode subfield
2586 // to the value obtained from the EMLSR Mode subfield of the received EML Operating Mode
2587 // Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2588
2589 // When included in a frame sent by an AP affiliated with an AP MLD, the EMLSR Parameter
2590 // Update Control subfield is set to 0. (Sec. 9.6.35.8 of 802.11be D3.0)
2591 frame.m_emlControl.emlsrParamUpdateCtrl = 0;
2592
2593 // An AP MLD with dot11EHTEMLSROptionImplemented equal to true sets the EMLSR Link Bitmap
2594 // subfield to the value obtained from the EMLSR Link Bitmap subfield of the received
2595 // EML Operating Mode Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2596
2597 // The EMLSR Parameter Update field [..] is present if [..] the Action frame is sent by
2598 // a non-AP STA affiliated with a non-AP MLD (Sec. 9.6.35.8 of 802.11be D3.0)
2599 frame.m_emlsrParamUpdate.reset();
2600
2601 auto ehtFem = StaticCast<EhtFrameExchangeManager>(GetFrameExchangeManager(linkId));
2602 ehtFem->SendEmlOmn(sender, frame);
2603}
2604
2605void
2607{
2608 NS_LOG_FUNCTION(this << *mpdu);
2609 for (auto& i : *PeekPointer(mpdu))
2610 {
2611 auto from = i.second.GetSourceAddr();
2612 auto to = i.second.GetDestinationAddr();
2613
2614 if (to.IsGroup() || IsAssociated(to))
2615 {
2616 NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
2617 WifiMac::Enqueue(i.first->Copy(), to, from, mpdu->GetHeader().GetQosTid());
2618 }
2619
2620 ForwardUp(i.first, from, to);
2621 }
2622}
2623
2624void
2626{
2627 NS_LOG_FUNCTION(this);
2629
2630 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
2631 {
2632 GetLink(linkId).beaconEvent.Cancel();
2634 {
2635 uint64_t jitterUs =
2637 ? static_cast<uint64_t>(m_beaconJitter->GetValue(0, 1) *
2639 : 0);
2640 NS_LOG_DEBUG("Scheduling initial beacon for access point "
2641 << GetAddress() << " at time " << jitterUs << "us");
2644 this,
2645 linkId);
2646 }
2649 }
2650
2651 if (m_gcrManager)
2652 {
2653 m_gcrManager->Initialize();
2654 }
2655
2660}
2661
2662bool
2664{
2665 bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
2666 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
2667 return useProtection;
2668}
2669
2670uint16_t
2672{
2673 const auto& links = GetLinks();
2674
2675 // Return the first AID value between 1 and 2007 that is free for all the links
2676 for (uint16_t nextAid = 1; nextAid <= 2007; ++nextAid)
2677 {
2678 if (std::none_of(links.cbegin(), links.cend(), [&](auto&& idLinkPair) {
2679 return GetStaList(idLinkPair.first).contains(nextAid);
2680 }))
2681 {
2682 return nextAid;
2683 }
2684 }
2685 NS_FATAL_ERROR("No free association ID available!");
2686 return 0;
2687}
2688
2689const std::map<uint16_t, Mac48Address>&
2690ApWifiMac::GetStaList(uint8_t linkId) const
2691{
2692 return GetLink(linkId).staList;
2693}
2694
2695uint16_t
2697{
2698 return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
2699}
2700
2701uint8_t
2702ApWifiMac::GetBufferStatus(uint8_t tid, Mac48Address address) const
2703{
2704 auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
2705 if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
2706 {
2707 return 255;
2708 }
2709 return it->second.value;
2710}
2711
2712void
2713ApWifiMac::SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
2714{
2715 if (size == 255)
2716 {
2717 // no point in storing an unspecified size
2718 m_bufferStatus.erase(WifiAddressTidPair(address, tid));
2719 }
2720 else
2721 {
2722 m_bufferStatus[WifiAddressTidPair(address, tid)] = {size, Simulator::Now()};
2723 }
2724}
2725
2726uint8_t
2728{
2729 uint8_t maxSize = 0;
2730 bool found = false;
2731
2732 for (uint8_t tid = 0; tid < 8; tid++)
2733 {
2734 uint8_t size = GetBufferStatus(tid, address);
2735 if (size != 255)
2736 {
2737 maxSize = std::max(maxSize, size);
2738 found = true;
2739 }
2740 }
2741
2742 if (found)
2743 {
2744 return maxSize;
2745 }
2746 return 255;
2747}
2748
2749bool
2751 uint8_t tid) const
2752{
2754 return GetQosTxop(tid)->GetBaManager()->IsGcrAgreementEstablished(
2755 groupAddress,
2756 tid,
2757 m_gcrManager->GetMemberStasForGroupAddress(groupAddress));
2758}
2759
2760} // 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.
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
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 IsQosData() is true and the A-MSDU present bit is set in the QoS control field.
Mac48Address GetAddr3() const
Return the address in the Address 3 field.
bool IsAssocResp() const
Return true if the header is an Association Response header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
bool IsMgt() const
Return true if the Type is Management.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsAction() const
Return true if the header is an Action header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
bool IsReassocReq() const
Return true if the header is a Reassociation Request header.
bool IsData() const
Return true if the Type is DATA.
bool IsReassocResp() const
Return true if the header is a Reassociation Response header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
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:2082
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< 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
#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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
const Time WIFI_TU
Wi-Fi Time Unit (see IEEE 802.11-2020 sec. 3.1)
Definition wifi-utils.cc:24
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1432
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
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
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
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1452
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