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 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19 * Mirko Banchi <mk.banchi@gmail.com>
20 */
21
22#include "ap-wifi-mac.h"
23
26#include "mac-rx-middle.h"
27#include "mac-tx-middle.h"
28#include "mgt-action-headers.h"
29#include "mgt-headers.h"
30#include "msdu-aggregator.h"
31#include "qos-txop.h"
34#include "wifi-mac-queue.h"
35#include "wifi-net-device.h"
36#include "wifi-phy.h"
37
38#include "ns3/eht-configuration.h"
39#include "ns3/eht-frame-exchange-manager.h"
40#include "ns3/he-configuration.h"
41#include "ns3/ht-configuration.h"
42#include "ns3/log.h"
43#include "ns3/multi-link-element.h"
44#include "ns3/packet.h"
45#include "ns3/pointer.h"
46#include "ns3/random-variable-stream.h"
47#include "ns3/simulator.h"
48#include "ns3/string.h"
49
50namespace ns3
51{
52
53NS_LOG_COMPONENT_DEFINE("ApWifiMac");
54
56
57TypeId
59{
60 static TypeId tid =
61 TypeId("ns3::ApWifiMac")
63 .SetGroupName("Wifi")
64 .AddConstructor<ApWifiMac>()
65 .AddAttribute(
66 "BeaconInterval",
67 "Delay between two beacons",
68 TimeValue(MicroSeconds(102400)),
71 .AddAttribute("BeaconJitter",
72 "A uniform random variable to cause the initial beacon starting time "
73 "(after simulation time 0) "
74 "to be distributed between 0 and the BeaconInterval.",
75 StringValue("ns3::UniformRandomVariable"),
77 MakePointerChecker<UniformRandomVariable>())
78 .AddAttribute("EnableBeaconJitter",
79 "If beacons are enabled, whether to jitter the initial send event.",
80 BooleanValue(true),
83 .AddAttribute("BeaconGeneration",
84 "Whether or not beacons are generated.",
85 BooleanValue(true),
88 .AddAttribute("EnableNonErpProtection",
89 "Whether or not protection mechanism should be used when non-ERP STAs "
90 "are present within the BSS."
91 "This parameter is only used when ERP is supported by the AP.",
92 BooleanValue(true),
95 .AddAttribute("BsrLifetime",
96 "Lifetime of Buffer Status Reports received from stations.",
100 .AddTraceSource("AssociatedSta",
101 "A station associated with this access point.",
103 "ns3::ApWifiMac::AssociationCallback")
104 .AddTraceSource("DeAssociatedSta",
105 "A station lost association with this access point.",
107 "ns3::ApWifiMac::AssociationCallback");
108 return tid;
109}
110
112 : m_enableBeaconGeneration(false)
113{
114 NS_LOG_FUNCTION(this);
115 m_beaconTxop = CreateObject<Txop>(CreateObject<WifiMacQueue>(AC_BEACON));
117
118 // Let the lower layers know that we are acting as an AP.
120}
121
123{
124 NS_LOG_FUNCTION(this);
125}
126
127void
129{
130 NS_LOG_FUNCTION(this);
132 m_beaconTxop = nullptr;
135}
136
138{
141}
142
143std::unique_ptr<WifiMac::LinkEntity>
145{
146 return std::make_unique<ApLinkEntity>();
147}
148
150ApWifiMac::GetLink(uint8_t linkId) const
151{
152 return static_cast<ApLinkEntity&>(WifiMac::GetLink(linkId));
153}
154
155void
157{
158 NS_LOG_FUNCTION(this << standard);
161 m_beaconTxop->SetAifsns(std::vector<uint8_t>(GetNLinks(), 1));
162 m_beaconTxop->SetMinCws(std::vector<uint32_t>(GetNLinks(), 0));
163 m_beaconTxop->SetMaxCws(std::vector<uint32_t>(GetNLinks(), 0));
164 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
165 {
167 }
168}
169
172{
173 if (ac == AC_BEACON)
174 {
176 }
177 return WifiMac::GetTxopQueue(ac);
178}
179
180void
182{
183 NS_LOG_FUNCTION(this << enable);
184 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
185 {
186 if (!enable)
187 {
188 GetLink(linkId).beaconEvent.Cancel();
189 }
190 else if (!m_enableBeaconGeneration)
191 {
192 GetLink(linkId).beaconEvent =
194 }
195 }
197}
198
199Time
201{
202 NS_LOG_FUNCTION(this);
203 return m_beaconInterval;
204}
205
206void
208{
209 NS_LOG_FUNCTION(this << &linkUp);
211
212 // The approach taken here is that, from the point of view of an AP,
213 // the link is always up, so we immediately invoke the callback if
214 // one is set
215 linkUp();
216}
217
218void
220{
221 NS_LOG_FUNCTION(this << interval);
222 if ((interval.GetMicroSeconds() % 1024) != 0)
223 {
224 NS_FATAL_ERROR("beacon interval should be multiple of 1024us (802.11 time unit), see IEEE "
225 "Std. 802.11-2012");
226 }
227 if (interval.GetMicroSeconds() > (1024 * 65535))
228 {
230 "beacon interval should be smaller then or equal to 65535 * 1024us (802.11 time unit)");
231 }
232 m_beaconInterval = interval;
233}
234
235int64_t
237{
238 NS_LOG_FUNCTION(this << stream);
239 m_beaconJitter->SetStream(stream);
240 return 1;
241}
242
243void
245{
246 NS_LOG_FUNCTION(this << +linkId);
247 auto& link = GetLink(linkId);
248 if (GetErpSupported(linkId) && GetShortSlotTimeSupported() && (link.numNonErpStations == 0))
249 {
250 for (const auto& sta : link.staList)
251 {
253 {
254 link.shortSlotTimeEnabled = false;
255 return;
256 }
257 }
258 link.shortSlotTimeEnabled = true;
259 }
260 else
261 {
262 link.shortSlotTimeEnabled = false;
263 }
264}
265
266void
268{
269 NS_LOG_FUNCTION(this << +linkId);
270 auto& link = GetLink(linkId);
271 if (GetErpSupported(linkId) && GetWifiPhy(linkId)->GetShortPhyPreambleSupported())
272 {
273 for (const auto& sta : link.staList)
274 {
275 if (!GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(sta.second) ||
276 !GetWifiRemoteStationManager(linkId)->GetShortPreambleSupported(sta.second))
277 {
278 link.shortPreambleEnabled = false;
279 return;
280 }
281 }
282 link.shortPreambleEnabled = true;
283 }
284 else
285 {
286 link.shortPreambleEnabled = false;
287 }
288}
289
290void
292{
293 NS_LOG_FUNCTION(this << packet << from << to);
294 // If we are not a QoS AP then we definitely want to use AC_BE to
295 // transmit the packet. A TID of zero will map to AC_BE (through \c
296 // QosUtilsMapTidToAc()), so we use that as our default here.
297 uint8_t tid = 0;
298
299 // If we are a QoS AP then we attempt to get a TID for this packet
300 if (GetQosSupported())
301 {
302 tid = QosUtilsGetTidForPacket(packet);
303 // Any value greater than 7 is invalid and likely indicates that
304 // the packet had no QoS tag, so we revert to zero, which'll
305 // mean that AC_BE is used.
306 if (tid > 7)
307 {
308 tid = 0;
309 }
310 }
311
312 ForwardDown(packet, from, to, tid);
313}
314
315void
317{
318 NS_LOG_FUNCTION(this << packet << from << to << +tid);
319 WifiMacHeader hdr;
320
321 // For now, an AP that supports QoS does not support non-QoS
322 // associations, and vice versa. In future the AP model should
323 // support simultaneously associated QoS and non-QoS STAs, at which
324 // point there will need to be per-association QoS state maintained
325 // by the association state machine, and consulted here.
326 if (GetQosSupported())
327 {
330 hdr.SetQosNoEosp();
331 hdr.SetQosNoAmsdu();
332 // Transmission of multiple frames in the same Polled TXOP is not supported for now
333 hdr.SetQosTxopLimit(0);
334 // Fill in the QoS control field in the MAC header
335 hdr.SetQosTid(tid);
336 }
337 else
338 {
340 }
341
342 if (GetQosSupported())
343 {
344 hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
345 // yet implemented (set it to 1 when implemented)
346 }
347
348 std::list<Mac48Address> addr2Set;
349 if (to.IsGroup())
350 {
351 // broadcast frames are transmitted on all the links
352 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
353 {
354 addr2Set.push_back(GetFrameExchangeManager(linkId)->GetAddress());
355 }
356 }
357 else
358 {
359 // the Transmitter Address (TA) is the MLD address only for non-broadcast data frames
360 // exchanged between two MLDs
361 addr2Set = {GetAddress()};
362 auto linkId = IsAssociated(to);
363 NS_ASSERT_MSG(linkId, "Station " << to << "is not associated, cannot send it a frame");
364 if (GetNLinks() == 1 || !GetWifiRemoteStationManager(*linkId)->GetMldAddress(to))
365 {
366 addr2Set = {GetFrameExchangeManager(*linkId)->GetAddress()};
367 }
368 }
369
370 for (const auto& addr2 : addr2Set)
371 {
372 hdr.SetAddr1(to);
373 hdr.SetAddr2(addr2);
374 hdr.SetAddr3(from);
375 hdr.SetDsFrom();
376 hdr.SetDsNotTo();
377
378 if (GetQosSupported())
379 {
380 // Sanity check that the TID is valid
381 NS_ASSERT(tid < 8);
382 GetQosTxop(tid)->Queue(packet, hdr);
383 }
384 else
385 {
386 GetTxop()->Queue(packet, hdr);
387 }
388 }
389}
390
391bool
393{
394 return (to.IsGroup() || IsAssociated(to));
395}
396
397void
399{
400 NS_LOG_FUNCTION(this << packet << to << from);
401 if (CanForwardPacketsTo(to))
402 {
403 ForwardDown(packet, from, to);
404 }
405 else
406 {
407 NotifyTxDrop(packet);
408 }
409}
410
411void
413{
414 NS_LOG_FUNCTION(this << packet << to);
415 // We're sending this packet with a from address that is our own. We
416 // get that address from the lower MAC and make use of the
417 // from-spoofing Enqueue() method to avoid duplicated code.
418 Enqueue(packet, to, GetAddress());
419}
420
421bool
423{
424 NS_LOG_FUNCTION(this);
425 return true;
426}
427
429ApWifiMac::GetSupportedRates(uint8_t linkId) const
430{
431 NS_LOG_FUNCTION(this << +linkId);
432 AllSupportedRates rates;
433 // Send the set of supported rates and make sure that we indicate
434 // the Basic Rate set in this set of supported rates.
435 for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
436 {
437 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
438 NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
439 rates.AddSupportedRate(modeDataRate);
440 // Add rates that are part of the BSSBasicRateSet (manufacturer dependent!)
441 // here we choose to add the mandatory rates to the BSSBasicRateSet,
442 // except for 802.11b where we assume that only the non HR-DSSS rates are part of the
443 // BSSBasicRateSet
444 if (mode.IsMandatory() && (mode.GetModulationClass() != WIFI_MOD_CLASS_HR_DSSS))
445 {
446 NS_LOG_DEBUG("Adding basic mode " << mode.GetUniqueName());
447 GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
448 }
449 }
450 // set the basic rates
451 for (uint8_t j = 0; j < GetWifiRemoteStationManager(linkId)->GetNBasicModes(); j++)
452 {
453 WifiMode mode = GetWifiRemoteStationManager(linkId)->GetBasicMode(j);
454 uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
455 NS_LOG_DEBUG("Setting basic rate " << mode.GetUniqueName());
456 rates.SetBasicRate(modeDataRate);
457 }
458 // If it is a HT AP, then add the BSSMembershipSelectorSet
459 // The standard says that the BSSMembershipSelectorSet
460 // must have its MSB set to 1 (must be treated as a Basic Rate)
461 // Also the standard mentioned that at least 1 element should be included in the SupportedRates
462 // the rest can be in the ExtendedSupportedRates
463 if (GetHtSupported())
464 {
465 for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
466 {
467 rates.AddBssMembershipSelectorRate(selector);
468 }
469 }
470 return rates;
471}
472
475{
476 NS_LOG_FUNCTION(this << +linkId);
478 DsssParameterSet dsssParameters;
479 dsssParameters.SetCurrentChannel(GetWifiPhy(linkId)->GetChannelNumber());
480 return dsssParameters;
481}
482
484ApWifiMac::GetCapabilities(uint8_t linkId) const
485{
486 NS_LOG_FUNCTION(this << +linkId);
487 CapabilityInformation capabilities;
488 capabilities.SetShortPreamble(GetLink(linkId).shortPreambleEnabled);
489 capabilities.SetShortSlotTime(GetLink(linkId).shortSlotTimeEnabled);
490 capabilities.SetEss();
491 return capabilities;
492}
493
495ApWifiMac::GetErpInformation(uint8_t linkId) const
496{
497 NS_LOG_FUNCTION(this << +linkId);
498 NS_ASSERT(GetErpSupported(linkId));
499 ErpInformation information;
500
501 information.SetNonErpPresent(GetLink(linkId).numNonErpStations > 0);
502 information.SetUseProtection(GetUseNonErpProtection(linkId));
503 if (GetLink(linkId).shortPreambleEnabled)
504 {
505 information.SetBarkerPreambleMode(0);
506 }
507 else
508 {
509 information.SetBarkerPreambleMode(1);
510 }
511
512 return information;
513}
514
517{
518 NS_LOG_FUNCTION(this << +linkId);
520 EdcaParameterSet edcaParameters;
521
522 Ptr<QosTxop> edca;
523 Time txopLimit;
524
525 edca = GetQosTxop(AC_BE);
526 txopLimit = edca->GetTxopLimit(linkId);
527 edcaParameters.SetBeAci(0);
528 edcaParameters.SetBeCWmin(edca->GetMinCw(linkId));
529 edcaParameters.SetBeCWmax(edca->GetMaxCw(linkId));
530 edcaParameters.SetBeAifsn(edca->GetAifsn(linkId));
531 edcaParameters.SetBeTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
532
533 edca = GetQosTxop(AC_BK);
534 txopLimit = edca->GetTxopLimit(linkId);
535 edcaParameters.SetBkAci(1);
536 edcaParameters.SetBkCWmin(edca->GetMinCw(linkId));
537 edcaParameters.SetBkCWmax(edca->GetMaxCw(linkId));
538 edcaParameters.SetBkAifsn(edca->GetAifsn(linkId));
539 edcaParameters.SetBkTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
540
541 edca = GetQosTxop(AC_VI);
542 txopLimit = edca->GetTxopLimit(linkId);
543 edcaParameters.SetViAci(2);
544 edcaParameters.SetViCWmin(edca->GetMinCw(linkId));
545 edcaParameters.SetViCWmax(edca->GetMaxCw(linkId));
546 edcaParameters.SetViAifsn(edca->GetAifsn(linkId));
547 edcaParameters.SetViTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
548
549 edca = GetQosTxop(AC_VO);
550 txopLimit = edca->GetTxopLimit(linkId);
551 edcaParameters.SetVoAci(3);
552 edcaParameters.SetVoCWmin(edca->GetMinCw(linkId));
553 edcaParameters.SetVoCWmax(edca->GetMaxCw(linkId));
554 edcaParameters.SetVoAifsn(edca->GetAifsn(linkId));
555 edcaParameters.SetVoTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
556
557 edcaParameters.SetQosInfo(0);
558
559 return edcaParameters;
560}
561
562std::optional<MuEdcaParameterSet>
564{
565 NS_LOG_FUNCTION(this);
567
568 Ptr<HeConfiguration> heConfiguration = GetHeConfiguration();
569 NS_ASSERT(heConfiguration);
570
571 MuEdcaParameterSet muEdcaParameters;
572 muEdcaParameters.SetQosInfo(0);
573
574 UintegerValue uintegerValue;
575 TimeValue timeValue;
576
577 heConfiguration->GetAttribute("MuBeAifsn", uintegerValue);
578 muEdcaParameters.SetMuAifsn(AC_BE, uintegerValue.Get());
579 heConfiguration->GetAttribute("MuBeCwMin", uintegerValue);
580 muEdcaParameters.SetMuCwMin(AC_BE, uintegerValue.Get());
581 heConfiguration->GetAttribute("MuBeCwMax", uintegerValue);
582 muEdcaParameters.SetMuCwMax(AC_BE, uintegerValue.Get());
583 heConfiguration->GetAttribute("BeMuEdcaTimer", timeValue);
584 muEdcaParameters.SetMuEdcaTimer(AC_BE, timeValue.Get());
585
586 heConfiguration->GetAttribute("MuBkAifsn", uintegerValue);
587 muEdcaParameters.SetMuAifsn(AC_BK, uintegerValue.Get());
588 heConfiguration->GetAttribute("MuBkCwMin", uintegerValue);
589 muEdcaParameters.SetMuCwMin(AC_BK, uintegerValue.Get());
590 heConfiguration->GetAttribute("MuBkCwMax", uintegerValue);
591 muEdcaParameters.SetMuCwMax(AC_BK, uintegerValue.Get());
592 heConfiguration->GetAttribute("BkMuEdcaTimer", timeValue);
593 muEdcaParameters.SetMuEdcaTimer(AC_BK, timeValue.Get());
594
595 heConfiguration->GetAttribute("MuViAifsn", uintegerValue);
596 muEdcaParameters.SetMuAifsn(AC_VI, uintegerValue.Get());
597 heConfiguration->GetAttribute("MuViCwMin", uintegerValue);
598 muEdcaParameters.SetMuCwMin(AC_VI, uintegerValue.Get());
599 heConfiguration->GetAttribute("MuViCwMax", uintegerValue);
600 muEdcaParameters.SetMuCwMax(AC_VI, uintegerValue.Get());
601 heConfiguration->GetAttribute("ViMuEdcaTimer", timeValue);
602 muEdcaParameters.SetMuEdcaTimer(AC_VI, timeValue.Get());
603
604 heConfiguration->GetAttribute("MuVoAifsn", uintegerValue);
605 muEdcaParameters.SetMuAifsn(AC_VO, uintegerValue.Get());
606 heConfiguration->GetAttribute("MuVoCwMin", uintegerValue);
607 muEdcaParameters.SetMuCwMin(AC_VO, uintegerValue.Get());
608 heConfiguration->GetAttribute("MuVoCwMax", uintegerValue);
609 muEdcaParameters.SetMuCwMax(AC_VO, uintegerValue.Get());
610 heConfiguration->GetAttribute("VoMuEdcaTimer", timeValue);
611 muEdcaParameters.SetMuEdcaTimer(AC_VO, timeValue.Get());
612
613 // The timers of the MU EDCA Parameter Set must be either all zero or all
614 // non-zero. The information element is advertised if all timers are non-zero
615 auto timerNotNull = [&muEdcaParameters](uint8_t aci) {
616 return !muEdcaParameters.GetMuEdcaTimer(aci).IsZero();
617 };
618 auto aci = {0, 1, 2, 3};
619 if (std::all_of(aci.begin(), aci.end(), timerNotNull))
620 {
621 return muEdcaParameters;
622 }
623
624 NS_ABORT_MSG_UNLESS(std::none_of(aci.begin(), aci.end(), timerNotNull),
625 "MU EDCA Timers must be all zero if the IE is not advertised.");
626
627 return std::nullopt;
628}
629
630std::optional<ReducedNeighborReport>
632{
633 NS_LOG_FUNCTION(this << +linkId);
634
635 if (GetNLinks() <= 1)
636 {
637 return std::nullopt;
638 }
639
642
643 for (uint8_t index = 0; index < GetNLinks(); ++index)
644 {
645 if (index != linkId) // all links but the one used to send this Beacon frame
646 {
647 rnr.AddNbrApInfoField();
648 std::size_t nbrId = rnr.GetNNbrApInfoFields() - 1;
650 rnr.AddTbttInformationField(nbrId);
651 rnr.SetBssid(nbrId, 0, GetLink(index).feManager->GetAddress());
652 rnr.SetShortSsid(nbrId, 0, 0);
653 rnr.SetBssParameters(nbrId, 0, 0);
654 rnr.SetPsd20MHz(nbrId, 0, 0);
655 rnr.SetMldParameters(nbrId, 0, 0, index, 0);
656 }
657 }
658 return rnr;
659}
660
662ApWifiMac::GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac48Address& to)
663{
664 NS_LOG_FUNCTION(this << +linkId << frameType << to);
665 NS_ABORT_IF(GetNLinks() == 1);
666
669 mle.SetLinkIdInfo(linkId);
671
672 auto ehtConfiguration = GetEhtConfiguration();
673 NS_ASSERT(ehtConfiguration);
674
675 if (BooleanValue emlsrActivated;
676 ehtConfiguration->GetAttributeFailSafe("EmlsrActivated", emlsrActivated) &&
677 emlsrActivated.Get())
678 {
679 mle.SetEmlsrSupported(true);
680 // When the EMLSR Padding Delay subfield is included in a frame sent by an AP affiliated
681 // with an AP MLD, the EMLSR Padding Delay subfield is reserved.
682 // When the EMLSR Transition Delay subfield is included in a frame sent by an AP affiliated
683 // with an AP MLD, the EMLSR Transition Delay subfield is reserved. (Sec. 9.4.2.312.2.3
684 // of 802.11be D2.3)
685 TimeValue time;
686 ehtConfiguration->GetAttribute("TransitionTimeout", time);
687 mle.SetTransitionTimeout(time.Get());
688
689 // An AP affiliated with an AP MLD may include the Medium Synchronization Delay Information
690 // subfield in the Common Info field of the Basic Multi-Link element carried in transmitted
691 // (Re)Association Response or Multi-Link Probe Response frames to provide medium
692 // synchronization information used by the AP MLD. (Section 35.3.16.8.2 of 802.11be D3.1)
693 if (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE)
694 {
695 auto& commonInfo = mle.GetCommonInfoBasic();
696
697 ehtConfiguration->GetAttribute("MediumSyncDuration", time);
698 commonInfo.SetMediumSyncDelayTimer(time.Get());
699
700 IntegerValue ofdmEdThres;
701 ehtConfiguration->GetAttribute("MsdOfdmEdThreshold", ofdmEdThres);
702 commonInfo.SetMediumSyncOfdmEdThreshold(ofdmEdThres.Get());
703
704 UintegerValue maxNTxops;
705 ehtConfiguration->GetAttribute("MsdMaxNTxops", maxNTxops);
706 commonInfo.SetMediumSyncMaxNTxops(maxNTxops.Get());
707 }
708 }
709
710 // The MLD Capabilities And Operations subfield is present in the Common Info field of the
711 // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
712 // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
713 if (frameType == WIFI_MAC_MGT_BEACON || frameType == WIFI_MAC_MGT_PROBE_RESPONSE ||
717 {
718 auto& mldCapabilities = mle.GetCommonInfoBasic().m_mldCapabilities;
719 mldCapabilities.emplace();
720 mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
721 mldCapabilities->srsSupport = 0;
723 ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
724 mldCapabilities->tidToLinkMappingSupport = negSupport.Get();
725 mldCapabilities->freqSepForStrApMld = 0; // not supported yet
726 mldCapabilities->aarSupport = 0; // not supported yet
727 }
728
729 // if the Multi-Link Element is being inserted in a (Re)Association Response frame
730 // and the remote station is affiliated with an MLD, try multi-link setup
731 if (auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
732 (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE ||
734 staMldAddress.has_value())
735 {
736 for (uint8_t i = 0; i < GetNLinks(); i++)
737 {
738 auto remoteStationManager = GetWifiRemoteStationManager(i);
739 if (auto staAddress = remoteStationManager->GetAffiliatedStaAddress(*staMldAddress);
740 i != linkId && staAddress.has_value() &&
741 (remoteStationManager->IsWaitAssocTxOk(*staAddress) ||
742 remoteStationManager->IsAssocRefused(*staAddress)))
743 {
744 // For each requested link in addition to the link on which the
745 // (Re)Association Response frame is transmitted, the Link Info field
746 // of the Basic Multi-Link element carried in the (Re)Association
747 // Response frame shall contain the corresponding Per-STA Profile
748 // subelement(s) (Sec. 35.3.5.4 of 802.11be D2.0)
750 auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
751 // The Link ID subfield of the STA Control field of the Per-STA Profile
752 // subelement for the AP corresponding to a link is set to the link ID
753 // of the AP affiliated with the AP MLD that is operating on that link.
754 perStaProfile.SetLinkId(i);
755 perStaProfile.SetCompleteProfile();
756 // For each Per-STA Profile subelement included in the Link Info field,
757 // the Complete Profile subfield of the STA Control field shall be set to 1
758 perStaProfile.SetStaMacAddress(GetFrameExchangeManager(i)->GetAddress());
759 perStaProfile.SetAssocResponse(GetAssocResp(*staAddress, i));
760 }
761 }
762 }
763
764 return mle;
765}
766
768ApWifiMac::GetHtOperation(uint8_t linkId) const
769{
770 NS_LOG_FUNCTION(this << +linkId);
772 HtOperation operation;
773 auto phy = GetWifiPhy(linkId);
774 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
775
776 operation.SetPrimaryChannel(phy->GetPrimaryChannelNumber(20));
777 operation.SetRifsMode(false);
778 operation.SetNonGfHtStasPresent(true);
779 if (phy->GetChannelWidth() > 20)
780 {
781 operation.SetSecondaryChannelOffset(1);
782 operation.SetStaChannelWidth(1);
783 }
784 if (GetLink(linkId).numNonHtStations == 0)
785 {
787 }
788 else
789 {
791 }
792 uint64_t maxSupportedRate = 0; // in bit/s
793 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HT))
794 {
795 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
796 NS_ASSERT(nss > 0 && nss < 5);
797 uint64_t dataRate =
798 mcs.GetDataRate(phy->GetChannelWidth(),
799 GetHtConfiguration()->GetShortGuardIntervalSupported() ? 400 : 800,
800 nss);
801 if (dataRate > maxSupportedRate)
802 {
803 maxSupportedRate = dataRate;
804 NS_LOG_DEBUG("Updating maxSupportedRate to " << maxSupportedRate);
805 }
806 }
807 uint8_t maxSpatialStream = phy->GetMaxSupportedTxSpatialStreams();
808 auto mcsList = phy->GetMcsList(WIFI_MOD_CLASS_HT);
809 uint8_t nMcs = mcsList.size();
810 for (const auto& sta : GetLink(linkId).staList)
811 {
812 if (remoteStationManager->GetHtSupported(sta.second))
813 {
814 uint64_t maxSupportedRateByHtSta = 0; // in bit/s
815 auto itMcs = mcsList.begin();
816 for (uint8_t j = 0;
817 j < (std::min(nMcs, remoteStationManager->GetNMcsSupported(sta.second)));
818 j++)
819 {
820 WifiMode mcs = *itMcs++;
821 uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
822 NS_ASSERT(nss > 0 && nss < 5);
823 uint64_t dataRate = mcs.GetDataRate(
824 remoteStationManager->GetChannelWidthSupported(sta.second),
825 remoteStationManager->GetShortGuardIntervalSupported(sta.second) ? 400 : 800,
826 nss);
827 if (dataRate > maxSupportedRateByHtSta)
828 {
829 maxSupportedRateByHtSta = dataRate;
830 }
831 }
832 if (maxSupportedRateByHtSta < maxSupportedRate)
833 {
834 maxSupportedRate = maxSupportedRateByHtSta;
835 }
836 if (remoteStationManager->GetNMcsSupported(sta.second) < nMcs)
837 {
838 nMcs = remoteStationManager->GetNMcsSupported(sta.second);
839 }
840 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
841 {
842 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
843 }
844 }
845 }
847 static_cast<uint16_t>(maxSupportedRate / 1e6)); // in Mbit/s
848 operation.SetTxMcsSetDefined(nMcs > 0);
849 operation.SetTxMaxNSpatialStreams(maxSpatialStream);
850 // To be filled in once supported
851 operation.SetObssNonHtStasPresent(0);
852 operation.SetDualBeacon(0);
853 operation.SetDualCtsProtection(0);
854 operation.SetStbcBeacon(0);
856 operation.SetPcoActive(0);
857 operation.SetPhase(0);
858 operation.SetRxMcsBitmask(0);
859 operation.SetTxRxMcsSetUnequal(0);
860 operation.SetTxUnequalModulation(0);
861
862 return operation;
863}
864
866ApWifiMac::GetVhtOperation(uint8_t linkId) const
867{
868 NS_LOG_FUNCTION(this << +linkId);
869 NS_ASSERT(GetVhtSupported(linkId));
870 VhtOperation operation;
871 auto phy = GetWifiPhy(linkId);
872 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
873
874 const uint16_t bssBandwidth = phy->GetChannelWidth();
875 // Set to 0 for 20 MHz or 40 MHz BSS bandwidth.
876 // Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS bandwidth.
877 operation.SetChannelWidth((bssBandwidth > 40) ? 1 : 0);
878 // For 20, 40, or 80 MHz BSS bandwidth, indicates the channel center frequency
879 // index for the 20, 40, or 80 MHz channel on which the VHT BSS operates.
880 // For 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
881 // indicates the channel center frequency index of the 80 MHz channel
882 // segment that contains the primary channel.
884 (bssBandwidth == 160)
885 ? phy->GetOperatingChannel().GetPrimaryChannelNumber(80, phy->GetStandard())
886 : phy->GetChannelNumber());
887 // For a 20, 40, or 80 MHz BSS bandwidth, this subfield is set to 0.
888 // For a 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
889 // indicates the channel center frequency index of the 160 MHz channel on
890 // which the VHT BSS operates.
891 operation.SetChannelCenterFrequencySegment1((bssBandwidth == 160) ? phy->GetChannelNumber()
892 : 0);
893 uint8_t maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
894 for (const auto& sta : GetLink(linkId).staList)
895 {
896 if (remoteStationManager->GetVhtSupported(sta.second))
897 {
898 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
899 {
900 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
901 }
902 }
903 }
904 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
905 {
906 uint8_t maxMcs =
907 9; // TBD: hardcode to 9 for now since we assume all MCS values are supported
908 operation.SetMaxVhtMcsPerNss(nss, maxMcs);
909 }
910
911 return operation;
912}
913
915ApWifiMac::GetHeOperation(uint8_t linkId) const
916{
917 NS_LOG_FUNCTION(this << +linkId);
919 HeOperation operation;
920 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
921
922 uint8_t maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
923 for (const auto& sta : GetLink(linkId).staList)
924 {
925 if (remoteStationManager->GetHeSupported(sta.second))
926 {
927 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
928 {
929 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
930 }
931 }
932 }
933 for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
934 {
935 operation.SetMaxHeMcsPerNss(
936 nss,
937 11); // TBD: hardcode to 11 for now since we assume all MCS values are supported
938 }
939 operation.SetBssColor(GetHeConfiguration()->GetBssColor());
940
941 return operation;
942}
943
945ApWifiMac::GetEhtOperation(uint8_t linkId) const
946{
947 NS_LOG_FUNCTION(this << +linkId);
949 EhtOperation operation;
950 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
951
952 auto maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
953 for (const auto& sta : GetLink(linkId).staList)
954 {
955 if (remoteStationManager->GetEhtSupported(sta.second))
956 {
957 if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
958 {
959 maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
960 }
961 }
962 }
963 operation.SetMaxRxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
964 operation.SetMaxTxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
965 return operation;
966}
967
968void
970{
971 NS_LOG_FUNCTION(this << to << +linkId);
972 WifiMacHeader hdr;
974 hdr.SetAddr1(to);
975 hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
976 hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
977 hdr.SetDsNotFrom();
978 hdr.SetDsNotTo();
979 Ptr<Packet> packet = Create<Packet>();
981 probe.Get<Ssid>() = GetSsid();
982 auto supportedRates = GetSupportedRates(linkId);
983 probe.Get<SupportedRates>() = supportedRates.rates;
984 probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
986 probe.Capabilities() = GetCapabilities(linkId);
987 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(
988 GetLink(linkId).shortPreambleEnabled);
989 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
990 GetLink(linkId).shortSlotTimeEnabled);
991 if (GetDsssSupported(linkId))
992 {
993 probe.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
994 }
995 if (GetErpSupported(linkId))
996 {
997 probe.Get<ErpInformation>() = GetErpInformation(linkId);
998 }
999 if (GetQosSupported())
1000 {
1001 probe.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1002 }
1003 if (GetHtSupported())
1004 {
1006 probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1007 probe.Get<HtOperation>() = GetHtOperation(linkId);
1008 }
1009 if (GetVhtSupported(linkId))
1010 {
1011 probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1012 probe.Get<VhtOperation>() = GetVhtOperation(linkId);
1013 }
1014 if (GetHeSupported())
1015 {
1016 probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1017 probe.Get<HeOperation>() = GetHeOperation(linkId);
1018 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1019 {
1020 probe.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1021 }
1022 }
1023 if (GetEhtSupported())
1024 {
1025 probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1026 probe.Get<EhtOperation>() = GetEhtOperation(linkId);
1027
1028 if (GetNLinks() > 1)
1029 {
1030 /*
1031 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1032 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1033 * include a TBTT Information field in a Reduced Neighbor Report element with the
1034 * TBTT Information Length field set to 16 or higher, for each of the other APs
1035 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1036 */
1037 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1038 {
1039 probe.Get<ReducedNeighborReport>() = std::move(*rnr);
1040 }
1041 /*
1042 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1043 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1044 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1045 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1046 * channel switching, extended channel switching, and channel quieting) are
1047 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1048 */
1049 probe.Get<MultiLinkElement>() =
1051 }
1052 }
1053 packet->AddHeader(probe);
1054
1055 if (!GetQosSupported())
1056 {
1057 GetTxop()->Queue(packet, hdr);
1058 }
1059 // "A QoS STA that transmits a Management frame determines access category used
1060 // for medium access in transmission of the Management frame as follows
1061 // (If dot11QMFActivated is false or not present)
1062 // — If the Management frame is individually addressed to a non-QoS STA, category
1063 // AC_BE should be selected.
1064 // — If category AC_BE was not selected by the previous step, category AC_VO
1065 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1066 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1067 {
1068 GetBEQueue()->Queue(packet, hdr);
1069 }
1070 else
1071 {
1072 GetVOQueue()->Queue(packet, hdr);
1073 }
1074}
1075
1078{
1080 StatusCode code;
1081 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1082 if (remoteStationManager->IsWaitAssocTxOk(to))
1083 {
1084 code.SetSuccess();
1085 }
1086 else
1087 {
1088 NS_ABORT_IF(!remoteStationManager->IsAssocRefused(to));
1089 // reset state
1090 remoteStationManager->RecordDisassociated(to);
1091 code.SetFailure();
1092 }
1093 auto supportedRates = GetSupportedRates(linkId);
1094 assoc.Get<SupportedRates>() = supportedRates.rates;
1095 assoc.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1096 assoc.SetStatusCode(code);
1097 assoc.Capabilities() = GetCapabilities(linkId);
1098 if (GetQosSupported())
1099 {
1100 assoc.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1101 }
1102 if (GetHtSupported())
1103 {
1105 assoc.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1106 assoc.Get<HtOperation>() = GetHtOperation(linkId);
1107 }
1108 if (GetVhtSupported(linkId))
1109 {
1110 assoc.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1111 assoc.Get<VhtOperation>() = GetVhtOperation(linkId);
1112 }
1113 if (GetHeSupported())
1114 {
1115 assoc.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1116 assoc.Get<HeOperation>() = GetHeOperation(linkId);
1117 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1118 {
1119 assoc.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1120 }
1121 }
1122 if (GetEhtSupported())
1123 {
1124 assoc.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1125 assoc.Get<EhtOperation>() = GetEhtOperation(linkId);
1126 // The AP MLD that accepts the requested TID-to-link mapping shall not include in the
1127 // (Re)Association Response frame the TID-to-link Mapping element.
1128 // (Sec. 35.3.7.1.8 of 802.11be D3.1).
1129 // For now, we assume that AP MLDs always accept requested TID-to-link mappings.
1130 }
1131 return assoc;
1132}
1133
1136 const Mac48Address& to,
1137 uint8_t linkId)
1138{
1139 // find all the links to setup (i.e., those for which status code is success)
1140 std::map<uint8_t /* link ID */, Mac48Address> linkIdStaAddrMap;
1141
1142 if (assoc.GetStatusCode().IsSuccess())
1143 {
1144 linkIdStaAddrMap[linkId] = to;
1145 }
1146
1147 if (const auto& mle = assoc.Get<MultiLinkElement>())
1148 {
1149 const auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1150 NS_ABORT_MSG_IF(!staMldAddress.has_value(),
1151 "Sending a Multi-Link Element to a single link device");
1152 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1153 {
1154 auto& perStaProfile = mle->GetPerStaProfile(idx);
1155 if (perStaProfile.HasAssocResponse() &&
1156 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1157 {
1158 uint8_t otherLinkId = perStaProfile.GetLinkId();
1159 auto staAddress = GetWifiRemoteStationManager(otherLinkId)
1160 ->GetAffiliatedStaAddress(*staMldAddress);
1161 NS_ABORT_MSG_IF(!staAddress.has_value(),
1162 "No STA to associate with on link " << +otherLinkId);
1163 const auto [it, inserted] = linkIdStaAddrMap.insert({otherLinkId, *staAddress});
1164 NS_ABORT_MSG_IF(!inserted,
1165 "More than one Association Response to MLD "
1166 << *staMldAddress << " on link ID " << +otherLinkId);
1167 }
1168 }
1169 }
1170
1171 return linkIdStaAddrMap;
1172}
1173
1174void
1176{
1177 if (linkIdStaAddrMap.empty())
1178 {
1179 // no link to setup, nothing to do
1180 return;
1181 }
1182
1183 // check if AIDs are already allocated to the STAs that are associating
1184 std::set<uint16_t> aids;
1185 std::map<uint8_t /* link ID */, uint16_t /* AID */> linkIdAidMap;
1186
1187 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1188 {
1189 for (const auto& [aid, addr] : GetLink(id).staList)
1190 {
1191 if (addr == staAddr)
1192 {
1193 aids.insert(aid);
1194 linkIdAidMap[id] = aid;
1195 break;
1196 }
1197 }
1198 }
1199
1200 // check if an AID already assigned to an STA can be assigned to all other STAs
1201 // affiliated with the non-AP MLD we are associating with
1202 while (!aids.empty())
1203 {
1204 const uint16_t aid = *aids.begin();
1205 bool good = true;
1206
1207 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1208 {
1209 if (auto it = GetLink(id).staList.find(aid);
1210 it != GetLink(id).staList.end() && it->second != staAddr)
1211 {
1212 // the AID is already assigned to an STA other than the one affiliated
1213 // with the non-AP MLD we are associating with
1214 aids.erase(aids.begin());
1215 good = false;
1216 break;
1217 }
1218 }
1219
1220 if (good)
1221 {
1222 break;
1223 }
1224 }
1225
1226 uint16_t aid = 0;
1227
1228 if (!aids.empty())
1229 {
1230 // one of the AIDs already assigned to an STA can be assigned to all the other
1231 // STAs affiliated with the non-AP MLD we are associating with
1232 aid = *aids.begin();
1233 }
1234 else
1235 {
1236 std::list<uint8_t> linkIds;
1237 std::transform(linkIdStaAddrMap.cbegin(),
1238 linkIdStaAddrMap.cend(),
1239 std::back_inserter(linkIds),
1240 [](auto&& linkIdStaAddrPair) { return linkIdStaAddrPair.first; });
1241 aid = GetNextAssociationId(linkIds);
1242 }
1243
1244 // store the MLD or link address in the AID-to-address map
1245 const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
1247 GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1248
1249 for (const auto& [id, staAddr] : linkIdStaAddrMap)
1250 {
1251 auto remoteStationManager = GetWifiRemoteStationManager(id);
1252 auto& link = GetLink(id);
1253
1254 if (auto it = linkIdAidMap.find(id); it == linkIdAidMap.end() || it->second != aid)
1255 {
1256 // the STA on this link has no AID assigned or has a different AID assigned
1257 link.staList.insert(std::make_pair(aid, staAddr));
1258 m_assocLogger(aid, staAddr);
1259 remoteStationManager->SetAssociationId(staAddr, aid);
1260
1261 if (it == linkIdAidMap.end())
1262 {
1263 // the STA on this link had no AID assigned
1264 if (remoteStationManager->GetDsssSupported(staAddr) &&
1265 !remoteStationManager->GetErpOfdmSupported(staAddr))
1266 {
1267 link.numNonErpStations++;
1268 }
1269 if (!remoteStationManager->GetHtSupported(staAddr))
1270 {
1271 link.numNonHtStations++;
1272 }
1275 }
1276 else
1277 {
1278 // the STA on this link had a different AID assigned
1279 link.staList.erase(it->second); // free the previous AID
1280 }
1281 }
1282 }
1283
1284 // set the AID in all the Association Responses. NOTE that the Association
1285 // Responses included in the Per-STA Profile Subelements of the Multi-Link
1286 // Element must not contain the AID field. We set the AID field in such
1287 // Association Responses anyway, in order to ease future implementation of
1288 // the inheritance mechanism.
1289 if (assoc.GetStatusCode().IsSuccess())
1290 {
1291 assoc.SetAssociationId(aid);
1292 }
1293 if (const auto& mle = assoc.Get<MultiLinkElement>())
1294 {
1295 for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1296 {
1297 if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1298 perStaProfile.HasAssocResponse() &&
1299 perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1300 {
1301 perStaProfile.GetAssocResponse().SetAssociationId(aid);
1302 }
1303 }
1304 }
1305}
1306
1307void
1308ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1309{
1310 NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1311 WifiMacHeader hdr;
1314 hdr.SetAddr1(to);
1317 hdr.SetDsNotFrom();
1318 hdr.SetDsNotTo();
1319
1320 MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1321
1322 // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1323 // Request frame that carries a Basic Multi-Link element shall include a Basic
1324 // Multi-Link element in the (Re)Association Response frame that it transmits
1325 // (Sec. 35.3.5.4 of 802.11be D2.0)
1326 // If the STA included a Multi-Link Element in the (Re)Association Request, we
1327 // stored its MLD address in the remote station manager
1328 if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1329 {
1330 assoc.Get<MultiLinkElement>() = GetMultiLinkElement(linkId, hdr.GetType(), to);
1331 }
1332
1333 auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1334 SetAid(assoc, linkIdStaAddrMap);
1335
1336 Ptr<Packet> packet = Create<Packet>();
1337 packet->AddHeader(assoc);
1338
1339 if (!GetQosSupported())
1340 {
1341 GetTxop()->Queue(packet, hdr);
1342 }
1343 // "A QoS STA that transmits a Management frame determines access category used
1344 // for medium access in transmission of the Management frame as follows
1345 // (If dot11QMFActivated is false or not present)
1346 // — If the Management frame is individually addressed to a non-QoS STA, category
1347 // AC_BE should be selected.
1348 // — If category AC_BE was not selected by the previous step, category AC_VO
1349 // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1350 else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1351 {
1352 GetBEQueue()->Queue(packet, hdr);
1353 }
1354 else
1355 {
1356 GetVOQueue()->Queue(packet, hdr);
1357 }
1358}
1359
1360void
1362{
1363 NS_LOG_FUNCTION(this << +linkId);
1364 auto& link = GetLink(linkId);
1365 WifiMacHeader hdr;
1368 hdr.SetAddr2(link.feManager->GetAddress());
1369 hdr.SetAddr3(link.feManager->GetAddress());
1370 hdr.SetDsNotFrom();
1371 hdr.SetDsNotTo();
1372 Ptr<Packet> packet = Create<Packet>();
1373 MgtBeaconHeader beacon;
1374 beacon.Get<Ssid>() = GetSsid();
1375 auto supportedRates = GetSupportedRates(linkId);
1376 beacon.Get<SupportedRates>() = supportedRates.rates;
1377 beacon.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
1379 beacon.Capabilities() = GetCapabilities(linkId);
1380 GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1381 GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1382 if (GetDsssSupported(linkId))
1383 {
1384 beacon.Get<DsssParameterSet>() = GetDsssParameterSet(linkId);
1385 }
1386 if (GetErpSupported(linkId))
1387 {
1388 beacon.Get<ErpInformation>() = GetErpInformation(linkId);
1389 }
1390 if (GetQosSupported())
1391 {
1392 beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
1393 }
1394 if (GetHtSupported())
1395 {
1397 beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
1398 beacon.Get<HtOperation>() = GetHtOperation(linkId);
1399 }
1400 if (GetVhtSupported(linkId))
1401 {
1402 beacon.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
1403 beacon.Get<VhtOperation>() = GetVhtOperation(linkId);
1404 }
1405 if (GetHeSupported())
1406 {
1407 beacon.Get<HeCapabilities>() = GetHeCapabilities(linkId);
1408 beacon.Get<HeOperation>() = GetHeOperation(linkId);
1409 if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1410 {
1411 beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
1412 }
1413 }
1414 if (GetEhtSupported())
1415 {
1416 beacon.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
1417 beacon.Get<EhtOperation>() = GetEhtOperation(linkId);
1418
1419 if (GetNLinks() > 1)
1420 {
1421 /*
1422 * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1423 * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1424 * include a TBTT Information field in a Reduced Neighbor Report element with the
1425 * TBTT Information Length field set to 16 or higher, for each of the other APs
1426 * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1427 */
1428 if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1429 {
1430 beacon.Get<ReducedNeighborReport>() = std::move(*rnr);
1431 }
1432 /*
1433 * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1434 * shall include, in a Beacon frame or a Probe Response frame, which is not a
1435 * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1436 * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1437 * channel switching, extended channel switching, and channel quieting) are
1438 * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1439 */
1441 }
1442 }
1443 packet->AddHeader(beacon);
1444
1445 // The beacon has it's own special queue, so we load it in there
1446 m_beaconTxop->Queue(packet, hdr);
1447 link.beaconEvent =
1449
1450 // If a STA that does not support Short Slot Time associates,
1451 // the AP shall use long slot time beginning at the first Beacon
1452 // subsequent to the association of the long slot time STA.
1453 if (GetErpSupported(linkId))
1454 {
1455 if (link.shortSlotTimeEnabled)
1456 {
1457 // Enable short slot time
1458 GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1459 }
1460 else
1461 {
1462 // Disable short slot time
1463 GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1464 }
1465 }
1466}
1467
1468void
1470{
1471 NS_LOG_FUNCTION(this << *mpdu);
1472 const WifiMacHeader& hdr = mpdu->GetHeader();
1473
1474 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1475 {
1476 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1477 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1478
1479 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1480 {
1481 NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
1482 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxOk(hdr.GetAddr1());
1483 }
1484
1485 if (auto staMldAddress =
1486 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1487 staMldAddress.has_value())
1488 {
1500 for (uint8_t i = 0; i < GetNLinks(); i++)
1501 {
1502 auto stationManager = GetWifiRemoteStationManager(i);
1503 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1504 staAddress.has_value() && i != *linkId &&
1505 stationManager->IsWaitAssocTxOk(*staAddress))
1506 {
1508 << " associated with STA=" << *staAddress);
1509 stationManager->RecordGotAssocTxOk(*staAddress);
1510 StaSwitchingToPsMode(*staAddress, i);
1511 }
1512 }
1513
1514 // Apply the negotiated TID-to-Link Mapping (if any) for DL direction
1516 }
1517 }
1518 else if (hdr.IsAction())
1519 {
1520 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
1521 category == WifiActionHeader::PROTECTED_EHT &&
1522 action.protectedEhtAction ==
1524 {
1525 // the EMLSR client acknowledged the EML Operating Mode Notification frame;
1526 // we can stop the timer and enforce the configuration deriving from the
1527 // EML Notification frame sent by the EMLSR client
1528 if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
1529 eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsRunning())
1530 {
1531 // no need to wait until the expiration of the transition timeout
1532 eventIt->second.PeekEventImpl()->Invoke();
1533 eventIt->second.Cancel();
1534 }
1535 }
1536 }
1537}
1538
1539void
1541{
1542 NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
1543 const WifiMacHeader& hdr = mpdu->GetHeader();
1544
1545 if (hdr.IsAssocResp() || hdr.IsReassocResp())
1546 {
1547 auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1548 NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1549
1550 if (GetWifiRemoteStationManager(*linkId)->IsWaitAssocTxOk(hdr.GetAddr1()))
1551 {
1552 NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
1553 << " association failed with STA=" << hdr.GetAddr1());
1554 GetWifiRemoteStationManager(*linkId)->RecordGotAssocTxFailed(hdr.GetAddr1());
1555 }
1556
1557 if (auto staMldAddress =
1558 GetWifiRemoteStationManager(*linkId)->GetMldAddress(hdr.GetAddr1());
1559 staMldAddress.has_value())
1560 {
1561 // the STA is affiliated with an MLD
1562 for (uint8_t i = 0; i < GetNLinks(); i++)
1563 {
1564 auto stationManager = GetWifiRemoteStationManager(i);
1565 if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1566 staAddress.has_value() && i != *linkId &&
1567 stationManager->IsWaitAssocTxOk(*staAddress))
1568 {
1570 << " association failed with STA=" << *staAddress);
1571 stationManager->RecordGotAssocTxFailed(*staAddress);
1572 }
1573 }
1574 }
1575 }
1576}
1577
1578void
1580{
1581 NS_LOG_FUNCTION(this << *mpdu << linkId);
1582
1583 Mac48Address staAddr = mpdu->GetHeader().GetAddr2();
1584 bool staInPsMode = GetWifiRemoteStationManager(linkId)->IsInPsMode(staAddr);
1585
1586 if (!staInPsMode && mpdu->GetHeader().IsPowerManagement())
1587 {
1588 // the sending STA is switching to Power Save mode
1589 StaSwitchingToPsMode(staAddr, linkId);
1590 }
1591 else if (staInPsMode && !mpdu->GetHeader().IsPowerManagement())
1592 {
1593 // the sending STA is switching back to Active mode
1595 }
1596}
1597
1598void
1599ApWifiMac::StaSwitchingToPsMode(const Mac48Address& staAddr, uint8_t linkId)
1600{
1601 NS_LOG_FUNCTION(this << staAddr << linkId);
1602
1603 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, true);
1604
1605 // Block frames addressed to the STA in PS mode
1606 NS_LOG_DEBUG("Block destination " << staAddr << " on link " << +linkId);
1607 auto staMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1609}
1610
1611void
1613{
1614 NS_LOG_FUNCTION(this << staAddr << linkId);
1615
1616 GetWifiRemoteStationManager(linkId)->SetPsMode(staAddr, false);
1617
1618 if (GetWifiRemoteStationManager(linkId)->IsAssociated(staAddr))
1619 {
1620 // the station is still associated, unblock its frames
1621 NS_LOG_DEBUG("Unblock destination " << staAddr << " on link " << +linkId);
1622 auto staMldAddr =
1623 GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1625 }
1626}
1627
1628std::optional<uint8_t>
1630{
1631 for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
1632 {
1633 if (GetWifiRemoteStationManager(linkId)->IsAssociated(address))
1634 {
1635 return linkId;
1636 }
1637 }
1638 NS_LOG_DEBUG(address << " is not associated");
1639 return std::nullopt;
1640}
1641
1644{
1645 auto linkId = IsAssociated(remoteAddr);
1646 NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
1647 return GetFrameExchangeManager(*linkId)->GetAddress();
1648}
1649
1650std::optional<Mac48Address>
1652{
1653 if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
1654 staIt != m_aidToMldOrLinkAddress.cend())
1655 {
1656 return staIt->second;
1657 }
1658 return std::nullopt;
1659}
1660
1661void
1663{
1664 NS_LOG_FUNCTION(this << *mpdu << +linkId);
1665 // consider the MAC header of the original MPDU (makes a difference for data frames only)
1666 const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1667 Ptr<const Packet> packet = mpdu->GetPacket();
1668 Mac48Address from = hdr->GetAddr2();
1669 if (hdr->IsData())
1670 {
1671 std::optional<uint8_t> apLinkId;
1672 if (!hdr->IsFromDs() && hdr->IsToDs() &&
1673 (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
1674 mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
1675 {
1676 // this MPDU is being acknowledged by the AP, so we can process
1677 // the Power Management flag
1678 ProcessPowerManagementFlag(mpdu, *apLinkId);
1679
1680 Mac48Address to = hdr->GetAddr3();
1681 // Address3 can be our MLD address (e.g., this is an MPDU containing a single MSDU
1682 // addressed to us) or a BSSID (e.g., this is an MPDU containing an A-MSDU)
1683 if (to == GetAddress() ||
1684 (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
1685 {
1686 NS_LOG_DEBUG("frame for me from=" << from);
1687 if (hdr->IsQosData())
1688 {
1689 if (hdr->IsQosAmsdu())
1690 {
1691 NS_LOG_DEBUG("Received A-MSDU from=" << from
1692 << ", size=" << packet->GetSize());
1694 packet = nullptr;
1695 }
1696 else if (hdr->HasData())
1697 {
1698 ForwardUp(packet, from, GetAddress());
1699 }
1700 }
1701 else if (hdr->HasData())
1702 {
1703 ForwardUp(packet, from, GetAddress());
1704 }
1705 }
1706 else if (to.IsGroup() || IsAssociated(to))
1707 {
1708 NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
1709 Ptr<Packet> copy = packet->Copy();
1710
1711 // If the frame we are forwarding is of type QoS Data,
1712 // then we need to preserve the UP in the QoS control
1713 // header...
1714 if (hdr->IsQosData())
1715 {
1716 ForwardDown(copy, from, to, hdr->GetQosTid());
1717 }
1718 else
1719 {
1720 ForwardDown(copy, from, to);
1721 }
1722 ForwardUp(packet, from, to);
1723 }
1724 else if (hdr->HasData())
1725 {
1726 ForwardUp(packet, from, to);
1727 }
1728 }
1729 else if (hdr->IsFromDs() && hdr->IsToDs())
1730 {
1731 // this is an AP-to-AP frame
1732 // we ignore for now.
1733 NotifyRxDrop(packet);
1734 }
1735 else
1736 {
1737 // we can ignore these frames since
1738 // they are not targeted at the AP
1739 NotifyRxDrop(packet);
1740 }
1741 return;
1742 }
1743 else if (hdr->IsMgt())
1744 {
1745 if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress() &&
1747 {
1748 // this MPDU is being acknowledged by the AP, so we can process
1749 // the Power Management flag
1750 ProcessPowerManagementFlag(mpdu, linkId);
1751 }
1752 if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
1753 hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
1754 {
1755 // In the case where the Address 1 field contains a group address, the
1756 // Address 3 field also is validated to verify that the group addressed
1757 // frame originated from a STA in the BSS of which the receiving STA is
1758 // a member (Section 9.3.3.1 of 802.11-2020)
1759 if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
1760 hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
1761 {
1762 // not addressed to us
1763 return;
1764 }
1765 MgtProbeRequestHeader probeRequestHeader;
1766 packet->PeekHeader(probeRequestHeader);
1767 const auto& ssid = probeRequestHeader.Get<Ssid>();
1768 if (ssid == GetSsid() || ssid->IsBroadcast())
1769 {
1770 NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
1771 SendProbeResp(from, linkId);
1772 }
1773 return;
1774 }
1775 else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
1776 {
1777 switch (hdr->GetType())
1778 {
1781 NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
1782 << " request received from " << from
1783 << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
1784
1785 MgtAssocRequestHeader assocReq;
1786 MgtReassocRequestHeader reassocReq;
1787 AssocReqRefVariant frame = assocReq;
1788 if (hdr->IsAssocReq())
1789 {
1790 packet->PeekHeader(assocReq);
1791 }
1792 else
1793 {
1794 packet->PeekHeader(reassocReq);
1795 frame = reassocReq;
1796 }
1797 if (ReceiveAssocRequest(frame, from, linkId) && GetNLinks() > 1)
1798 {
1799 ParseReportedStaInfo(frame, from, linkId);
1800 }
1801 SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
1802 return;
1803 }
1805 NS_LOG_DEBUG("Disassociation received from " << from);
1806 GetWifiRemoteStationManager(linkId)->RecordDisassociated(from);
1807 auto& staList = GetLink(linkId).staList;
1808 for (auto it = staList.begin(); it != staList.end(); ++it)
1809 {
1810 if (it->second == from)
1811 {
1812 staList.erase(it);
1813 m_deAssocLogger(it->first, it->second);
1814 if (GetWifiRemoteStationManager(linkId)->GetDsssSupported(from) &&
1815 !GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(from))
1816 {
1817 GetLink(linkId).numNonErpStations--;
1818 }
1819 if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from))
1820 {
1821 GetLink(linkId).numNonHtStations--;
1822 }
1826 break;
1827 }
1828 }
1829 return;
1830 }
1831 case WIFI_MAC_MGT_ACTION: {
1832 auto pkt = mpdu->GetPacket()->Copy();
1833 auto [category, action] = WifiActionHeader::Remove(pkt);
1834 if (category == WifiActionHeader::PROTECTED_EHT &&
1835 action.protectedEhtAction ==
1837 IsAssociated(hdr->GetAddr2()))
1838 {
1839 // received an EML Operating Mode Notification frame from an associated station
1840 MgtEmlOmn frame;
1841 pkt->RemoveHeader(frame);
1842 ReceiveEmlOmn(frame, hdr->GetAddr2(), linkId);
1843 return;
1844 }
1845 break;
1846 }
1847 default:;
1848 // do nothing
1849 }
1850 }
1851 }
1852
1853 // Invoke the receive handler of our parent class to deal with any
1854 // other frames. Specifically, this will handle Block Ack-related
1855 // Management Action frames.
1856 WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
1857}
1858
1859bool
1861 const Mac48Address& from,
1862 uint8_t linkId)
1863{
1864 NS_LOG_FUNCTION(this << from << +linkId);
1865
1866 auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1867
1868 auto failure = [&](const std::string& msg) -> bool {
1869 NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
1870 remoteStationManager->RecordAssocRefused(from);
1871 return false;
1872 };
1873
1874 // lambda to process received (Re)Association Request
1875 auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
1876 const auto& frame = frameRefWrapper.get();
1877
1878 // first, verify that the the station's supported
1879 // rate set is compatible with our Basic Rate set
1880 const CapabilityInformation& capabilities = frame.Capabilities();
1881 remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
1882 NS_ASSERT(frame.template Get<SupportedRates>());
1883 const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1884 frame.template Get<ExtendedSupportedRatesIE>()};
1885
1886 if (rates.GetNRates() == 0)
1887 {
1888 return failure("STA's supported rate set not compatible with our Basic Rate set");
1889 }
1890
1891 if (GetHtSupported())
1892 {
1893 // check whether the HT STA supports all MCSs in Basic MCS Set
1894 const auto& htCapabilities = frame.template Get<HtCapabilities>();
1895 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
1896 {
1897 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
1898 {
1899 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
1900 if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
1901 {
1902 return failure("HT STA does not support all MCSs in Basic MCS Set");
1903 }
1904 }
1905 }
1906 }
1907 if (GetVhtSupported(linkId))
1908 {
1909 // check whether the VHT STA supports all MCSs in Basic MCS Set
1910 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1911 if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
1912 {
1913 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
1914 {
1915 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
1916 if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
1917 {
1918 return failure("VHT STA does not support all MCSs in Basic MCS Set");
1919 }
1920 }
1921 }
1922 }
1923 if (GetHeSupported())
1924 {
1925 // check whether the HE STA supports all MCSs in Basic MCS Set
1926 const auto& heCapabilities = frame.template Get<HeCapabilities>();
1927 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1928 {
1929 for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
1930 {
1931 WifiMode mcs = remoteStationManager->GetBasicMcs(i);
1932 if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
1933 {
1934 return failure("HE STA does not support all MCSs in Basic MCS Set");
1935 }
1936 }
1937 }
1938 }
1939 if (GetEhtSupported())
1940 {
1941 // TODO check whether the EHT STA supports all MCSs in Basic MCS Set
1942 auto ehtConfig = GetEhtConfiguration();
1943 NS_ASSERT(ehtConfig);
1944
1945 if (const auto& tidLinkMapping = frame.template Get<TidToLinkMapping>();
1946 !tidLinkMapping.empty())
1947 {
1948 // non-AP MLD included TID-to-Link Mapping IE(s) in the Association Request.
1949 // We refuse association if we do not support TID-to-Link mapping negotiation
1950 // or the non-AP MLD included more than two TID-to-Link Mapping IEs
1951 // or we support negotiation type 1 but TIDs are mapped onto distinct link sets
1952 // or there is some TID that is not mapped to any link
1953 // or the direction(s) is/are not set properly
1954 if (tidLinkMapping.size() > 2)
1955 {
1956 return failure("More than two TID-to-Link Mapping IEs");
1957 }
1958
1959 // if only one Tid-to-Link Mapping element is present, it must be valid for
1960 // both directions
1961 bool bothDirIfOneTlm =
1962 tidLinkMapping.size() != 1 ||
1963 tidLinkMapping[0].m_control.direction == WifiDirection::BOTH_DIRECTIONS;
1964 // An MLD that includes two TID-To-Link Mapping elements in a (Re)Association
1965 // Request frame or a (Re)Association Response frame shall set the Direction
1966 // subfield in one of the TID-To-Link Mapping elements to 0 and the Direction
1967 // subfield in the other TID-To- Link Mapping element to 1.
1968 // (Sec. 35.3.7.1.8 of 802.11be D3.1)
1969 bool distinctDirsIfTwoTlms =
1970 tidLinkMapping.size() != 2 ||
1971 (tidLinkMapping[0].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
1972 tidLinkMapping[1].m_control.direction != WifiDirection::BOTH_DIRECTIONS &&
1973 tidLinkMapping[0].m_control.direction !=
1974 tidLinkMapping[1].m_control.direction);
1975
1976 if (!bothDirIfOneTlm || !distinctDirsIfTwoTlms)
1977 {
1978 return failure("Incorrect directions in TID-to-Link Mapping IEs");
1979 }
1980
1982 ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
1983
1984 if (negSupport.Get() == 0)
1985 {
1986 return failure("TID-to-Link Mapping negotiation not supported");
1987 }
1988
1989 auto getMapping = [](const TidToLinkMapping& tlmIe, WifiTidLinkMapping& mapping) {
1990 if (tlmIe.m_control.defaultMapping)
1991 {
1992 return;
1993 }
1994 for (uint8_t tid = 0; tid < 8; tid++)
1995 {
1996 if (auto linkSet = tlmIe.GetLinkMappingOfTid(tid); !linkSet.empty())
1997 {
1998 mapping.emplace(tid, std::move(linkSet));
1999 }
2000 }
2001 };
2002
2003 WifiTidLinkMapping dlMapping;
2004 WifiTidLinkMapping ulMapping;
2005
2006 switch (tidLinkMapping[0].m_control.direction)
2007 {
2009 getMapping(tidLinkMapping.at(0), dlMapping);
2010 ulMapping = dlMapping;
2011 break;
2013 getMapping(tidLinkMapping.at(0), dlMapping);
2014 getMapping(tidLinkMapping.at(1), ulMapping);
2015 break;
2017 getMapping(tidLinkMapping.at(0), ulMapping);
2018 getMapping(tidLinkMapping.at(1), dlMapping);
2019 break;
2020 }
2021
2022 if (negSupport.Get() == 1 &&
2023 !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
2024 {
2025 return failure("Mapping TIDs to distinct link sets is incompatible with "
2026 "negotiation support of 1");
2027 }
2028
2029 // otherwise, we accept the TID-to-link Mapping and store it
2030 const auto& mle = frame.template Get<MultiLinkElement>();
2031 NS_ASSERT_MSG(mle,
2032 "Multi-Link Element not present in an Association Request including "
2033 "TID-to-Link Mapping element(s)");
2034 auto mldAddr = mle->GetMldMacAddress();
2035
2036 // The requested link mappings are valid and can be accepted; store them.
2038 UpdateTidToLinkMapping(mldAddr, WifiDirection::UPLINK, ulMapping);
2039 }
2040 }
2041
2042 // The association request from the station can be accepted.
2043 // Record all its supported modes in its associated WifiRemoteStation
2044 auto phy = GetWifiPhy(linkId);
2045
2046 for (const auto& mode : phy->GetModeList())
2047 {
2048 if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
2049 {
2050 remoteStationManager->AddSupportedMode(from, mode);
2051 }
2052 }
2053 if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
2054 capabilities.IsShortSlotTime())
2055 {
2056 remoteStationManager->AddSupportedErpSlotTime(from, true);
2057 }
2058 if (GetHtSupported())
2059 {
2060 const auto& htCapabilities = frame.template Get<HtCapabilities>();
2061 if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
2062 {
2063 remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
2064 }
2065 // const ExtendedCapabilities& extendedCapabilities = frame.GetExtendedCapabilities();
2066 // TODO: to be completed
2067 }
2068 if (GetVhtSupported(linkId))
2069 {
2070 const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
2071 // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
2072 // to check whether it supports VHT
2073 if (vhtCapabilities.has_value() &&
2074 vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
2075 {
2076 remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
2077 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
2078 {
2079 if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2080 {
2081 remoteStationManager->AddSupportedMcs(from, mcs);
2082 // here should add a control to add basic MCS when it is implemented
2083 }
2084 }
2085 }
2086 }
2087 if (GetHeSupported())
2088 {
2089 const auto& heCapabilities = frame.template Get<HeCapabilities>();
2090 if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
2091 {
2092 remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
2093 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
2094 {
2095 if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
2096 {
2097 remoteStationManager->AddSupportedMcs(from, mcs);
2098 // here should add a control to add basic MCS when it is implemented
2099 }
2100 }
2101 }
2102 }
2103 if (GetEhtSupported())
2104 {
2105 if (const auto& ehtCapabilities = frame.template Get<EhtCapabilities>())
2106 {
2107 remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
2108 }
2109 for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
2110 {
2111 // TODO: Add check whether MCS is supported from the capabilities
2112 remoteStationManager->AddSupportedMcs(from, mcs);
2113 // here should add a control to add basic MCS when it is implemented
2114 }
2115 }
2116
2117 NS_LOG_DEBUG("Association Request from " << from << " accepted");
2118 remoteStationManager->RecordWaitAssocTxOk(from);
2119 return true;
2120 };
2121
2122 return std::visit(recvAssocRequest, assoc);
2123}
2124
2125void
2127{
2128 NS_LOG_FUNCTION(this << from << +linkId);
2129
2130 // lambda to process received Multi-Link Element
2131 auto recvMle = [&](auto&& frame) {
2132 const auto& mle = frame.get().template Get<MultiLinkElement>();
2133
2134 if (!mle.has_value())
2135 {
2136 return;
2137 }
2138
2139 auto mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
2140 GetWifiRemoteStationManager(linkId)->AddStationMleCommonInfo(from, mleCommonInfo);
2141
2142 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
2143 {
2144 auto& perStaProfile = mle->GetPerStaProfile(i);
2145 if (!perStaProfile.HasStaMacAddress())
2146 {
2147 NS_LOG_DEBUG("[i=" << i
2148 << "] Cannot setup a link if the STA MAC address is missing");
2149 continue;
2150 }
2151 uint8_t newLinkId = perStaProfile.GetLinkId();
2152 if (newLinkId == linkId || newLinkId >= GetNLinks())
2153 {
2154 NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
2155 continue;
2156 }
2157 if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
2158 {
2159 NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
2160 continue;
2161 }
2162
2163 ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
2164 perStaProfile.GetStaMacAddress(),
2165 newLinkId);
2166 GetWifiRemoteStationManager(newLinkId)->AddStationMleCommonInfo(
2167 perStaProfile.GetStaMacAddress(),
2168 mleCommonInfo);
2169 }
2170 };
2171
2172 std::visit(recvMle, assoc);
2173}
2174
2175void
2176ApWifiMac::ReceiveEmlOmn(MgtEmlOmn& frame, const Mac48Address& sender, uint8_t linkId)
2177{
2178 NS_LOG_FUNCTION(this << frame << sender << linkId);
2179
2180 auto ehtConfiguration = GetEhtConfiguration();
2181
2182 if (BooleanValue emlsrActivated;
2183 !ehtConfiguration ||
2184 !ehtConfiguration->GetAttributeFailSafe("EmlsrActivated", emlsrActivated) ||
2185 !emlsrActivated.Get())
2186 {
2188 "Received an EML Operating Mode Notification frame but EMLSR is not activated");
2189 return;
2190 }
2191
2193 {
2195 auto emlCapabilities =
2196 GetWifiRemoteStationManager(linkId)->GetStationEmlCapabilities(sender);
2197 NS_ASSERT_MSG(emlCapabilities, "EML Capabilities not stored for STA " << sender);
2198
2199 // update values stored in remote station manager
2200 emlCapabilities->get().emlsrPaddingDelay = frame.m_emlsrParamUpdate->paddingDelay;
2201 emlCapabilities->get().emlsrTransitionDelay = frame.m_emlsrParamUpdate->transitionDelay;
2202 }
2203
2204 auto mldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(sender);
2205 NS_ASSERT_MSG(mldAddress, "No MLD address stored for STA " << sender);
2206 auto emlsrLinks =
2207 frame.m_emlControl.emlsrMode == 1 ? frame.GetLinkBitmap() : std::list<uint8_t>{};
2208
2209 // The AP MLD has to consider the changes carried by the received EML Notification frame
2210 // as effective at the same time as the non-AP MLD. Therefore, we need to start a time
2211 // when the transmission of the Ack following the received EML Notification frame is
2212 // completed. For this purpose, we connect a callback to the PHY TX begin trace to catch
2213 // the Ack transmitted after the EML Notification frame.
2215 [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, double /* txPowerW */) {
2216 NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
2217 psduMap.begin()->second->GetHeader(0).IsAck(),
2218 "Expected a Normal Ack after EML Notification frame");
2219
2220 auto ackDuration =
2221 WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
2222
2223 TimeValue transitionTimeout;
2224 ehtConfiguration->GetAttribute("TransitionTimeout", transitionTimeout);
2225
2227 Simulator::Schedule(ackDuration + transitionTimeout.Get(), [=, this]() {
2228 for (uint8_t id = 0; id < GetNLinks(); id++)
2229 {
2230 auto linkAddress =
2231 GetWifiRemoteStationManager(id)->GetAffiliatedStaAddress(*mldAddress);
2232 if (!linkAddress)
2233 {
2234 // this link has not been setup by the non-AP MLD
2235 continue;
2236 }
2237
2238 if (!emlsrLinks.empty())
2239 {
2240 // the non-AP MLD is enabling EMLSR mode
2252 auto enabled = std::find(emlsrLinks.cbegin(), emlsrLinks.cend(), id) !=
2253 emlsrLinks.cend();
2254 if (enabled)
2255 {
2256 StaSwitchingToActiveModeOrDeassociated(*linkAddress, id);
2257 }
2258 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, enabled);
2259 }
2260 else
2261 {
2262 // the non-AP MLD is disabling EMLSR mode
2275 if (id != linkId &&
2276 GetWifiRemoteStationManager(id)->GetEmlsrEnabled(*linkAddress))
2277 {
2278 StaSwitchingToPsMode(*linkAddress, id);
2279 }
2280 GetWifiRemoteStationManager(id)->SetEmlsrEnabled(*linkAddress, false);
2281 }
2282 }
2283 });
2284 });
2285
2286 // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
2287 // after its transmission begins
2288 auto phy = GetLink(linkId).phy;
2289 phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
2290 Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
2291 [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
2292
2293 // An AP MLD with dot11EHTEMLSROptionActivated equal to true sets the EMLSR Mode subfield
2294 // to the value obtained from the EMLSR Mode subfield of the received EML Operating Mode
2295 // Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2296
2297 // When included in a frame sent by an AP affiliated with an AP MLD, the EMLSR Parameter
2298 // Update Control subfield is set to 0. (Sec. 9.6.35.8 of 802.11be D3.0)
2299 frame.m_emlControl.emlsrParamUpdateCtrl = 0;
2300
2301 // An AP MLD with dot11EHTEMLSROptionImplemented equal to true sets the EMLSR Link Bitmap
2302 // subfield to the value obtained from the EMLSR Link Bitmap subfield of the received
2303 // EML Operating Mode Notification frame. (Sec. 9.6.35.8 of 802.11be D3.0)
2304
2305 // The EMLSR Parameter Update field [..] is present if [..] the Action frame is sent by
2306 // a non-AP STA affiliated with a non-AP MLD (Sec. 9.6.35.8 of 802.11be D3.0)
2307 frame.m_emlsrParamUpdate.reset();
2308
2309 auto ehtFem = StaticCast<EhtFrameExchangeManager>(GetFrameExchangeManager(linkId));
2310 ehtFem->SendEmlOmn(sender, frame);
2311}
2312
2313void
2315{
2316 NS_LOG_FUNCTION(this << *mpdu);
2317 for (auto& i : *PeekPointer(mpdu))
2318 {
2319 auto from = i.second.GetSourceAddr();
2320 auto to = i.second.GetDestinationAddr();
2321
2322 if (to.IsGroup() || IsAssociated(to))
2323 {
2324 NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
2325 ForwardDown(i.first->Copy(), from, to, mpdu->GetHeader().GetQosTid());
2326 }
2327
2328 ForwardUp(i.first, from, to);
2329 }
2330}
2331
2332void
2334{
2335 NS_LOG_FUNCTION(this);
2337
2338 for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
2339 {
2340 GetLink(linkId).beaconEvent.Cancel();
2342 {
2343 uint64_t jitterUs =
2345 ? static_cast<uint64_t>(m_beaconJitter->GetValue(0, 1) *
2347 : 0);
2348 NS_LOG_DEBUG("Scheduling initial beacon for access point "
2349 << GetAddress() << " at time " << jitterUs << "us");
2352 this,
2353 linkId);
2354 }
2357 }
2358
2363}
2364
2365bool
2367{
2368 bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
2369 GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
2370 return useProtection;
2371}
2372
2373uint16_t
2374ApWifiMac::GetNextAssociationId(std::list<uint8_t> linkIds)
2375{
2376 // Return the first AID value between 1 and 2007 that is free for all the given links
2377 for (uint16_t nextAid = 1; nextAid <= 2007; nextAid++)
2378 {
2379 if (std::all_of(linkIds.begin(), linkIds.end(), [&](auto&& linkId) {
2380 auto& staList = GetLink(linkId).staList;
2381 return staList.find(nextAid) == staList.end();
2382 }))
2383 {
2384 return nextAid;
2385 }
2386 }
2387 NS_FATAL_ERROR("No free association ID available!");
2388 return 0;
2389}
2390
2391const std::map<uint16_t, Mac48Address>&
2392ApWifiMac::GetStaList(uint8_t linkId) const
2393{
2394 return GetLink(linkId).staList;
2395}
2396
2397uint16_t
2399{
2400 return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
2401}
2402
2403uint8_t
2404ApWifiMac::GetBufferStatus(uint8_t tid, Mac48Address address) const
2405{
2406 auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
2407 if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
2408 {
2409 return 255;
2410 }
2411 return it->second.value;
2412}
2413
2414void
2415ApWifiMac::SetBufferStatus(uint8_t tid, Mac48Address address, uint8_t size)
2416{
2417 if (size == 255)
2418 {
2419 // no point in storing an unspecified size
2420 m_bufferStatus.erase(WifiAddressTidPair(address, tid));
2421 }
2422 else
2423 {
2424 m_bufferStatus[WifiAddressTidPair(address, tid)] = {size, Simulator::Now()};
2425 }
2426}
2427
2428uint8_t
2430{
2431 uint8_t maxSize = 0;
2432 bool found = false;
2433
2434 for (uint8_t tid = 0; tid < 8; tid++)
2435 {
2436 uint8_t size = GetBufferStatus(tid, address);
2437 if (size != 255)
2438 {
2439 maxSize = std::max(maxSize, size);
2440 found = true;
2441 }
2442 }
2443
2444 if (found)
2445 {
2446 return maxSize;
2447 }
2448 return 255;
2449}
2450
2451} // namespace ns3
Wi-Fi AP state machine.
Definition: ap-wifi-mac.h:65
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.
Definition: ap-wifi-mac.cc:144
Ptr< Txop > m_beaconTxop
Dedicated Txop for beacons.
Definition: ap-wifi-mac.h:519
void SetBeaconGeneration(bool enable)
Enable or disable beacon generation of the AP.
Definition: ap-wifi-mac.cc:181
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.
Definition: ap-wifi-mac.cc:244
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.
Definition: ap-wifi-mac.cc:128
void SetBeaconInterval(Time interval)
Definition: ap-wifi-mac.cc:219
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.
Definition: ap-wifi-mac.h:316
std::map< Mac48Address, EventId > m_transitionTimeoutEvents
transition timeout events running for EMLSR clients
Definition: ap-wifi-mac.h:529
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.
Definition: ap-wifi-mac.cc:484
Ptr< UniformRandomVariable > m_beaconJitter
UniformRandomVariable used to randomize the time of the first beacon.
Definition: ap-wifi-mac.h:523
bool CanForwardPacketsTo(Mac48Address to) const override
Return true if packets can be forwarded to the given destination, false otherwise.
Definition: ap-wifi-mac.cc:392
bool m_enableNonErpProtection
Flag whether protection mechanism is used or not when non-ERP STAs are present within the BSS.
Definition: ap-wifi-mac.h:525
EdcaParameterSet GetEdcaParameterSet(uint8_t linkId) const
Return the EDCA Parameter Set of the current AP for the given link.
Definition: ap-wifi-mac.cc:516
void StaSwitchingToActiveModeOrDeassociated(const Mac48Address &staAddr, uint8_t linkId)
Perform the necessary actions when a given station deassociates or switches from powersave mode to ac...
MultiLinkElement GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac48Address &to=Mac48Address::GetBroadcast())
Return the Multi-Link Element that the current AP includes in the management frames of the given type...
Definition: ap-wifi-mac.cc:662
HtOperation GetHtOperation(uint8_t linkId) const
Return the HT operation of the current AP for the given link.
Definition: ap-wifi-mac.cc:768
std::optional< Mac48Address > GetMldOrLinkAddressByAid(uint16_t aid) const
void UpdateShortPreambleEnabled(uint8_t linkId)
Update whether short preamble should be enabled or not in the BSS corresponding to the given link.
Definition: ap-wifi-mac.cc:267
void TxOk(Ptr< const WifiMpdu > mpdu)
The packet we sent was successfully received by the receiver (i.e.
std::map< uint16_t, Mac48Address > m_aidToMldOrLinkAddress
Maps AIDs to MLD addresses (for MLDs) or link addresses (in case of single link devices)
Definition: ap-wifi-mac.h:205
TracedCallback< uint16_t, Mac48Address > m_deAssocLogger
deassociation logger
Definition: ap-wifi-mac.h:550
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.
bool m_enableBeaconGeneration
Flag whether beacons are being generated.
Definition: ap-wifi-mac.h:520
Time m_beaconInterval
Beacon interval.
Definition: ap-wifi-mac.h:521
uint16_t GetNextAssociationId(std::list< uint8_t > linkIds)
bool m_enableBeaconJitter
Flag whether the first beacon should be generated at random time.
Definition: ap-wifi-mac.h:524
std::unordered_map< WifiAddressTidPair, BsrType, WifiAddressTidHash > m_bufferStatus
Per (MAC address, TID) buffer status reports.
Definition: ap-wifi-mac.h:539
void SendProbeResp(Mac48Address to, uint8_t linkId)
Send a Probe Response in response to a Probe Request received from the STA with the given address on ...
Definition: ap-wifi-mac.cc:969
DsssParameterSet GetDsssParameterSet(uint8_t linkId) const
Return the DSSS Parameter Set that we support on the given link.
Definition: ap-wifi-mac.cc:474
TracedCallback< uint16_t, Mac48Address > m_assocLogger
association logger
Definition: ap-wifi-mac.h:549
Time GetBeaconInterval() const
Definition: ap-wifi-mac.cc:200
static TypeId GetTypeId()
Get the type ID.
Definition: ap-wifi-mac.cc:58
std::optional< ReducedNeighborReport > GetReducedNeighborReport(uint8_t linkId) const
Return the Reduced Neighbor Report (RNR) element that the current AP sends on the given link,...
Definition: ap-wifi-mac.cc:631
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 ...
void Enqueue(Ptr< Packet > packet, Mac48Address to) override
Definition: ap-wifi-mac.cc:412
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.
Definition: ap-wifi-mac.h:527
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Definition: ap-wifi-mac.cc:236
ApLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: ap-wifi-mac.cc:150
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.
Definition: ap-wifi-mac.cc:945
void ConfigureStandard(WifiStandard standard) override
Definition: ap-wifi-mac.cc:156
ErpInformation GetErpInformation(uint8_t linkId) const
Return the ERP information of the current AP for the given link.
Definition: ap-wifi-mac.cc:495
void SetLinkUpCallback(Callback< void > linkUp) override
Definition: ap-wifi-mac.cc:207
VhtOperation GetVhtOperation(uint8_t linkId) const
Return the VHT operation of the current AP for the given link.
Definition: ap-wifi-mac.cc:866
~ApWifiMac() override
Definition: ap-wifi-mac.cc:122
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.
Definition: ap-wifi-mac.cc:915
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...
std::optional< MuEdcaParameterSet > GetMuEdcaParameterSet() const
Return the MU EDCA Parameter Set of the current AP, if one needs to be advertised.
Definition: ap-wifi-mac.cc:563
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
Definition: ap-wifi-mac.cc:422
MgtAssocResponseHeader GetAssocResp(Mac48Address to, uint8_t linkId)
Get the Association Response frame to send on a given link.
void ForwardDown(Ptr< Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet down to DCF/EDCAF (enqueue the packet).
Definition: ap-wifi-mac.cc:291
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,...
Definition: ap-wifi-mac.cc:171
bool GetUseNonErpProtection(uint8_t linkId) const
Return whether protection for non-ERP stations is used in the BSS corresponding to the given link.
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...
Definition: ap-wifi-mac.cc:429
AttributeValue implementation for Boolean.
Definition: boolean.h:37
bool Get() const
Definition: boolean.cc:55
Base class for Callback class.
Definition: callback.h:360
Callback template class.
Definition: callback.h:438
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.
Definition: eht-operation.h:66
void SetMaxTxNss(uint8_t maxNss, uint8_t mcsStart, uint8_t mcsEnd)
Set the max Tx NSS for input MCS index range.
void SetMaxRxNss(uint8_t maxNss, uint8_t mcsStart, uint8_t mcsEnd)
Set the max Rx NSS for input MCS index range.
Hold variables of type enum.
Definition: enum.h:62
T Get() const
Definition: enum.h:102
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:55
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
The IEEE 802.11ax HE Capabilities.
The HE Operation Information Element.
Definition: he-operation.h:36
void SetBssColor(uint8_t bssColor)
Set the BSS color.
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 tuple (n...
Definition: he-operation.cc:94
The HT Capabilities Information Element.
The HT Operation Information Element.
Definition: ht-operation.h:51
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.
Definition: ht-operation.cc:95
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.
Definition: ht-operation.cc:89
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.
Hold a signed integer type.
Definition: integer.h:45
int64_t Get() const
Definition: integer.cc:37
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
static Mac48Address GetBroadcast()
bool IsBroadcast() const
Implement the header for management frames of type association request.
Definition: mgt-headers.h:157
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:334
CapabilityInformation & Capabilities()
Definition: mgt-headers.cc:474
StatusCode GetStatusCode()
Return the status code.
Definition: mgt-headers.cc:456
void SetStatusCode(StatusCode code)
Set the status code.
Definition: mgt-headers.cc:462
void SetAssociationId(uint16_t aid)
Set the association ID.
Definition: mgt-headers.cc:480
Implement the header for management frames of type beacon.
Definition: mgt-headers.h:512
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.
Definition: mgt-headers.h:432
Implement the header for management frames of type probe response.
Definition: mgt-headers.h:451
void SetBeaconIntervalUs(uint64_t us)
Set the beacon interval in microseconds unit.
Definition: mgt-headers.cc:81
CapabilityInformation & Capabilities()
Definition: mgt-headers.cc:93
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:241
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.
Definition: object-base.cc:315
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition: object.cc:186
void Dispose()
Dispose of this Object.
Definition: object.cc:219
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
The Reduced Neighbor Report element.
std::size_t GetNNbrApInfoFields() const
Get the number of Neighbor AP Information fields.
void SetMldParameters(std::size_t nbrApInfoId, std::size_t index, uint8_t mldId, uint8_t linkId, uint8_t changeSequence)
Set the MLD Parameters subfield of the i-th TBTT Information field of the given Neighbor AP Informati...
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 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:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
Status code for association response.
Definition: status-code.h:32
bool IsSuccess() const
Return whether the status code is success.
Definition: status-code.cc:42
void SetFailure()
Set success bit to 1 (failure).
Definition: status-code.cc:36
void SetSuccess()
Set success bit to 0 (success).
Definition: status-code.cc:30
Hold variables of type string.
Definition: string.h:56
The Supported Rates Information Element.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:315
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:413
AttributeValue implementation for Time.
Definition: nstime.h:1413
Time Get() const
Definition: time.cc:530
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:231
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the wifi MAC this Txop is associated to.
Definition: txop.cc:209
void SetMaxCws(std::vector< uint32_t > maxCws)
Set the maximum contention window size for each link.
Definition: txop.cc:273
void SetTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set MacTxMiddle this Txop is associated to.
Definition: txop.cc:202
void SetMinCws(std::vector< uint32_t > minCws)
Set the minimum contention window size for each link.
Definition: txop.cc:243
void SetAifsns(std::vector< uint8_t > aifsns)
Set the number of slots that make up an AIFS for each link.
Definition: txop.cc:371
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:523
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
uint64_t Get() const
Definition: uinteger.cc:37
double GetValue(double min, double max)
Get the next random value drawn from the distribution.
The IEEE 802.11ac VHT Capabilities.
The VHT Operation Information Element.
Definition: vht-operation.h:36
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.
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.
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.
void SetQosAckPolicy(QosAckPolicy policy)
Set the QoS Ack policy in the QoS control field.
bool IsProbeReq() const
Return true if the header is a Probe Request header.
bool IsQosAmsdu() const
Check if the A-MSDU present bit is set in the QoS control field.
Mac48Address GetAddr3() const
Return the address in the Address 3 field.
bool IsAssocResp() const
Return true if the header is an Association Response header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
void SetQosTxopLimit(uint8_t txop)
Set TXOP limit in the QoS control field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
bool IsMgt() const
Return true if the Type is Management.
void SetNoOrder()
Unset order bit in the frame control field.
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.
void SetQosNoAmsdu()
Set that A-MSDU is not present.
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.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
bool IsData() const
Return true if the Type is DATA.
void SetQosNoEosp()
Un-set the end of service period (EOSP) bit in the QoS control field.
bool IsReassocResp() const
Return true if the header is a Reassociation Response header.
void SetDsFrom()
Set the From DS bit in the Frame Control field.
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:96
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:864
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition: wifi-mac.cc:533
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1632
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1749
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition: wifi-mac.cc:493
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2018
bool GetQosSupported() const
Return whether the device supports QoS.
Definition: wifi-mac.cc:1222
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:933
void DoInitialize() override
Initialize() implementation.
Definition: wifi-mac.cc:349
virtual void ConfigureStandard(WifiStandard standard)
Definition: wifi-mac.cc:748
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Definition: wifi-mac.cc:1428
Ssid GetSsid() const
Definition: wifi-mac.cc:465
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition: wifi-mac.cc:1228
bool GetHtSupported() const
Return whether the device supports HT.
Definition: wifi-mac.cc:1761
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition: wifi-mac.cc:521
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition: wifi-mac.cc:415
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1171
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Definition: wifi-mac.cc:1387
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition: wifi-mac.cc:1780
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1774
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition: wifi-mac.cc:1959
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:961
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:1305
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition: wifi-mac.cc:1755
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition: wifi-mac.cc:1767
Ptr< MacTxMiddle > m_txMiddle
TX middle (aggregation etc.)
Definition: wifi-mac.h:893
Ptr< HtConfiguration > GetHtConfiguration() const
Definition: wifi-mac.cc:1737
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:1066
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition: wifi-mac.cc:1948
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:545
bool GetShortSlotTimeSupported() const
Definition: wifi-mac.cc:1272
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:619
virtual void SetLinkUpCallback(Callback< void > linkUp)
Definition: wifi-mac.cc:1291
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:906
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition: wifi-mac.cc:1490
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:1497
Mac48Address GetAddress() const
Definition: wifi-mac.cc:452
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2158
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: wifi-mac.cc:924
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition: wifi-mac.cc:2100
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:601
void DoDispose() override
Destructor implementation.
Definition: wifi-mac.cc:373
bool GetDsssSupported(uint8_t linkId) const
Return whether the device supports DSSS on the given link.
Definition: wifi-mac.cc:1252
represent a single transmission mode
Definition: wifi-mode.h:51
std::string GetUniqueName() const
Definition: wifi-mode.cc:148
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
uint8_t GetMcsValue() const
Definition: wifi-mode.cc:163
uint8_t GetMaxSupportedRxSpatialStreams() const
Definition: wifi-phy.cc:1319
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1507
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition: wifi-phy.cc:787
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:1033
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:66
#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:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:227
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1434
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiStandard
Identifies the IEEE 802.11 specifications that a Wifi device can be configured to use.
WifiMacDropReason
The reason why an MPDU was dropped.
Definition: wifi-mac.h:77
uint8_t QosUtilsGetTidForPacket(Ptr< const Packet > packet)
If a QoS tag is attached to the packet, returns a value < 8.
Definition: qos-utils.cc:156
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:73
@ AP
Definition: wifi-mac.h:66
@ 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:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
@ AC_VI
Video.
Definition: qos-utils.h:79
@ AC_BK
Background.
Definition: qos-utils.h:77
@ AC_BEACON
Beacon queue.
Definition: qos-utils.h:85
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:449
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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:704
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:55
@ NO_PROTECTION
Definition: ht-operation.h:37
@ MIXED_MODE_PROTECTION
Definition: ht-operation.h:40
constexpr uint8_t WIFI_EHT_MAX_MCS_INDEX
IEEE 802.11be D2.0 Figure 9-1002ai.
Definition: eht-operation.h:32
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_DATA
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
@ WIFI_MAC_QOSDATA
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping &dlLinkMapping, const WifiTidLinkMapping &ulLinkMapping)
Check if the given TID-to-Link Mappings are valid for a negotiation type of 1.
Definition: wifi-utils.cc:148
std::pair< Mac48Address, uint8_t > WifiAddressTidPair
(MAC address, TID) pair
Definition: qos-utils.h:36
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:74
Struct containing all supported rates.
void SetBasicRate(uint64_t bs)
Set the given rate to basic rates.
void AddBssMembershipSelectorRate(uint64_t bs)
Add a special value to the supported rate set, corresponding to a BSS membership selector.
void AddSupportedRate(uint64_t bs)
Add the given rate to the supported rates.
std::optional< MldCapabilities > m_mldCapabilities
MLD Capabilities.
void SetMediumSyncDelayTimer(Time delay)
Set the Medium Synchronization Duration subfield of the Medium Synchronization Delay Information in t...
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.