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