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