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