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 const auto phy = GetWifiPhy(linkId);
1152
1153 auto maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
1154 for (const auto& sta : GetLink(linkId).staList)
1155 {
1156 if (remoteStationManager->GetEhtSupported(sta.second))
1157 {
1158 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
1159 {
1160 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
1161 }
1162 }
1163 }
1164 operation.SetMaxRxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1165 operation.SetMaxTxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
1167
1168 if (const auto bw = phy->GetChannelWidth();
1169 (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) && (bw == MHz_u{320}))
1170 {
1171 operation.m_opInfo.emplace(EhtOperation::EhtOpInfo{{.channelWidth = 4}});
1172 operation.m_params.opInfoPresent = 1;
1173 }
1174 return operation;
1175}
1176
1177void
1179 Mac48Address to,
1180 uint8_t linkId)
1181{
1182 NS_LOG_FUNCTION(this << to << +linkId);
1184 hdr.SetAddr1(to);
1185 hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
1186 hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
1187 hdr.SetDsNotFrom();
1188 hdr.SetDsNotTo();
1189 Ptr<Packet> packet = Create<Packet>();
1190 packet->AddHeader(probeResp);
1191
1192 if (!GetQosSupported())
1193 {
1194 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1195 }
1196 // "A QoS STA that transmits a Management frame determines access category used
1197 // for medium access in transmission of the Management frame as follows
1198 // (If dot11QMFActivated is false or not present)
1199 // — If the Management frame is individually addressed to a non-QoS STA, category
1200 // AC_BE should be selected.
1201 // — If category AC_BE was not selected by the previous step, category AC_VO
1202 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1203 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1204 {
1205 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1206 }
1207 else
1208 {
1209 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1210 }
1211}
1212
1215{
1217 probe.Get<Ssid>() = GetSsid();
1218 auto supportedRates = GetSupportedRates(linkId);
1219 probe.Get<SupportedRates>() = supportedRates.rates;
1220 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1221 probe.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
1222 probe.Capabilities() = GetCapabilities(linkId);
1223 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(
1224 GetLink(linkId).shortPreambleEnabled);
1225 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1226 GetLink(linkId).shortSlotTimeEnabled);
1227 if (GetDsssSupported(linkId))
1228 {
1229 probe.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1230 }
1231 if (GetErpSupported(linkId))
1232 {
1233 probe.Get<ErpInformation>() = GetErpInformation(linkId);
1234 }
1235 if (GetQosSupported())
1236 {
1237 probe.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1238 }
1239 if (GetHtSupported(linkId))
1240 {
1242 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1243 probe.Get<HtOperation>() = GetHtOperation(linkId);
1244 }
1245 if (GetVhtSupported(linkId))
1246 {
1247 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1248 probe.Get<VhtOperation>() = GetVhtOperation(linkId);
1249 }
1250 if (GetHeSupported())
1251 {
1252 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1253 probe.Get<HeOperation>() = GetHeOperation(linkId);
1254 if (auto muEdcaParameterSet = GetMuEdcaParameterSet())
1255 {
1256 probe.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1257 }
1258 if (Is6GhzBand(linkId))
1259 {
1261 }
1262 }
1263 if (GetEhtSupported())
1264 {
1265 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1266 probe.Get<EhtOperation>() = GetEhtOperation(linkId);
1267 }
1268
1269 return probe;
1270}
1271
1273ApWifiMac::GetProbeResp(uint8_t linkId, const std::optional<MultiLinkElement>& reqMle)
1274{
1275 NS_LOG_FUNCTION(this << linkId << reqMle.has_value());
1276 NS_ASSERT_MSG(linkId < GetNLinks(), "Invalid link ID = " << +linkId);
1277
1278 auto probeResp = GetProbeRespProfile(linkId);
1279
1280 if (GetNLinks() > 1)
1281 {
1282 /*
1283 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1284 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1285 * include a TBTT Information field in a Reduced Neighbor Report element with the
1286 * TBTT Information Length field set to 16 or higher, for each of the other APs
1287 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1288 */
1289 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1290 {
1291 probeResp.Get<ReducedNeighborReport>() = std::move(*rnr);
1292 }
1293 /*
1294 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1295 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1296 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1297 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1298 * channel switching, extended channel switching, and channel quieting) are
1299 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1300 */
1301 probeResp.Get<MultiLinkElement>() = GetMultiLinkElement(linkId,
1304 reqMle);
1305 }
1306 return probeResp;
1307}
1308
1311{
1313 StatusCode code;
1314 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1315 if (remoteStationManager->IsWaitAssocTxOk(to))
1316 {
1317 code.SetSuccess();
1318 }
1319 else
1320 {
1321 NS_ABORT_IF(!remoteStationManager->IsAssocRefused(to));
1322 // reset state
1323 remoteStationManager->RecordDisassociated(to);
1324 code.SetFailure();
1325 }
1326 auto supportedRates = GetSupportedRates(linkId);
1327 assoc.Get<SupportedRates>() = supportedRates.rates;
1328 assoc.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1329 assoc.SetStatusCode(code);
1330 assoc.Capabilities() = GetCapabilities(linkId);
1331 if (GetQosSupported())
1332 {
1333 assoc.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1334 }
1335 if (GetHtSupported(linkId))
1336 {
1338 assoc.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1339 assoc.Get<HtOperation>() = GetHtOperation(linkId);
1340 }
1341 if (GetVhtSupported(linkId))
1342 {
1343 assoc.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1344 assoc.Get<VhtOperation>() = GetVhtOperation(linkId);
1345 }
1346 if (GetHeSupported())
1347 {
1348 assoc.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1349 assoc.Get<HeOperation>() = GetHeOperation(linkId);
1350 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1351 {
1352 assoc.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1353 }
1354 if (Is6GhzBand(linkId))
1355 {
1357 }
1358 }
1359 if (GetEhtSupported())
1360 {
1361 assoc.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1362 assoc.Get<EhtOperation>() = GetEhtOperation(linkId);
1363 // The AP MLD that accepts the requested TID-to-link mapping shall not include in the
1364 // (Re)Association Response frame the TID-to-link Mapping element.
1365 // (Sec. 35.3.7.1.8 of 802.11be D3.1).
1366 // For now, we assume that AP MLDs always accept requested TID-to-link mappings.
1367 }
1368 return assoc;
1369}
1370
1373 const Mac48Address& to,
1374 uint8_t linkId)
1375{
1376 // find all the links to setup (i.e., those for which status code is success)
1377 std::map<uint8_t /* link ID */, Mac48Address> linkIdStaAddrMap;
1378
1379 if (assoc.GetStatusCode().IsSuccess())
1380 {
1381 linkIdStaAddrMap[linkId] = to;
1382 }
1383
1384 if (const auto& mle = assoc.Get<MultiLinkElement>())
1385 {
1386 const auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1387 NS_ABORT_MSG_IF(!staMldAddress.has_value(),
1388 "Sending a Multi-Link Element to a single link device");
1389 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1390 {
1391 auto& perStaProfile = mle->GetPerStaProfile(idx);
1392 if (perStaProfile.HasAssocResponse() &&
1393 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1394 {
1395 uint8_t otherLinkId = perStaProfile.GetLinkId();
1396 auto staAddress = GetWifiRemoteStationManager(otherLinkId)
1397 ->GetAffiliatedStaAddress(*staMldAddress);
1398 NS_ABORT_MSG_IF(!staAddress.has_value(),
1399 "No STA to associate with on link " << +otherLinkId);
1400 const auto [it, inserted] = linkIdStaAddrMap.insert({otherLinkId, *staAddress});
1401 NS_ABORT_MSG_IF(!inserted,
1402 "More than one Association Response to MLD "
1403 << *staMldAddress << " on link ID " << +otherLinkId);
1404 }
1405 }
1406 }
1407
1408 return linkIdStaAddrMap;
1409}
1410
1411void
1413{
1414 if (linkIdStaAddrMap.empty())
1415 {
1416 // no link to setup, nothing to do
1417 return;
1418 }
1419
1420 const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
1421 const auto addr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1422
1423 // check if an AID is already allocated to the device that is associating
1424 std::set<uint16_t> aids;
1425
1426 for (const auto& [id, link] : GetLinks())
1427 {
1428 if (const auto aid = link->stationManager->GetAssociationId(addr); aid != SU_STA_ID)
1429 {
1430 aids.insert(aid);
1431 }
1432 }
1433
1434 NS_ABORT_MSG_IF(aids.size() > 1, addr << " cannot have more than one AID assigned");
1435
1436 const auto aid = aids.empty() ? GetNextAssociationId() : *aids.cbegin();
1437
1438 // store the MLD or link address in the AID-to-address map
1439 const auto [it, inserted] = m_aidToMldOrLinkAddress.emplace(aid, addr);
1440
1441 NS_ABORT_MSG_IF(!inserted, "AID " << aid << " already present, cannot be assigned to " << addr);
1442
1443 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1444 {
1445 auto& link = GetLink(id);
1446
1447 if (const auto [it, inserted] = link.staList.emplace(aid, staAddr); inserted)
1448 {
1449 // the STA on this link had no AID assigned
1450 link.stationManager->SetAssociationId(staAddr, aid);
1451
1452 if (link.stationManager->GetDsssSupported(staAddr) &&
1453 !link.stationManager->GetErpOfdmSupported(staAddr))
1454 {
1455 link.numNonErpStations++;
1456 }
1457 if (!link.stationManager->GetHtSupported(staAddr) &&
1458 !link.stationManager->GetStationHe6GhzCapabilities(staAddr))
1459 {
1460 link.numNonHtStations++;
1461 }
1464 }
1465 else
1466 {
1467 // the STA on this link had an AID assigned
1468 NS_ABORT_MSG_IF(it->first != aid,
1469 "AID " << it->first << " already assigned to " << staAddr
1470 << ", could not assign " << aid);
1471 }
1472 }
1473
1474 // set the AID in all the Association Responses. NOTE that the Association
1475 // Responses included in the Per-STA Profile Subelements of the Multi-Link
1476 // Element must not contain the AID field. We set the AID field in such
1477 // Association Responses anyway, in order to ease future implementation of
1478 // the inheritance mechanism.
1479 if (assoc.GetStatusCode().IsSuccess())
1480 {
1481 assoc.SetAssociationId(aid);
1482 }
1483 if (const auto& mle = assoc.Get<MultiLinkElement>())
1484 {
1485 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1486 {
1487 if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1488 perStaProfile.HasAssocResponse() &&
1489 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1490 {
1491 perStaProfile.GetAssocResponse().SetAssociationId(aid);
1492 }
1493 }
1494 }
1495}
1496
1497void
1498ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1499{
1500 NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1501 WifiMacHeader hdr;
1504 hdr.SetAddr1(to);
1505 hdr.SetAddr2(GetFrameExchangeManager(linkId)->GetAddress());
1506 hdr.SetAddr3(GetFrameExchangeManager(linkId)->GetAddress());
1507 hdr.SetDsNotFrom();
1508 hdr.SetDsNotTo();
1509
1510 MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1511
1512 // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1513 // Request frame that carries a Basic Multi-Link element shall include a Basic
1514 // Multi-Link element in the (Re)Association Response frame that it transmits
1515 // (Sec. 35.3.5.4 of 802.11be D2.0)
1516 // If the STA included a Multi-Link Element in the (Re)Association Request, we
1517 // stored its MLD address in the remote station manager
1518 if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1519 {
1520 assoc.Get<MultiLinkElement>() = GetMultiLinkElement(linkId, hdr.GetType(), to);
1521 }
1522
1523 auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1524 SetAid(assoc, linkIdStaAddrMap);
1525
1526 Ptr<Packet> packet = Create<Packet>();
1527 packet->AddHeader(assoc);
1528
1529 if (!GetQosSupported())
1530 {
1531 GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
1532 }
1533 // "A QoS STA that transmits a Management frame determines access category used
1534 // for medium access in transmission of the Management frame as follows
1535 // (If dot11QMFActivated is false or not present)
1536 // — If the Management frame is individually addressed to a non-QoS STA, category
1537 // AC_BE should be selected.
1538 // — If category AC_BE was not selected by the previous step, category AC_VO
1539 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1540 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1541 {
1542 GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1543 }
1544 else
1545 {
1546 GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
1547 }
1548}
1549
1550void
1552{
1553 NS_LOG_FUNCTION(this << +linkId);
1554 auto& link = GetLink(linkId);
1555 WifiMacHeader hdr;
1558 hdr.SetAddr2(link.feManager->GetAddress());
1559 hdr.SetAddr3(link.feManager->GetAddress());
1560 hdr.SetDsNotFrom();
1561 hdr.SetDsNotTo();
1562 Ptr<Packet> packet = Create<Packet>();
1563 MgtBeaconHeader beacon;
1564 beacon.Get<Ssid>() = GetSsid();
1565 auto supportedRates = GetSupportedRates(linkId);
1566 beacon.Get<SupportedRates>() = supportedRates.rates;
1567 beacon.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1568 beacon.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
1569 beacon.Capabilities() = GetCapabilities(linkId);
1570 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1571 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1572 if (GetDsssSupported(linkId))
1573 {
1574 beacon.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1575 }
1576 if (GetErpSupported(linkId))
1577 {
1578 beacon.Get<ErpInformation>() = GetErpInformation(linkId);
1579 }
1580 if (GetQosSupported())
1581 {
1582 beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1583 }
1584 if (GetHtSupported(linkId))
1585 {
1587 beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1588 beacon.Get<HtOperation>() = GetHtOperation(linkId);
1589 }
1590 if (GetVhtSupported(linkId))
1591 {
1592 beacon.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1593 beacon.Get<VhtOperation>() = GetVhtOperation(linkId);
1594 }
1595 if (GetHeSupported())
1596 {
1597 beacon.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1598 beacon.Get<HeOperation>() = GetHeOperation(linkId);
1599 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1600 {
1601 beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1602 }
1603 if (Is6GhzBand(linkId))
1604 {
1605 beacon.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
1606 }
1607 }
1608 if (GetEhtSupported())
1609 {
1610 beacon.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1611 beacon.Get<EhtOperation>() = GetEhtOperation(linkId);
1612
1613 if (GetNLinks() > 1)
1614 {
1615 /*
1616 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1617 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1618 * include a TBTT Information field in a Reduced Neighbor Report element with the
1619 * TBTT Information Length field set to 16 or higher, for each of the other APs
1620 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1621 */
1622 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1623 {
1624 beacon.Get<ReducedNeighborReport>() = std::move(*rnr);
1625 }
1626 /*
1627 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1628 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1629 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1630 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1631 * channel switching, extended channel switching, and channel quieting) are
1632 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1633 */
1635 }
1636 }
1637 packet->AddHeader(beacon);
1638
1639 NS_LOG_INFO("Generating beacon from " << link.feManager->GetAddress() << " linkID " << +linkId);
1640 // The beacon has it's own special queue, so we load it in there
1641 m_beaconTxop->Queue(Create<WifiMpdu>(packet, hdr));
1642 link.beaconEvent =
1644
1646
1647 // If a STA that does not support Short Slot Time associates,
1648 // the AP shall use long slot time beginning at the first Beacon
1649 // subsequent to the association of the long slot time STA.
1650 if (GetErpSupported(linkId))
1651 {
1652 if (link.shortSlotTimeEnabled)
1653 {
1654 // Enable short slot time
1655 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1656 }
1657 else
1658 {
1659 // Disable short slot time
1660 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1661 }
1662 }
1663}
1664
1666ApWifiMac::GetFilsDiscovery(uint8_t linkId) const
1667{
1670 auto& link = GetLink(linkId);
1671 hdr.SetAddr2(link.feManager->GetAddress());
1672 hdr.SetAddr3(link.feManager->GetAddress());
1673 hdr.SetDsNotFrom();
1674 hdr.SetDsNotTo();
1675
1676 WifiActionHeader actionHdr;
1678 action.publicAction = WifiActionHeader::FILS_DISCOVERY;
1679 actionHdr.SetAction(WifiActionHeader::PUBLIC, action);
1680
1681 FilsDiscHeader fils;
1682 fils.SetSsid(GetSsid().PeekString());
1683 fils.m_beaconInt = (m_beaconInterval / WIFI_TU).GetHigh();
1684
1686 fils.m_fdCap->SetOpChannelWidth(link.phy->GetChannelWidth());
1687 fils.m_fdCap->SetMaxNss(std::min(link.phy->GetMaxSupportedTxSpatialStreams(),
1688 link.phy->GetMaxSupportedRxSpatialStreams()));
1689 fils.m_fdCap->SetStandard(link.phy->GetStandard());
1690
1691 fils.SetLengthSubfield();
1692 fils.m_rnr = GetReducedNeighborReport(linkId);
1693
1694 auto packet = Create<Packet>();
1695 packet->AddHeader(fils);
1696 packet->AddHeader(actionHdr);
1697
1698 return Create<WifiMpdu>(packet, hdr);
1699}
1700
1701void
1703{
1704 NS_LOG_FUNCTION(this << linkId);
1705 auto phy = GetLink(linkId).phy;
1706
1707 auto fdBeaconInterval = (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) ? m_fdBeaconInterval6GHz
1709
1710 if (!fdBeaconInterval.IsStrictlyPositive())
1711 {
1712 NS_LOG_DEBUG("Sending FILS Discovery/unsolicited Probe Response disabled");
1713 return;
1714 }
1715
1716 // Schedule FD or unsolicited Probe Response frames (IEEE Std 802.11ax-2021 26.17.2.3.2)
1717 for (uint8_t count = 1; count < (m_beaconInterval / fdBeaconInterval).GetHigh(); ++count)
1718 {
1720 {
1721 Simulator::Schedule(fdBeaconInterval * count,
1723 this,
1724 GetProbeResp(linkId, std::nullopt),
1726 linkId);
1727 }
1728 else
1729 {
1730 Simulator::Schedule(fdBeaconInterval * count,
1731 [=, this]() { m_beaconTxop->Queue(GetFilsDiscovery(linkId)); });
1732 }
1733 }
1734}
1735
1736void
1738{
1739 NS_LOG_FUNCTION(this << *mpdu);
1740 const WifiMacHeader& hdr = mpdu->GetHeader();
1741
1742 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1743 {
1744 MgtAssocResponseHeader assocResp;
1745 mpdu->GetPacket()->PeekHeader(assocResp);
1746 auto aid = assocResp.GetAssociationId();
1747
1748 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1749 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1750
1751 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1752 {
1753 NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
1754 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxOk(hdr.GetAddr1());
1755 m_assocLogger(aid, hdr.GetAddr1());
1756 }
1757
1758 if (auto staMldAddress =
1759 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1760 staMldAddress.has_value())
1761 {
1762 /**
1763 * The STA is affiliated with an MLD. From Sec. 35.3.7.1.4 of 802.11be D3.0:
1764 * When a link becomes enabled for a non-AP STA that is affiliated with a non-AP MLD
1765 * after successful association with an AP MLD with (Re)Association Request/Response
1766 * frames transmitted on another link [...], the power management mode of the non-AP
1767 * STA, immediately after the acknowledgement of the (Re)Association Response frame
1768 * [...], is power save mode, and its power state is doze.
1769 *
1770 * Thus, STAs operating on all the links but the link used to establish association
1771 * transition to power save mode.
1772 */
1773 for (uint8_t i = 0; i < GetNLinks(); i++)
1774 {
1775 auto stationManager = GetWifiRemoteStationManager(i);
1776 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1777 staAddress.has_value() && i != *linkId &&
1778 stationManager->IsWaitAssocTxOk(*staAddress))
1779 {
1781 << " associated with STA=" << *staAddress);
1782 stationManager->RecordGotAssocTxOk(*staAddress);
1783 m_assocLogger(aid, *staAddress);
1784 StaSwitchingToPsMode(*staAddress, i);
1785 }
1786 }
1787
1788 // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
1790 }
1791
1792 if (auto extendedCapabilities =
1793 GetWifiRemoteStationManager(*linkId)->GetStationExtendedCapabilities(
1794 hdr.GetAddr1());
1796 {
1797 const auto isGcrCapable =
1798 extendedCapabilities && extendedCapabilities->m_robustAvStreaming;
1799 m_gcrManager->NotifyStaAssociated(hdr.GetAddr1(), isGcrCapable);
1800 }
1801 }
1802 else if (hdr.IsAction())
1803 {
1804 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
1805 category == WifiActionHeader::PROTECTED_EHT &&
1806 action.protectedEhtAction ==
1808 {
1809 // the EMLSR client acknowledged the EML Operating Mode Notification frame;
1810 // we can stop the timer and enforce the configuration deriving from the
1811 // EML Notification frame sent by the EMLSR client
1812 if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
1813 eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsPending())
1814 {
1815 // no need to wait until the expiration of the transition timeout
1816 eventIt->second.PeekEventImpl()->Invoke();
1817 eventIt->second.Cancel();
1818 }
1819 }
1820 }
1821}
1822
1823void
1825{
1826 NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
1827 const WifiMacHeader& hdr = mpdu->GetHeader();
1828
1829 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1830 {
1831 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1832 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1833
1834 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1835 {
1836 NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
1837 << " association failed with STA=" << hdr.GetAddr1());
1838 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxFailed(hdr.GetAddr1());
1839 }
1840
1841 if (auto staMldAddress =
1842 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1843 staMldAddress.has_value())
1844 {
1845 // the STA is affiliated with an MLD
1846 for (uint8_t i = 0; i < GetNLinks(); i++)
1847 {
1848 auto stationManager = GetWifiRemoteStationManager(i);
1849 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1850 staAddress.has_value() && i != *linkId &&
1851 stationManager->IsWaitAssocTxOk(*staAddress))
1852 {
1854 << " association failed with STA=" << *staAddress);
1855 stationManager->RecordGotAssocTxFailed(*staAddress);
1856 }
1857 }
1858 }
1859
1860 // free the assigned AID
1861 MgtAssocResponseHeader assocResp;
1862 mpdu->GetPacket()->PeekHeader(assocResp);
1863 auto aid = assocResp.GetAssociationId();
1864 m_aidToMldOrLinkAddress.erase(aid);
1865 for (const auto& [id, lnk] : GetLinks())
1866 {
1867 auto& link = GetLink(id);
1868 link.staList.erase(aid);
1869 }
1870 }
1871}
1872
1873void
1875{
1876 NS_LOG_FUNCTION(this << *mpdu << linkId);
1877
1878 Mac48Address staAddr = mpdu->GetHeader().GetAddr2();
1879 bool staInPsMode = GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr);
1880
1881 if (!staInPsMode && mpdu->GetHeader().IsPowerManagement())
1882 {
1883 // the sending STA is switching to Power Save mode
1884 StaSwitchingToPsMode(staAddr, linkId);
1885 }
1886 else if (staInPsMode && !mpdu->GetHeader().IsPowerManagement())
1887 {
1888 // the sending STA is switching back to Active mode
1890 }
1891}
1892
1893void
1894ApWifiMac::StaSwitchingToPsMode(const Mac48Address& staAddr, uint8_t linkId)
1895{
1896 NS_LOG_FUNCTION(this << staAddr << linkId);
1897
1898 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, true);
1899
1900 // Block frames addressed to the STA in PS mode
1901 NS_LOG_DEBUG("Block destination " << staAddr << " on link " << +linkId);
1902 auto staMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1904}
1905
1906void
1908{
1909 NS_LOG_FUNCTION(this << staAddr << linkId);
1910
1911 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, false);
1912
1913 if (GetWifiRemoteStationManager(linkId)->IsAssociated(staAddr))
1914 {
1915 // the station is still associated, unblock its frames
1916 NS_LOG_DEBUG("Unblock destination " << staAddr << " on link " << +linkId);
1917 auto staMldAddr =
1918 GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1920 }
1921}
1922
1923std::optional<uint8_t>
1925{
1926 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
1927 {
1928 if (GetWifiRemoteStationManager(linkId)->IsAssociated(address))
1929 {
1930 return linkId;
1931 }
1932 }
1933 NS_LOG_DEBUG(address << " is not associated");
1934 return std::nullopt;
1935}
1936
1939{
1940 auto linkId = IsAssociated(remoteAddr);
1941 NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
1942 return GetFrameExchangeManager(*linkId)->GetAddress();
1943}
1944
1945std::optional<Mac48Address>
1947{
1948 if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
1949 staIt != m_aidToMldOrLinkAddress.cend())
1950 {
1951 return staIt->second;
1952 }
1953 return std::nullopt;
1954}
1955
1956void
1958{
1959 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1960 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1961 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1962 Ptr<const Packet> packet = mpdu->GetPacket();
1963 Mac48Address from = hdr->GetAddr2();
1964 if (hdr->IsData())
1965 {
1966 std::optional<uint8_t> apLinkId;
1967 if (!hdr->IsFromDs() && hdr->IsToDs() &&
1968 (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
1969 mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
1970 {
1971 // this MPDU is being acknowledged by the AP, so we can process
1972 // the Power Management flag
1973 ProcessPowerManagementFlag(mpdu, *apLinkId);
1974
1975 Mac48Address to = hdr->GetAddr3();
1976 // Address3 can be our MLD address (e.g., this is an MPDU containing a single MSDU
1977 // addressed to us) or a BSSID (e.g., this is an MPDU containing an A-MSDU)
1978 if (to == GetAddress() ||
1979 (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
1980 {
1981 NS_LOG_DEBUG("frame for me from=" << from);
1982 if (hdr->IsQosData())
1983 {
1984 if (hdr->IsQosAmsdu())
1985 {
1986 NS_LOG_DEBUG("Received A-MSDU from=" << from
1987 << ", size=" << packet->GetSize());
1989 packet = nullptr;
1990 }
1991 else if (hdr->HasData())
1992 {
1993 ForwardUp(packet, from, GetAddress());
1994 }
1995 }
1996 else if (hdr->HasData())
1997 {
1998 ForwardUp(packet, from, GetAddress());
1999 }
2000 }
2001 else if (to.IsGroup() || IsAssociated(to))
2002 {
2003 NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
2004 Ptr<Packet> copy = packet->Copy();
2005
2006 // If the frame we are forwarding is of type QoS Data,
2007 // then we need to preserve the UP in the QoS control
2008 // header...
2009 if (hdr->IsQosData())
2010 {
2011 WifiMac::Enqueue(copy, to, from, hdr->GetQosTid());
2012 }
2013 else
2014 {
2015 WifiMac::Enqueue(copy, to, from);
2016 }
2017 ForwardUp(packet, from, to);
2018 }
2019 else if (hdr->HasData())
2020 {
2021 ForwardUp(packet, from, to);
2022 }
2023 }
2024 // NOLINTBEGIN(bugprone-branch-clone)
2025 else if (hdr->IsFromDs() && hdr->IsToDs())
2026 {
2027 // this is an AP-to-AP frame
2028 // we ignore for now.
2029 NotifyRxDrop(packet);
2030 }
2031 // NOLINTEND(bugprone-branch-clone)
2032 else
2033 {
2034 // we can ignore these frames since
2035 // they are not targeted at the AP
2036 NotifyRxDrop(packet);
2037 }
2038 return;
2039 }
2040 else if (hdr->IsMgt())
2041 {
2042 if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress() &&
2044 {
2045 // this MPDU is being acknowledged by the AP, so we can process
2046 // the Power Management flag
2047 ProcessPowerManagementFlag(mpdu, linkId);
2048 }
2049 if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
2050 hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
2051 {
2052 // In the case where the Address 1 field contains a group address, the
2053 // Address 3 field also is validated to verify that the group addressed
2054 // frame originated from a STA in the BSS of which the receiving STA is
2055 // a member (Section 9.3.3.1 of 802.11-2020)
2056 if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
2057 hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
2058 {
2059 // not addressed to us
2060 return;
2061 }
2062 MgtProbeRequestHeader probeRequestHeader;
2063 packet->PeekHeader(probeRequestHeader);
2064 const auto& ssid = probeRequestHeader.Get<Ssid>();
2065 if (ssid == GetSsid() || ssid->IsBroadcast())
2066 {
2067 NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
2068 const auto isReqBcast = hdr->GetAddr1().IsGroup() && hdr->GetAddr3().IsBroadcast();
2069 // not an ML Probe Request if ADDR1 and ADDR3 are broadcast
2070 const auto probeResp = GetProbeResp(
2071 linkId,
2072 isReqBcast ? std::nullopt : probeRequestHeader.Get<MultiLinkElement>());
2073 EnqueueProbeResp(probeResp, from, linkId);
2074 }
2075 return;
2076 }
2077 else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
2078 {
2079 switch (hdr->GetType())
2080 {
2083 NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
2084 << " request received from " << from
2085 << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
2086
2087 MgtAssocRequestHeader assocReq;
2088 MgtReassocRequestHeader reassocReq;
2089 AssocReqRefVariant frame = assocReq;
2090 if (hdr->IsAssocReq())
2091 {
2092 packet->PeekHeader(assocReq);
2093 }
2094 else
2095 {
2096 packet->PeekHeader(reassocReq);
2097 frame = reassocReq;
2098 }
2099 if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
2100 {
2101 ParseReportedStaInfo(frame, from, linkId);
2102 }
2103 SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
2104 return;
2105 }
2107 NS_LOG_DEBUG("Disassociation received from " << from);
2108 GetWifiRemoteStationManager(linkId)->RecordDisassociated(from);
2109 auto& staList = GetLink(linkId).staList;
2110 for (auto it = staList.begin(); it != staList.end(); ++it)
2111 {
2112 if (it->second == from)
2113 {
2114 staList.erase(it);
2115 m_deAssocLogger(it->first, it->second);
2116 if (GetWifiRemoteStationManager(linkId)->GetDsssSupported(from) &&
2117 !GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(from))
2118 {
2119 GetLink(linkId).numNonErpStations--;
2120 }
2121 if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from) &&
2122 !GetWifiRemoteStationManager(linkId)->GetStationHe6GhzCapabilities(
2123 from))
2124 {
2125 GetLink(linkId).numNonHtStations--;
2126 }
2130 if (m_gcrManager)
2131 {
2132 m_gcrManager->NotifyStaDeassociated(from);
2133 }
2134 break;
2135 }
2136 }
2137 return;
2138 }
2139 case WIFI_MAC_MGT_ACTION: {
2140 auto pkt = mpdu->GetPacket()->Copy();
2141 auto [category, action] = WifiActionHeader::Remove(pkt);
2142 if (category == WifiActionHeader::PROTECTED_EHT &&
2143 action.protectedEhtAction ==
2145 IsAssociated(hdr->GetAddr2()))
2146 {
2147 // received an EML Operating Mode Notification frame from an associated station
2148 MgtEmlOmn frame;
2149 pkt->RemoveHeader(frame);
2150 ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
2151 return;
2152 }
2153 break;
2154 }
2155 default:;
2156 // do nothing
2157 }
2158 }
2159 }
2160
2161 // Invoke the receive handler of our parent class to deal with any other frames
2162 WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
2163}
2164
2165bool
2167 const Mac48Address& from,
2168 uint8_t linkId)
2169{
2170 NS_LOG_FUNCTION(this << from << +linkId);
2171
2172 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
2173
2174 auto failure = [&](const std::string& msg) -> bool {
2175 NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
2176 remoteStationManager->RecordAssocRefused(from);
2177 return false;
2178 };
2179
2180 // lambda to process received (Re)Association Request
2181 auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
2182 const auto& frame = frameRefWrapper.get();
2183
2184 // first, verify that the the station's supported
2185 // rate set is compatible with our Basic Rate set
2186 const CapabilityInformation& capabilities = frame.Capabilities();
2187 remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
2188 NS_ASSERT(frame.template Get<SupportedRates>());
2189 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
2190 frame.template Get<ExtendedSupportedRatesIE>()};
2191
2192 if (rates.GetNRates() == 0)
2193 {
2194 return failure("STA's supported rate set not compatible with our Basic Rate set");
2195 }
2196
2197 if (GetHtSupported(linkId))
2198 {
2199 // check whether the HT STA supports all MCSs in Basic MCS Set
2200 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2201 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
2202 {
2203 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2204 {
2205 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2206 if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
2207 {
2208 return failure("HT STA does not support all MCSs in Basic MCS Set");
2209 }
2210 }
2211 }
2212 }
2213 if (GetVhtSupported(linkId))
2214 {
2215 // check whether the VHT STA supports all MCSs in Basic MCS Set
2216 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2217 if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
2218 {
2219 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2220 {
2221 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2222 if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2223 {
2224 return failure("VHT STA does not support all MCSs in Basic MCS Set");
2225 }
2226 }
2227 }
2228 }
2229 if (GetHeSupported())
2230 {
2231 // check whether the HE STA supports all MCSs in Basic MCS Set
2232 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2233 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2234 {
2235 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
2236 {
2237 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
2238 if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2239 {
2240 return failure("HE STA does not support all MCSs in Basic MCS Set");
2241 }
2242 }
2243 }
2244 if (Is6GhzBand(linkId))
2245 {
2246 if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
2247 {
2248 remoteStationManager->AddStationHe6GhzCapabilities(from, *he6GhzCapabilities);
2249 }
2250 }
2251 }
2252 if (GetEhtSupported())
2253 {
2254 // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
2255 auto ehtConfig = GetEhtConfiguration();
2256 NS_ASSERT(ehtConfig);
2257
2258 if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
2259 !tidLinkMapping.empty())
2260 {
2261 // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
2262 // We refuse association if we do not support TID-to-Link mapping negotiation
2263 // or the non-AP MLD included more than two TID-to-Link Mapping IEs
2264 // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
2265 // or there is some TID that is not mapped to any link
2266 // or the direction(s) is/are not set properly
2267 if (tidLinkMapping.size() > 2)
2268 {
2269 return failure("More than two TID-to-Link Mapping IEs");
2270 }
2271
2272 // if only one Tid-to-Link Mapping element is present, it must be valid for
2273 // both directions
2274 bool bothDirIfOneTlm =
2275 tidLinkMapping.size() != 1 ||
2276 tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
2277 // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
2278 // Request frame or a (Re)Association Response frame shall set the Direction
2279 // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
2280 // subfield in the other TID-To- Link Mapping element to 1.
2281 // (Sec. 35.3.7.1.8 of 802.11be D3.1)
2282 bool distinctDirsIfTwoTlms =
2283 tidLinkMapping.size() != 2 ||
2284 (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2285 tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
2286 tidLinkMapping[0].m_control.direction !=
2287 tidLinkMapping[1].m_control.direction);
2288
2289 if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
2290 {
2291 return failure("Incorrect directions in TID-to-Link Mapping IEs");
2292 }
2293
2294 if (ehtConfig->m_tidLinkMappingSupport ==
2296 {
2297 return failure("TID-to-Link Mapping negotiation not supported");
2298 }
2299
2300 auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
2301 if (tlmIe.m_control.defaultMapping)
2302 {
2303 return;
2304 }
2305 for (uint8_t tid = 0; tid < 8; tid++)
2306 {
2307 if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
2308 {
2309 mapping.emplace(tid, std::move(linkSet));
2310 }
2311 }
2312 };
2313
2314 WifiTidLinkMapping dlMapping;
2315 WifiTidLinkMapping ulMapping;
2316
2317 switch (tidLinkMapping[0].m_control.direction)
2318 {
2320 getMapping(tidLinkMapping.at(0), dlMapping);
2321 ulMapping = dlMapping;
2322 break;
2324 getMapping(tidLinkMapping.at(0), dlMapping);
2325 getMapping(tidLinkMapping.at(1), ulMapping);
2326 break;
2328 getMapping(tidLinkMapping.at(0), ulMapping);
2329 getMapping(tidLinkMapping.at(1), dlMapping);
2330 break;
2331 }
2332
2333 if (ehtConfig->m_tidLinkMappingSupport ==
2335 !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
2336 {
2337 return failure("Mapping TIDs to distinct link sets is incompatible with "
2338 "negotiation support of 1");
2339 }
2340
2341 // otherwise, we accept the TID-to-link Mapping and store it
2342 const auto& mle = frame.template Get<MultiLinkElement>();
2343 NS_ASSERT_MSG(mle,
2344 "Multi-Link Element not present in an Association Request including "
2345 "TID-to-Link Mapping element(s)");
2346 auto mldAddr = mle->GetMldMacAddress();
2347
2348 // The requested link mappings are valid and can be accepted; store them.
2350 UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
2351 }
2352 }
2353
2354 // The association request from the station can be accepted.
2355 // Record all its supported modes in its associated WifiRemoteStation
2356 auto phy = GetWifiPhy(linkId);
2357
2358 for (const auto& mode : phy->GetModeList())
2359 {
2360 if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
2361 {
2362 remoteStationManager->AddSupportedMode(from, mode);
2363 }
2364 }
2365 if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
2366 capabilities.IsShortSlotTime())
2367 {
2368 remoteStationManager->AddSupportedErpSlotTime(from, true);
2369 }
2370 if (GetHtSupported(linkId))
2371 {
2372 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2373 if (htCapabilities.has_value())
2374 {
2375 remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
2376 }
2377 const auto& extendedCapabilities = frame.template Get<ExtendedCapabilities>();
2378 if (extendedCapabilities.has_value())
2379 {
2380 remoteStationManager->AddStationExtendedCapabilities(from, *extendedCapabilities);
2381 }
2382 }
2383 if (GetVhtSupported(linkId))
2384 {
2385 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2386 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
2387 // to check whether it supports VHT
2388 if (vhtCapabilities.has_value() &&
2389 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
2390 {
2391 remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
2392 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
2393 {
2394 if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2395 {
2396 remoteStationManager->AddSupportedMcs(from, mcs);
2397 // here should add a control to add basic MCS when it is implemented
2398 }
2399 }
2400 }
2401 }
2402 if (GetHeSupported())
2403 {
2404 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2405 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2406 {
2407 remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
2408 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
2409 {
2410 if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2411 {
2412 remoteStationManager->AddSupportedMcs(from, mcs);
2413 // here should add a control to add basic MCS when it is implemented
2414 }
2415 }
2416 }
2417 }
2418 if (GetEhtSupported())
2419 {
2420 if (const auto& ehtCapabilities = frame.template Get<EhtCapabilities>())
2421 {
2422 remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
2423 }
2424 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
2425 {
2426 // TODO: Add check whether MCS is supported from the capabilities
2427 remoteStationManager->AddSupportedMcs(from, mcs);
2428 // here should add a control to add basic MCS when it is implemented
2429 }
2430 }
2431
2432 NS_LOG_DEBUG("Association Request from " << from << " accepted");
2433 remoteStationManager->RecordWaitAssocTxOk(from);
2434 return true;
2435 };
2436
2437 return std::visit(recvAssocRequest, assoc);
2438}
2439
2440void
2442{
2443 NS_LOG_FUNCTION(this << from << +linkId);
2444
2445 // lambda to process received Multi-Link Element
2446 auto recvMle = [&](auto&& frame) {
2447 const auto& mle = frame.get().template Get<MultiLinkElement>();
2448
2449 if (!mle.has_value())
2450 {
2451 return;
2452 }
2453
2454 auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
2455 GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
2456
2457 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
2458 {
2459 auto& perStaProfile = mle->GetPerStaProfile(i);
2460 if (!perStaProfile.HasStaMacAddress())
2461 {
2462 NS_LOG_DEBUG("[i=" << i
2463 << "] Cannot setup a link if the STA MAC address is missing");
2464 continue;
2465 }
2466 uint8_t newLinkId = perStaProfile.GetLinkId();
2467 if (newLinkId == linkId || newLinkId >= GetNLinks())
2468 {
2469 NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
2470 continue;
2471 }
2472 if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
2473 {
2474 NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
2475 continue;
2476 }
2477
2478 ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
2479 perStaProfile.GetStaMacAddress(),
2480 newLinkId);
2481 GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
2482 perStaProfile.GetStaMacAddress(),
2483 mleCommonInfo);
2484 }
2485 };
2486
2487 std::visit(recvMle, assoc);
2488}
2489
2490void
2491ApWifiMac::ReceiveEmlOmn(MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
2492{
2493 NS_LOG_FUNCTION(this << frame << sender << linkId);
2494
2495 auto ehtConfiguration = GetEhtConfiguration();
2496
2497 if (!ehtConfiguration || !ehtConfiguration->m_emlsrActivated)
2498 {
2500 "Received an EML Operating Mode Notification frame but EMLSR is not activated");
2501 return;
2502 }
2503
2505 {
2507 auto emlCapabilities =
2508 GetWifiRemoteStationManager(linkId)->GetStationEmlCapabilities(sender);
2509 NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
2510
2511 // update values stored in remote station manager
2512 emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
2513 emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
2514 }
2515
2516 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
2517 NS_ASSERT_MSG(mldAddress, "No MLD address stored for STA " << sender);
2518 auto emlsrLinks =
2519 frame.m_emlControl.emlsrMode == 1 ? frame.GetLinkBitmap() : std::list<uint8_t>{};
2520
2521 // The AP MLD has to consider the changes carried by the received EML Notification frame
2522 // as effective at the same time as the non-AP MLD. Therefore, we need to start a time
2523 // when the transmission of the Ack following the received EML Notification frame is
2524 // completed. For this purpose, we connect a callback to the PHY TX begin trace to catch
2525 // the Ack transmitted after the EML Notification frame.
2527 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u /* txPower */) {
2528 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
2529 psduMap.begin()->second->GetHeader(0).IsAck(),
2530 "Expected a Normal Ack after EML Notification frame");
2531
2532 auto ackDuration =
2533 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
2534
2536 ackDuration + ehtConfiguration->m_transitionTimeout,
2537 [=, this]() {
2538 for (uint8_t id = 0; id < GetNLinks(); id++)
2539 {
2540 auto linkAddress =
2541 GetWifiRemoteStationManager(id)->GetAffiliatedStaAddress(*mldAddress);
2542 if (!linkAddress)
2543 {
2544 // this link has not been setup by the non-AP MLD
2545 continue;
2546 }
2547
2548 if (!emlsrLinks.empty())
2549 {
2550 // the non-AP MLD is enabling EMLSR mode
2551 /**
2552 * After the successful transmission of the EML Operating Mode
2553 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
2554 * the non-AP MLD shall operate in the EMLSR mode and the other non-AP
2555 * STAs operating on the corresponding EMLSR links shall transition to
2556 * active mode after the transition delay indicated in the Transition
2557 * Timeout subfield in the EML Capabilities subfield of the Basic
2558 * Multi-Link element or immediately after receiving an EML Operating
2559 * Mode Notification frame from one of the APs operating on the EMLSR
2560 * links and affiliated with the AP MLD (Sec. 35.3.17 of 802.11be D3.0)
2561 */
2562 auto enabled = std::find(emlsrLinks.cbegin(), emlsrLinks.cend(), id) !=
2563 emlsrLinks.cend();
2564 if (enabled)
2565 {
2566 StaSwitchingToActiveModeOrDeassociated(*linkAddress, id);
2567 }
2568 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, enabled);
2569 }
2570 else
2571 {
2572 // the non-AP MLD is disabling EMLSR mode
2573 /**
2574 * After the successful transmission of the EML Operating Mode
2575 * Notification frame by the non-AP STA affiliated with the non-AP MLD,
2576 * the non-AP MLD shall disable the EMLSR mode and the other non-AP
2577 * STAs operating on the corresponding EMLSR links shall transition to
2578 * power save mode after the transition delay indicated in the
2579 * Transition Timeout subfield in the EML Capabilities subfield of the
2580 * Basic Multi-Link element or immediately after receiving an EML
2581 * Operating Mode Notification frame from one of the APs operating on
2582 * the EMLSR links and affiliated with the AP MLD. (Sec. 35.3.17 of
2583 * 802.11be D3.0)
2584 */
2585 if (id != linkId &&
2586 GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*linkAddress))
2587 {
2588 StaSwitchingToPsMode(*linkAddress, id);
2589 }
2590 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, false);
2591 }
2592 }
2593 });
2594 });
2595
2596 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
2597 // after its transmission begins
2598 auto phy = GetLink(linkId).phy;
2599 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
2600 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
2601 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
2602
2603 // An AP MLD with dot11EHTEMLSROptionActivated equal to true sets the EMLSR Mode subfield
2604 // to the value obtained from the EMLSR Mode subfield of the received EML Operating Mode
2605 // Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2606
2607 // When included in a frame sent by an AP affiliated with an AP MLD, the EMLSR Parameter
2608 // Update Control subfield is set to 0. (Sec. 9.6.35.8 of 802.11be D3.0)
2609 frame.m_emlControl.emlsrParamUpdateCtrl = 0;
2610
2611 // An AP MLD with dot11EHTEMLSROptionImplemented equal to true sets the EMLSR Link Bitmap
2612 // subfield to the value obtained from the EMLSR Link Bitmap subfield of the received
2613 // EML Operating Mode Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2614
2615 // The EMLSR Parameter Update field [..] is present if [..] the Action frame is sent by
2616 // a non-AP STA affiliated with a non-AP MLD (Sec. 9.6.35.8 of 802.11be D3.0)
2617 frame.m_emlsrParamUpdate.reset();
2618
2619 auto ehtFem = StaticCast<EhtFrameExchangeManager>(GetFrameExchangeManager(linkId));
2620 ehtFem->SendEmlOmn(sender, frame);
2621}
2622
2623void
2625{
2626 NS_LOG_FUNCTION(this << *mpdu);
2627 for (auto& i : *PeekPointer(mpdu))
2628 {
2629 auto from = i.second.GetSourceAddr();
2630 auto to = i.second.GetDestinationAddr();
2631
2632 if (to.IsGroup() || IsAssociated(to))
2633 {
2634 NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
2635 WifiMac::Enqueue(i.first->Copy(), to, from, mpdu->GetHeader().GetQosTid());
2636 }
2637
2638 ForwardUp(i.first, from, to);
2639 }
2640}
2641
2642void
2644{
2645 NS_LOG_FUNCTION(this);
2647
2648 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
2649 {
2650 GetLink(linkId).beaconEvent.Cancel();
2652 {
2653 uint64_t jitterUs =
2655 ? static_cast<uint64_t>(m_beaconJitter->GetValue(0, 1) *
2657 : 0);
2658 NS_LOG_DEBUG("Scheduling initial beacon for access point "
2659 << GetAddress() << " at time " << jitterUs << "us");
2662 this,
2663 linkId);
2664 }
2667 }
2668
2669 if (m_gcrManager)
2670 {
2671 m_gcrManager->Initialize();
2672 }
2673
2678}
2679
2680bool
2682{
2683 bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
2684 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
2685 return useProtection;
2686}
2687
2688uint16_t
2690{
2691 const auto& links = GetLinks();
2692
2693 // if this is an AP MLD, AIDs from 1 to N, where N is 2^(Group_addr_BU_Indic_Exp + 1) - 1
2694 // shall not be allocated (see Section 35.3.15.1 of 802.11be D7.0)
2695 const uint16_t startAid = links.size() == 1 ? MIN_AID : (1 << (m_grpAddrBuIndicExp + 1));
2696
2697 // Return the first AID value between min and max that is free for all the links
2698 const auto maxAid = GetEhtSupported() ? EHT_MAX_AID : MAX_AID;
2699 for (uint16_t nextAid = startAid; nextAid <= maxAid; ++nextAid)
2700 {
2701 if (std::none_of(links.cbegin(), links.cend(), [&](auto&& idLinkPair) {
2702 return GetStaList(idLinkPair.first).contains(nextAid);
2703 }))
2704 {
2705 return nextAid;
2706 }
2707 }
2708 NS_FATAL_ERROR("No free association ID available!");
2709 return 0;
2710}
2711
2712const std::map<uint16_t, Mac48Address>&
2713ApWifiMac::GetStaList(uint8_t linkId) const
2714{
2715 return GetLink(linkId).staList;
2716}
2717
2718uint16_t
2720{
2721 return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
2722}
2723
2724uint8_t
2725ApWifiMac::GetBufferStatus(uint8_t tid, Mac48Address address) const
2726{
2727 auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
2728 if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
2729 {
2730 return 255;
2731 }
2732 return it->second.value;
2733}
2734
2735void
2736ApWifiMac::SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
2737{
2738 if (size == 255)
2739 {
2740 // no point in storing an unspecified size
2741 m_bufferStatus.erase(WifiAddressTidPair(address, tid));
2742 }
2743 else
2744 {
2745 m_bufferStatus[WifiAddressTidPair(address, tid)] = {size, Simulator::Now()};
2746 }
2747}
2748
2749uint8_t
2751{
2752 uint8_t maxSize = 0;
2753 bool found = false;
2754
2755 for (uint8_t tid = 0; tid < 8; tid++)
2756 {
2757 uint8_t size = GetBufferStatus(tid, address);
2758 if (size != 255)
2759 {
2760 maxSize = std::max(maxSize, size);
2761 found = true;
2762 }
2763 }
2764
2765 if (found)
2766 {
2767 return maxSize;
2768 }
2769 return 255;
2770}
2771
2772bool
2774 uint8_t tid) const
2775{
2777 return GetQosTxop(tid)->GetBaManager()->IsGcrAgreementEstablished(
2778 groupAddress,
2779 tid,
2780 m_gcrManager->GetMemberStasForGroupAddress(groupAddress));
2781}
2782
2783} // 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.
std::optional< EhtOpInfo > m_opInfo
EHT Operation Information.
Hold variables of type enum.
Definition enum.h:52
The ErpInformation Information Element.
void SetBarkerPreambleMode(uint8_t barkerPreambleMode)
Set the Barker_Preamble_Mode field in the ErpInformation information element.
void SetUseProtection(uint8_t useProtection)
Set the Use_Protection field in the ErpInformation information element.
void SetNonErpPresent(uint8_t nonErpPresent)
Set the Non_Erp_Present field in the ErpInformation information element.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
Implement the FILS (Fast Initial Link Setup) action frame.
uint16_t m_beaconInt
Beacon Interval in TU (1024 us)
std::optional< ReducedNeighborReport > m_rnr
Reduced Neighbor Report.
void SetSsid(const std::string &ssid)
Set the SSID field.
OptFieldWithPresenceInd< FdCapability > m_fdCap
FD Capability.
void SetLengthSubfield()
sets value of Length subfield
The HE 6 GHz Band Capabilities (IEEE 802.11ax-2021 9.4.2.263)
The IEEE 802.11ax HE Capabilities.
The HE Operation Information Element.
OptFieldWithPresenceInd< OpInfo6GHz > m_6GHzOpInfo
6 GHz Operation Information field
void SetMaxHeMcsPerNss(uint8_t nss, uint8_t maxHeMcs)
Set the Basic HE-MCS and NSS field in the HE Operation information element by specifying the pair (ns...
BssColorInfo m_bssColorInfo
BSS Color Information field.
The HT Capabilities Information Element.
The HT Operation Information Element.
void SetObssNonHtStasPresent(uint8_t obssNonHtStasPresent)
Set the OBSS non HT STAs present.
void SetRifsMode(uint8_t rifsMode)
Set the RIFS mode.
void SetSecondaryChannelOffset(uint8_t secondaryChannelOffset)
Set the secondary channel offset.
void SetPcoActive(uint8_t pcoActive)
Set the PCO active.
void SetTxUnequalModulation(uint8_t txUnequalModulation)
Set the transmit unequal modulation.
void SetHtProtection(uint8_t htProtection)
Set the HT protection.
void SetTxMaxNSpatialStreams(uint8_t maxTxSpatialStreams)
Set the transmit maximum number spatial streams.
void SetTxRxMcsSetUnequal(uint8_t txRxMcsSetUnequal)
Set the transmit / receive MCS set unequal.
void SetDualBeacon(uint8_t dualBeacon)
Set the dual beacon.
void SetNonGfHtStasPresent(uint8_t nonGfHtStasPresent)
Set the non GF HT STAs present.
void SetTxMcsSetDefined(uint8_t txMcsSetDefined)
Set the transmit MCS set defined.
void SetLSigTxopProtectionFullSupport(uint8_t lSigTxopProtectionFullSupport)
Set the LSIG TXOP protection full support.
void SetStaChannelWidth(uint8_t staChannelWidth)
Set the STA channel width.
void SetRxHighestSupportedDataRate(uint16_t maxSupportedRate)
Set the receive highest supported data rate.
void SetRxMcsBitmask(uint8_t index)
Set the receive MCS bitmask.
void SetPrimaryChannel(uint8_t ctrl)
Set the Primary Channel field in the HT Operation information element.
void SetDualCtsProtection(uint8_t dualCtsProtection)
Set the dual CTS protection.
void SetPhase(uint8_t pcoPhase)
Set the PCO phase.
void SetStbcBeacon(uint8_t stbcBeacon)
Set the STBC beacon.
an EUI-48 address
bool IsGroup() const
static Mac48Address GetBroadcast()
bool IsBroadcast() const
Implement the header for management frames of type association request.
Implement the header for management frames of type association and reassociation response.
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:38
const std::string & GetUniqueName() const
Definition wifi-mode.cc:136
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:110
uint8_t GetMcsValue() const
Definition wifi-mode.cc:151
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:844
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:2062
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 value in microseconds (see IEEE 802.11-2020 sec.
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:70
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
static constexpr uint16_t MIN_AID
The minimum value for the association ID (Sec. 9.4.1.8 of 802.11-2020)
std::variant< std::reference_wrapper< MgtAssocRequestHeader >, std::reference_wrapper< MgtReassocRequestHeader > > AssocReqRefVariant
variant holding a reference to a (Re)Association Request
Definition ap-wifi-mac.h:45
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
static constexpr uint16_t MAX_AID
The maximum value for the association ID (Sec. 9.4.1.8 of 802.11-2020)
static constexpr uint16_t EHT_MAX_AID
The maximum value for the association ID updated since 802.11be (Sec. 9.4.1.8 of 802....
Struct containing all supported rates.
void SetBasicRate(uint64_t bs)
Set the given rate to basic rates.
void AddBssMembershipSelectorRate(uint64_t bs)
Add a special value to the supported rate set, corresponding to a BSS membership selector.
void AddSupportedRate(uint64_t bs)
Add the given rate to the supported rates.
std::optional< MldCapabilities > m_mldCapabilities
MLD Capabilities.
void SetMediumSyncDelayTimer(Time delay)
Set the Medium Synchronization Duration subfield of the Medium Synchronization Delay Information in t...
EHT Operation Information subfield IEEE 802.11be D2.0 Figure 9-1002c.
uint8_t grpBuExp
Group Addressed BU Indication Exponent.
uint8_t opInfoPresent
EHT Operation Information Present.
FD Capability subfield of FILS Discovery Information field.
6 GHz Operation Information field
uint8_t m_chCntrFreqSeg0
Channel center frequency segment 0.
uint8_t m_chWid
Channel Width.
uint8_t m_primCh
Primary Channel.
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
typedef for union of different ActionValues