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 "frame-exchange-manager.h"
27 #include "mac-rx-middle.h"
28 #include "mac-tx-middle.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/he-configuration.h"
39 #include "ns3/ht-configuration.h"
40 #include "ns3/log.h"
41 #include "ns3/multi-link-element.h"
42 #include "ns3/packet.h"
43 #include "ns3/pointer.h"
44 #include "ns3/random-variable-stream.h"
45 #include "ns3/simulator.h"
46 #include "ns3/string.h"
47 
48 namespace ns3
49 {
50 
51 NS_LOG_COMPONENT_DEFINE("ApWifiMac");
52 
54 
55 TypeId
57 {
58  static TypeId tid =
59  TypeId("ns3::ApWifiMac")
60  .SetParent<WifiMac>()
61  .SetGroupName("Wifi")
62  .AddConstructor<ApWifiMac>()
63  .AddAttribute(
64  "BeaconInterval",
65  "Delay between two beacons",
66  TimeValue(MicroSeconds(102400)),
69  .AddAttribute("BeaconJitter",
70  "A uniform random variable to cause the initial beacon starting time "
71  "(after simulation time 0) "
72  "to be distributed between 0 and the BeaconInterval.",
73  StringValue("ns3::UniformRandomVariable"),
75  MakePointerChecker<UniformRandomVariable>())
76  .AddAttribute("EnableBeaconJitter",
77  "If beacons are enabled, whether to jitter the initial send event.",
78  BooleanValue(true),
81  .AddAttribute("BeaconGeneration",
82  "Whether or not beacons are generated.",
83  BooleanValue(true),
86  .AddAttribute("EnableNonErpProtection",
87  "Whether or not protection mechanism should be used when non-ERP STAs "
88  "are present within the BSS."
89  "This parameter is only used when ERP is supported by the AP.",
90  BooleanValue(true),
93  .AddAttribute("BsrLifetime",
94  "Lifetime of Buffer Status Reports received from stations.",
98  .AddTraceSource("AssociatedSta",
99  "A station associated with this access point.",
101  "ns3::ApWifiMac::AssociationCallback")
102  .AddTraceSource("DeAssociatedSta",
103  "A station lost association with this access point.",
105  "ns3::ApWifiMac::AssociationCallback");
106  return tid;
107 }
108 
110  : m_enableBeaconGeneration(false)
111 {
112  NS_LOG_FUNCTION(this);
113  m_beaconTxop = CreateObject<Txop>(CreateObject<WifiMacQueue>(AC_BEACON));
115 
116  // Let the lower layers know that we are acting as an AP.
118 }
119 
121 {
122  NS_LOG_FUNCTION(this);
123 }
124 
125 void
127 {
128  NS_LOG_FUNCTION(this);
130  m_beaconTxop = nullptr;
131  m_enableBeaconGeneration = false;
133 }
134 
136 {
139 }
140 
141 std::unique_ptr<WifiMac::LinkEntity>
143 {
144  return std::make_unique<ApLinkEntity>();
145 }
146 
148 ApWifiMac::GetLink(uint8_t linkId) const
149 {
150  return static_cast<ApLinkEntity&>(WifiMac::GetLink(linkId));
151 }
152 
153 void
155 {
156  NS_LOG_FUNCTION(this << standard);
157  WifiMac::ConfigureStandard(standard);
158  m_beaconTxop->SetWifiMac(this);
159  m_beaconTxop->SetAifsns(std::vector<uint8_t>(GetNLinks(), 1));
160  m_beaconTxop->SetMinCws(std::vector<uint32_t>(GetNLinks(), 0));
161  m_beaconTxop->SetMaxCws(std::vector<uint32_t>(GetNLinks(), 0));
162  for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
163  {
165  }
166 }
167 
170 {
171  if (ac == AC_BEACON)
172  {
173  return m_beaconTxop->GetWifiMacQueue();
174  }
175  return WifiMac::GetTxopQueue(ac);
176 }
177 
178 void
180 {
181  NS_LOG_FUNCTION(this << enable);
182  for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
183  {
184  if (!enable)
185  {
186  GetLink(linkId).beaconEvent.Cancel();
187  }
188  else if (!m_enableBeaconGeneration)
189  {
190  GetLink(linkId).beaconEvent =
192  }
193  }
194  m_enableBeaconGeneration = enable;
195 }
196 
197 Time
199 {
200  NS_LOG_FUNCTION(this);
201  return m_beaconInterval;
202 }
203 
204 void
206 {
207  NS_LOG_FUNCTION(this << &linkUp);
209 
210  // The approach taken here is that, from the point of view of an AP,
211  // the link is always up, so we immediately invoke the callback if
212  // one is set
213  linkUp();
214 }
215 
216 void
218 {
219  NS_LOG_FUNCTION(this << interval);
220  if ((interval.GetMicroSeconds() % 1024) != 0)
221  {
222  NS_FATAL_ERROR("beacon interval should be multiple of 1024us (802.11 time unit), see IEEE "
223  "Std. 802.11-2012");
224  }
225  if (interval.GetMicroSeconds() > (1024 * 65535))
226  {
228  "beacon interval should be smaller then or equal to 65535 * 1024us (802.11 time unit)");
229  }
230  m_beaconInterval = interval;
231 }
232 
233 int64_t
235 {
236  NS_LOG_FUNCTION(this << stream);
237  m_beaconJitter->SetStream(stream);
238  return 1;
239 }
240 
241 void
243 {
244  NS_LOG_FUNCTION(this << +linkId);
245  auto& link = GetLink(linkId);
246  if (GetErpSupported(linkId) && GetShortSlotTimeSupported() && (link.numNonErpStations == 0))
247  {
248  for (const auto& sta : link.staList)
249  {
250  if (!GetWifiRemoteStationManager(linkId)->GetShortSlotTimeSupported(sta.second))
251  {
252  link.shortSlotTimeEnabled = false;
253  return;
254  }
255  }
256  link.shortSlotTimeEnabled = true;
257  }
258  else
259  {
260  link.shortSlotTimeEnabled = false;
261  }
262 }
263 
264 void
266 {
267  NS_LOG_FUNCTION(this << +linkId);
268  auto& link = GetLink(linkId);
269  if (GetErpSupported(linkId) && GetWifiPhy(linkId)->GetShortPhyPreambleSupported())
270  {
271  for (const auto& sta : link.staList)
272  {
273  if (!GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(sta.second) ||
274  !GetWifiRemoteStationManager(linkId)->GetShortPreambleSupported(sta.second))
275  {
276  link.shortPreambleEnabled = false;
277  return;
278  }
279  }
280  link.shortPreambleEnabled = true;
281  }
282  else
283  {
284  link.shortPreambleEnabled = false;
285  }
286 }
287 
288 void
290 {
291  NS_LOG_FUNCTION(this << packet << from << to);
292  // If we are not a QoS AP then we definitely want to use AC_BE to
293  // transmit the packet. A TID of zero will map to AC_BE (through \c
294  // QosUtilsMapTidToAc()), so we use that as our default here.
295  uint8_t tid = 0;
296 
297  // If we are a QoS AP then we attempt to get a TID for this packet
298  if (GetQosSupported())
299  {
300  tid = QosUtilsGetTidForPacket(packet);
301  // Any value greater than 7 is invalid and likely indicates that
302  // the packet had no QoS tag, so we revert to zero, which'll
303  // mean that AC_BE is used.
304  if (tid > 7)
305  {
306  tid = 0;
307  }
308  }
309 
310  ForwardDown(packet, from, to, tid);
311 }
312 
313 void
315 {
316  NS_LOG_FUNCTION(this << packet << from << to << +tid);
317  WifiMacHeader hdr;
318 
319  // For now, an AP that supports QoS does not support non-QoS
320  // associations, and vice versa. In future the AP model should
321  // support simultaneously associated QoS and non-QoS STAs, at which
322  // point there will need to be per-association QoS state maintained
323  // by the association state machine, and consulted here.
324  if (GetQosSupported())
325  {
328  hdr.SetQosNoEosp();
329  hdr.SetQosNoAmsdu();
330  // Transmission of multiple frames in the same Polled TXOP is not supported for now
331  hdr.SetQosTxopLimit(0);
332  // Fill in the QoS control field in the MAC header
333  hdr.SetQosTid(tid);
334  }
335  else
336  {
337  hdr.SetType(WIFI_MAC_DATA);
338  }
339 
340  if (GetQosSupported())
341  {
342  hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
343  // yet implemented (set it to 1 when implemented)
344  }
345 
346  std::list<Mac48Address> addr2Set;
347  if (to.IsGroup())
348  {
349  // broadcast frames are transmitted on all the links
350  for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
351  {
352  addr2Set.push_back(GetFrameExchangeManager(linkId)->GetAddress());
353  }
354  }
355  else
356  {
357  // the Transmitter Address (TA) is the MLD address only for non-broadcast data frames
358  // exchanged between two MLDs
359  addr2Set = {GetAddress()};
360  auto linkId = IsAssociated(to);
361  NS_ASSERT_MSG(linkId, "Station " << to << "is not associated, cannot send it a frame");
362  if (GetNLinks() == 1 || !GetWifiRemoteStationManager(*linkId)->GetMldAddress(to))
363  {
364  addr2Set = {GetFrameExchangeManager(*linkId)->GetAddress()};
365  }
366  }
367 
368  for (const auto& addr2 : addr2Set)
369  {
370  hdr.SetAddr1(to);
371  hdr.SetAddr2(addr2);
372  hdr.SetAddr3(from);
373  hdr.SetDsFrom();
374  hdr.SetDsNotTo();
375 
376  if (GetQosSupported())
377  {
378  // Sanity check that the TID is valid
379  NS_ASSERT(tid < 8);
380  GetQosTxop(tid)->Queue(packet, hdr);
381  }
382  else
383  {
384  GetTxop()->Queue(packet, hdr);
385  }
386  }
387 }
388 
389 bool
391 {
392  return (to.IsGroup() || IsAssociated(to));
393 }
394 
395 void
397 {
398  NS_LOG_FUNCTION(this << packet << to << from);
399  if (CanForwardPacketsTo(to))
400  {
401  ForwardDown(packet, from, to);
402  }
403  else
404  {
405  NotifyTxDrop(packet);
406  }
407 }
408 
409 void
411 {
412  NS_LOG_FUNCTION(this << packet << to);
413  // We're sending this packet with a from address that is our own. We
414  // get that address from the lower MAC and make use of the
415  // from-spoofing Enqueue() method to avoid duplicated code.
416  Enqueue(packet, to, GetAddress());
417 }
418 
419 bool
421 {
422  NS_LOG_FUNCTION(this);
423  return true;
424 }
425 
427 ApWifiMac::GetSupportedRates(uint8_t linkId) const
428 {
429  NS_LOG_FUNCTION(this << +linkId);
430  SupportedRates rates;
431  // Send the set of supported rates and make sure that we indicate
432  // the Basic Rate set in this set of supported rates.
433  for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
434  {
435  uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
436  NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
437  rates.AddSupportedRate(modeDataRate);
438  // Add rates that are part of the BSSBasicRateSet (manufacturer dependent!)
439  // here we choose to add the mandatory rates to the BSSBasicRateSet,
440  // except for 802.11b where we assume that only the non HR-DSSS rates are part of the
441  // BSSBasicRateSet
442  if (mode.IsMandatory() && (mode.GetModulationClass() != WIFI_MOD_CLASS_HR_DSSS))
443  {
444  NS_LOG_DEBUG("Adding basic mode " << mode.GetUniqueName());
446  }
447  }
448  // set the basic rates
449  for (uint8_t j = 0; j < GetWifiRemoteStationManager(linkId)->GetNBasicModes(); j++)
450  {
452  uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
453  NS_LOG_DEBUG("Setting basic rate " << mode.GetUniqueName());
454  rates.SetBasicRate(modeDataRate);
455  }
456  // If it is a HT AP, then add the BSSMembershipSelectorSet
457  // The standard says that the BSSMembershipSelectorSet
458  // must have its MSB set to 1 (must be treated as a Basic Rate)
459  // Also the standard mentioned that at least 1 element should be included in the SupportedRates
460  // the rest can be in the ExtendedSupportedRates
461  if (GetHtSupported())
462  {
463  for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
464  {
465  rates.AddBssMembershipSelectorRate(selector);
466  }
467  }
468  return rates;
469 }
470 
472 ApWifiMac::GetDsssParameterSet(uint8_t linkId) const
473 {
474  NS_LOG_FUNCTION(this << +linkId);
475  NS_ASSERT(GetDsssSupported(linkId));
476  DsssParameterSet dsssParameters;
477  dsssParameters.SetCurrentChannel(GetWifiPhy(linkId)->GetChannelNumber());
478  return dsssParameters;
479 }
480 
482 ApWifiMac::GetCapabilities(uint8_t linkId) const
483 {
484  NS_LOG_FUNCTION(this << +linkId);
485  CapabilityInformation capabilities;
486  capabilities.SetShortPreamble(GetLink(linkId).shortPreambleEnabled);
487  capabilities.SetShortSlotTime(GetLink(linkId).shortSlotTimeEnabled);
488  capabilities.SetEss();
489  return capabilities;
490 }
491 
493 ApWifiMac::GetErpInformation(uint8_t linkId) const
494 {
495  NS_LOG_FUNCTION(this << +linkId);
496  NS_ASSERT(GetErpSupported(linkId));
497  ErpInformation information;
498 
499  information.SetNonErpPresent(GetLink(linkId).numNonErpStations > 0);
500  information.SetUseProtection(GetUseNonErpProtection(linkId));
501  if (GetLink(linkId).shortPreambleEnabled)
502  {
503  information.SetBarkerPreambleMode(0);
504  }
505  else
506  {
507  information.SetBarkerPreambleMode(1);
508  }
509 
510  return information;
511 }
512 
514 ApWifiMac::GetEdcaParameterSet(uint8_t linkId) const
515 {
516  NS_LOG_FUNCTION(this << +linkId);
518  EdcaParameterSet edcaParameters;
519 
520  Ptr<QosTxop> edca;
521  Time txopLimit;
522 
523  edca = GetQosTxop(AC_BE);
524  txopLimit = edca->GetTxopLimit(linkId);
525  edcaParameters.SetBeAci(0);
526  edcaParameters.SetBeCWmin(edca->GetMinCw(linkId));
527  edcaParameters.SetBeCWmax(edca->GetMaxCw(linkId));
528  edcaParameters.SetBeAifsn(edca->GetAifsn(linkId));
529  edcaParameters.SetBeTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
530 
531  edca = GetQosTxop(AC_BK);
532  txopLimit = edca->GetTxopLimit(linkId);
533  edcaParameters.SetBkAci(1);
534  edcaParameters.SetBkCWmin(edca->GetMinCw(linkId));
535  edcaParameters.SetBkCWmax(edca->GetMaxCw(linkId));
536  edcaParameters.SetBkAifsn(edca->GetAifsn(linkId));
537  edcaParameters.SetBkTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
538 
539  edca = GetQosTxop(AC_VI);
540  txopLimit = edca->GetTxopLimit(linkId);
541  edcaParameters.SetViAci(2);
542  edcaParameters.SetViCWmin(edca->GetMinCw(linkId));
543  edcaParameters.SetViCWmax(edca->GetMaxCw(linkId));
544  edcaParameters.SetViAifsn(edca->GetAifsn(linkId));
545  edcaParameters.SetViTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
546 
547  edca = GetQosTxop(AC_VO);
548  txopLimit = edca->GetTxopLimit(linkId);
549  edcaParameters.SetVoAci(3);
550  edcaParameters.SetVoCWmin(edca->GetMinCw(linkId));
551  edcaParameters.SetVoCWmax(edca->GetMaxCw(linkId));
552  edcaParameters.SetVoAifsn(edca->GetAifsn(linkId));
553  edcaParameters.SetVoTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
554 
555  edcaParameters.SetQosInfo(0);
556 
557  return edcaParameters;
558 }
559 
560 std::optional<MuEdcaParameterSet>
562 {
563  NS_LOG_FUNCTION(this);
565 
566  Ptr<HeConfiguration> heConfiguration = GetHeConfiguration();
567  NS_ASSERT(heConfiguration);
568 
569  MuEdcaParameterSet muEdcaParameters;
570  muEdcaParameters.SetQosInfo(0);
571 
572  UintegerValue uintegerValue;
573  TimeValue timeValue;
574 
575  heConfiguration->GetAttribute("MuBeAifsn", uintegerValue);
576  muEdcaParameters.SetMuAifsn(AC_BE, uintegerValue.Get());
577  heConfiguration->GetAttribute("MuBeCwMin", uintegerValue);
578  muEdcaParameters.SetMuCwMin(AC_BE, uintegerValue.Get());
579  heConfiguration->GetAttribute("MuBeCwMax", uintegerValue);
580  muEdcaParameters.SetMuCwMax(AC_BE, uintegerValue.Get());
581  heConfiguration->GetAttribute("BeMuEdcaTimer", timeValue);
582  muEdcaParameters.SetMuEdcaTimer(AC_BE, timeValue.Get());
583 
584  heConfiguration->GetAttribute("MuBkAifsn", uintegerValue);
585  muEdcaParameters.SetMuAifsn(AC_BK, uintegerValue.Get());
586  heConfiguration->GetAttribute("MuBkCwMin", uintegerValue);
587  muEdcaParameters.SetMuCwMin(AC_BK, uintegerValue.Get());
588  heConfiguration->GetAttribute("MuBkCwMax", uintegerValue);
589  muEdcaParameters.SetMuCwMax(AC_BK, uintegerValue.Get());
590  heConfiguration->GetAttribute("BkMuEdcaTimer", timeValue);
591  muEdcaParameters.SetMuEdcaTimer(AC_BK, timeValue.Get());
592 
593  heConfiguration->GetAttribute("MuViAifsn", uintegerValue);
594  muEdcaParameters.SetMuAifsn(AC_VI, uintegerValue.Get());
595  heConfiguration->GetAttribute("MuViCwMin", uintegerValue);
596  muEdcaParameters.SetMuCwMin(AC_VI, uintegerValue.Get());
597  heConfiguration->GetAttribute("MuViCwMax", uintegerValue);
598  muEdcaParameters.SetMuCwMax(AC_VI, uintegerValue.Get());
599  heConfiguration->GetAttribute("ViMuEdcaTimer", timeValue);
600  muEdcaParameters.SetMuEdcaTimer(AC_VI, timeValue.Get());
601 
602  heConfiguration->GetAttribute("MuVoAifsn", uintegerValue);
603  muEdcaParameters.SetMuAifsn(AC_VO, uintegerValue.Get());
604  heConfiguration->GetAttribute("MuVoCwMin", uintegerValue);
605  muEdcaParameters.SetMuCwMin(AC_VO, uintegerValue.Get());
606  heConfiguration->GetAttribute("MuVoCwMax", uintegerValue);
607  muEdcaParameters.SetMuCwMax(AC_VO, uintegerValue.Get());
608  heConfiguration->GetAttribute("VoMuEdcaTimer", timeValue);
609  muEdcaParameters.SetMuEdcaTimer(AC_VO, timeValue.Get());
610 
611  // The timers of the MU EDCA Parameter Set must be either all zero or all
612  // non-zero. The information element is advertised if all timers are non-zero
613  auto timerNotNull = [&muEdcaParameters](uint8_t aci) {
614  return !muEdcaParameters.GetMuEdcaTimer(aci).IsZero();
615  };
616  auto aci = {0, 1, 2, 3};
617  if (std::all_of(aci.begin(), aci.end(), timerNotNull))
618  {
619  return muEdcaParameters;
620  }
621 
622  NS_ABORT_MSG_UNLESS(std::none_of(aci.begin(), aci.end(), timerNotNull),
623  "MU EDCA Timers must be all zero if the IE is not advertised.");
624 
625  return std::nullopt;
626 }
627 
628 std::optional<ReducedNeighborReport>
630 {
631  NS_LOG_FUNCTION(this << +linkId);
632 
633  if (GetNLinks() <= 1)
634  {
635  return std::nullopt;
636  }
637 
640 
641  for (uint8_t index = 0; index < GetNLinks(); ++index)
642  {
643  if (index != linkId) // all links but the one used to send this Beacon frame
644  {
645  rnr.AddNbrApInfoField();
646  std::size_t nbrId = rnr.GetNNbrApInfoFields() - 1;
647  rnr.SetOperatingChannel(nbrId, GetLink(index).phy->GetOperatingChannel());
648  rnr.AddTbttInformationField(nbrId);
649  rnr.SetBssid(nbrId, 0, GetLink(index).feManager->GetAddress());
650  rnr.SetShortSsid(nbrId, 0, 0);
651  rnr.SetBssParameters(nbrId, 0, 0);
652  rnr.SetPsd20MHz(nbrId, 0, 0);
653  rnr.SetMldParameters(nbrId, 0, 0, index, 0);
654  }
655  }
656  return rnr;
657 }
658 
660 ApWifiMac::GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac48Address& to)
661 {
662  NS_LOG_FUNCTION(this << +linkId << frameType << to);
663  NS_ABORT_IF(GetNLinks() == 1);
664 
667  mle.SetLinkIdInfo(linkId);
669 
670  // if the Multi-Link Element is being inserted in a (Re)Association Response frame
671  // and the remote station is affiliated with an MLD, try multi-link setup
672  if (auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
673  (frameType == WIFI_MAC_MGT_ASSOCIATION_RESPONSE ||
674  frameType == WIFI_MAC_MGT_REASSOCIATION_RESPONSE) &&
675  staMldAddress.has_value())
676  {
677  for (uint8_t i = 0; i < GetNLinks(); i++)
678  {
679  auto remoteStationManager = GetWifiRemoteStationManager(i);
680  if (auto staAddress = remoteStationManager->GetAffiliatedStaAddress(*staMldAddress);
681  i != linkId && staAddress.has_value() &&
682  (remoteStationManager->IsWaitAssocTxOk(*staAddress) ||
683  remoteStationManager->IsAssocRefused(*staAddress)))
684  {
685  // For each requested link in addition to the link on which the
686  // (Re)Association Response frame is transmitted, the Link Info field
687  // of the Basic Multi-Link element carried in the (Re)Association
688  // Response frame shall contain the corresponding Per-STA Profile
689  // subelement(s) (Sec. 35.3.5.4 of 802.11be D2.0)
691  auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
692  // The Link ID subfield of the STA Control field of the Per-STA Profile
693  // subelement for the AP corresponding to a link is set to the link ID
694  // of the AP affiliated with the AP MLD that is operating on that link.
695  perStaProfile.SetLinkId(i);
696  perStaProfile.SetCompleteProfile();
697  // For each Per-STA Profile subelement included in the Link Info field,
698  // the Complete Profile subfield of the STA Control field shall be set to 1
699  perStaProfile.SetStaMacAddress(GetFrameExchangeManager(i)->GetAddress());
700  perStaProfile.SetAssocResponse(GetAssocResp(*staAddress, i));
701  }
702  }
703  }
704 
705  return mle;
706 }
707 
709 ApWifiMac::GetHtOperation(uint8_t linkId) const
710 {
711  NS_LOG_FUNCTION(this << +linkId);
713  HtOperation operation;
714  auto phy = GetWifiPhy(linkId);
715  auto remoteStationManager = GetWifiRemoteStationManager(linkId);
716 
717  operation.SetPrimaryChannel(phy->GetPrimaryChannelNumber(20));
718  operation.SetRifsMode(false);
719  operation.SetNonGfHtStasPresent(true);
720  if (phy->GetChannelWidth() > 20)
721  {
722  operation.SetSecondaryChannelOffset(1);
723  operation.SetStaChannelWidth(1);
724  }
725  if (GetLink(linkId).numNonHtStations == 0)
726  {
727  operation.SetHtProtection(NO_PROTECTION);
728  }
729  else
730  {
732  }
733  uint64_t maxSupportedRate = 0; // in bit/s
734  for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HT))
735  {
736  uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
737  NS_ASSERT(nss > 0 && nss < 5);
738  uint64_t dataRate =
739  mcs.GetDataRate(phy->GetChannelWidth(),
740  GetHtConfiguration()->GetShortGuardIntervalSupported() ? 400 : 800,
741  nss);
742  if (dataRate > maxSupportedRate)
743  {
744  maxSupportedRate = dataRate;
745  NS_LOG_DEBUG("Updating maxSupportedRate to " << maxSupportedRate);
746  }
747  }
748  uint8_t maxSpatialStream = phy->GetMaxSupportedTxSpatialStreams();
749  auto mcsList = phy->GetMcsList(WIFI_MOD_CLASS_HT);
750  uint8_t nMcs = mcsList.size();
751  for (const auto& sta : GetLink(linkId).staList)
752  {
753  if (remoteStationManager->GetHtSupported(sta.second))
754  {
755  uint64_t maxSupportedRateByHtSta = 0; // in bit/s
756  auto itMcs = mcsList.begin();
757  for (uint8_t j = 0;
758  j < (std::min(nMcs, remoteStationManager->GetNMcsSupported(sta.second)));
759  j++)
760  {
761  WifiMode mcs = *itMcs++;
762  uint8_t nss = (mcs.GetMcsValue() / 8) + 1;
763  NS_ASSERT(nss > 0 && nss < 5);
764  uint64_t dataRate = mcs.GetDataRate(
765  remoteStationManager->GetChannelWidthSupported(sta.second),
766  remoteStationManager->GetShortGuardIntervalSupported(sta.second) ? 400 : 800,
767  nss);
768  if (dataRate > maxSupportedRateByHtSta)
769  {
770  maxSupportedRateByHtSta = dataRate;
771  }
772  }
773  if (maxSupportedRateByHtSta < maxSupportedRate)
774  {
775  maxSupportedRate = maxSupportedRateByHtSta;
776  }
777  if (remoteStationManager->GetNMcsSupported(sta.second) < nMcs)
778  {
779  nMcs = remoteStationManager->GetNMcsSupported(sta.second);
780  }
781  if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
782  {
783  maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
784  }
785  }
786  }
788  static_cast<uint16_t>(maxSupportedRate / 1e6)); // in Mbit/s
789  operation.SetTxMcsSetDefined(nMcs > 0);
790  operation.SetTxMaxNSpatialStreams(maxSpatialStream);
791  // To be filled in once supported
792  operation.SetObssNonHtStasPresent(0);
793  operation.SetDualBeacon(0);
794  operation.SetDualCtsProtection(0);
795  operation.SetStbcBeacon(0);
797  operation.SetPcoActive(0);
798  operation.SetPhase(0);
799  operation.SetRxMcsBitmask(0);
800  operation.SetTxRxMcsSetUnequal(0);
801  operation.SetTxUnequalModulation(0);
802 
803  return operation;
804 }
805 
807 ApWifiMac::GetVhtOperation(uint8_t linkId) const
808 {
809  NS_LOG_FUNCTION(this << +linkId);
810  NS_ASSERT(GetVhtSupported(linkId));
811  VhtOperation operation;
812  auto phy = GetWifiPhy(linkId);
813  auto remoteStationManager = GetWifiRemoteStationManager(linkId);
814 
815  const uint16_t bssBandwidth = phy->GetChannelWidth();
816  // Set to 0 for 20 MHz or 40 MHz BSS bandwidth.
817  // Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS bandwidth.
818  operation.SetChannelWidth((bssBandwidth > 40) ? 1 : 0);
819  // For 20, 40, or 80 MHz BSS bandwidth, indicates the channel center frequency
820  // index for the 20, 40, or 80 MHz channel on which the VHT BSS operates.
821  // For 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
822  // indicates the channel center frequency index of the 80 MHz channel
823  // segment that contains the primary channel.
825  (bssBandwidth == 160)
826  ? phy->GetOperatingChannel().GetPrimaryChannelNumber(80, phy->GetStandard())
827  : phy->GetChannelNumber());
828  // For a 20, 40, or 80 MHz BSS bandwidth, this subfield is set to 0.
829  // For a 160 MHz BSS bandwidth and the Channel Width subfield equal to 1,
830  // indicates the channel center frequency index of the 160 MHz channel on
831  // which the VHT BSS operates.
832  operation.SetChannelCenterFrequencySegment1((bssBandwidth == 160) ? phy->GetChannelNumber()
833  : 0);
834  uint8_t maxSpatialStream = phy->GetMaxSupportedRxSpatialStreams();
835  for (const auto& sta : GetLink(linkId).staList)
836  {
837  if (remoteStationManager->GetVhtSupported(sta.second))
838  {
839  if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
840  {
841  maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
842  }
843  }
844  }
845  for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
846  {
847  uint8_t maxMcs =
848  9; // TBD: hardcode to 9 for now since we assume all MCS values are supported
849  operation.SetMaxVhtMcsPerNss(nss, maxMcs);
850  }
851 
852  return operation;
853 }
854 
856 ApWifiMac::GetHeOperation(uint8_t linkId) const
857 {
858  NS_LOG_FUNCTION(this << +linkId);
860  HeOperation operation;
861  auto remoteStationManager = GetWifiRemoteStationManager(linkId);
862 
863  uint8_t maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
864  for (const auto& sta : GetLink(linkId).staList)
865  {
866  if (remoteStationManager->GetHeSupported(sta.second))
867  {
868  if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
869  {
870  maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
871  }
872  }
873  }
874  for (uint8_t nss = 1; nss <= maxSpatialStream; nss++)
875  {
876  operation.SetMaxHeMcsPerNss(
877  nss,
878  11); // TBD: hardcode to 11 for now since we assume all MCS values are supported
879  }
880  operation.SetBssColor(GetHeConfiguration()->GetBssColor());
881 
882  return operation;
883 }
884 
886 ApWifiMac::GetEhtOperation(uint8_t linkId) const
887 {
888  NS_LOG_FUNCTION(this << +linkId);
890  EhtOperation operation;
891  auto remoteStationManager = GetWifiRemoteStationManager(linkId);
892 
893  auto maxSpatialStream = GetWifiPhy(linkId)->GetMaxSupportedRxSpatialStreams();
894  for (const auto& sta : GetLink(linkId).staList)
895  {
896  if (remoteStationManager->GetEhtSupported(sta.second))
897  {
898  if (remoteStationManager->GetNumberOfSupportedStreams(sta.second) < maxSpatialStream)
899  {
900  maxSpatialStream = remoteStationManager->GetNumberOfSupportedStreams(sta.second);
901  }
902  }
903  }
904  operation.SetMaxRxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
905  operation.SetMaxTxNss(maxSpatialStream, 0, WIFI_EHT_MAX_MCS_INDEX);
906  return operation;
907 }
908 
909 void
911 {
912  NS_LOG_FUNCTION(this << to << +linkId);
913  WifiMacHeader hdr;
915  hdr.SetAddr1(to);
916  hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
917  hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
918  hdr.SetDsNotFrom();
919  hdr.SetDsNotTo();
920  Ptr<Packet> packet = Create<Packet>();
922  probe.SetSsid(GetSsid());
923  probe.SetSupportedRates(GetSupportedRates(linkId));
924  probe.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
925  probe.SetCapabilities(GetCapabilities(linkId));
927  GetLink(linkId).shortPreambleEnabled);
929  GetLink(linkId).shortSlotTimeEnabled);
930  if (GetDsssSupported(linkId))
931  {
933  }
934  if (GetErpSupported(linkId))
935  {
936  probe.SetErpInformation(GetErpInformation(linkId));
937  }
938  if (GetQosSupported())
939  {
941  }
942  if (GetHtSupported())
943  {
945  probe.SetHtCapabilities(GetHtCapabilities(linkId));
946  probe.SetHtOperation(GetHtOperation(linkId));
947  }
949  {
950  probe.SetVhtCapabilities(GetVhtCapabilities(linkId));
951  probe.SetVhtOperation(GetVhtOperation(linkId));
952  }
953  if (GetHeSupported())
954  {
955  probe.SetHeCapabilities(GetHeCapabilities(linkId));
956  probe.SetHeOperation(GetHeOperation(linkId));
957  if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
958  {
959  probe.SetMuEdcaParameterSet(std::move(*muEdcaParameterSet));
960  }
961  }
962  if (GetEhtSupported())
963  {
964  probe.SetEhtCapabilities(GetEhtCapabilities(linkId));
965  probe.SetEhtOperation(GetEhtOperation(linkId));
966 
967  if (GetNLinks() > 1)
968  {
969  /*
970  * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
971  * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
972  * include a TBTT Information field in a Reduced Neighbor Report element with the
973  * TBTT Information Length field set to 16 or higher, for each of the other APs
974  * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
975  */
976  if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
977  {
978  probe.SetReducedNeighborReport(std::move(*rnr));
979  }
980  /*
981  * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
982  * shall include, in a Beacon frame or a Probe Response frame, which is not a
983  * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
984  * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
985  * channel switching, extended channel switching, and channel quieting) are
986  * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
987  */
989  }
990  }
991  packet->AddHeader(probe);
992 
993  if (!GetQosSupported())
994  {
995  GetTxop()->Queue(packet, hdr);
996  }
997  // "A QoS STA that transmits a Management frame determines access category used
998  // for medium access in transmission of the Management frame as follows
999  // (If dot11QMFActivated is false or not present)
1000  // — If the Management frame is individually addressed to a non-QoS STA, category
1001  // AC_BE should be selected.
1002  // — If category AC_BE was not selected by the previous step, category AC_VO
1003  // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1004  else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1005  {
1006  GetBEQueue()->Queue(packet, hdr);
1007  }
1008  else
1009  {
1010  GetVOQueue()->Queue(packet, hdr);
1011  }
1012 }
1013 
1016 {
1017  MgtAssocResponseHeader assoc;
1018  StatusCode code;
1019  auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1020  if (remoteStationManager->IsWaitAssocTxOk(to))
1021  {
1022  code.SetSuccess();
1023  }
1024  else
1025  {
1026  NS_ABORT_IF(!remoteStationManager->IsAssocRefused(to));
1027  // reset state
1028  remoteStationManager->RecordDisassociated(to);
1029  code.SetFailure();
1030  }
1031  assoc.SetSupportedRates(GetSupportedRates(linkId));
1032  assoc.SetStatusCode(code);
1033  assoc.SetCapabilities(GetCapabilities(linkId));
1034  if (GetErpSupported(linkId))
1035  {
1036  assoc.SetErpInformation(GetErpInformation(linkId));
1037  }
1038  if (GetQosSupported())
1039  {
1041  }
1042  if (GetHtSupported())
1043  {
1045  assoc.SetHtCapabilities(GetHtCapabilities(linkId));
1046  assoc.SetHtOperation(GetHtOperation(linkId));
1047  }
1048  if (GetVhtSupported(linkId))
1049  {
1050  assoc.SetVhtCapabilities(GetVhtCapabilities(linkId));
1051  assoc.SetVhtOperation(GetVhtOperation(linkId));
1052  }
1053  if (GetHeSupported())
1054  {
1055  assoc.SetHeCapabilities(GetHeCapabilities(linkId));
1056  assoc.SetHeOperation(GetHeOperation(linkId));
1057  if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1058  {
1059  assoc.SetMuEdcaParameterSet(std::move(*muEdcaParameterSet));
1060  }
1061  }
1062  if (GetEhtSupported())
1063  {
1064  assoc.SetEhtCapabilities(GetEhtCapabilities(linkId));
1065  assoc.SetEhtOperation(GetEhtOperation(linkId));
1066  }
1067  return assoc;
1068 }
1069 
1072  const Mac48Address& to,
1073  uint8_t linkId)
1074 {
1075  // find all the links to setup (i.e., those for which status code is success)
1076  std::map<uint8_t /* link ID */, Mac48Address> linkIdStaAddrMap;
1077 
1078  if (assoc.GetStatusCode().IsSuccess())
1079  {
1080  linkIdStaAddrMap[linkId] = to;
1081  }
1082 
1083  if (const auto& mle = assoc.GetMultiLinkElement())
1084  {
1085  const auto staMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(to);
1086  NS_ABORT_MSG_IF(!staMldAddress.has_value(),
1087  "Sending a Multi-Link Element to a single link device");
1088  for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1089  {
1090  auto& perStaProfile = mle->GetPerStaProfile(idx);
1091  if (perStaProfile.HasAssocResponse() &&
1092  perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1093  {
1094  uint8_t otherLinkId = perStaProfile.GetLinkId();
1095  auto staAddress = GetWifiRemoteStationManager(otherLinkId)
1096  ->GetAffiliatedStaAddress(*staMldAddress);
1097  NS_ABORT_MSG_IF(!staAddress.has_value(),
1098  "No STA to associate with on link " << +otherLinkId);
1099  const auto [it, inserted] = linkIdStaAddrMap.insert({otherLinkId, *staAddress});
1100  NS_ABORT_MSG_IF(!inserted,
1101  "More than one Association Response to MLD "
1102  << *staMldAddress << " on link ID " << +otherLinkId);
1103  }
1104  }
1105  }
1106 
1107  return linkIdStaAddrMap;
1108 }
1109 
1110 void
1112 {
1113  if (linkIdStaAddrMap.empty())
1114  {
1115  // no link to setup, nothing to do
1116  return;
1117  }
1118 
1119  // check if AIDs are already allocated to the STAs that are associating
1120  std::set<uint16_t> aids;
1121  std::map<uint8_t /* link ID */, uint16_t /* AID */> linkIdAidMap;
1122 
1123  for (const auto& [id, staAddr] : linkIdStaAddrMap)
1124  {
1125  for (const auto& [aid, addr] : GetLink(id).staList)
1126  {
1127  if (addr == staAddr)
1128  {
1129  aids.insert(aid);
1130  linkIdAidMap[id] = aid;
1131  break;
1132  }
1133  }
1134  }
1135 
1136  // check if an AID already assigned to an STA can be assigned to all other STAs
1137  // affiliated with the non-AP MLD we are associating with
1138  while (!aids.empty())
1139  {
1140  const uint16_t aid = *aids.begin();
1141  bool good = true;
1142 
1143  for (const auto& [id, staAddr] : linkIdStaAddrMap)
1144  {
1145  if (auto it = GetLink(id).staList.find(aid);
1146  it != GetLink(id).staList.end() && it->second != staAddr)
1147  {
1148  // the AID is already assigned to an STA other than the one affiliated
1149  // with the non-AP MLD we are associating with
1150  aids.erase(aids.begin());
1151  good = false;
1152  break;
1153  }
1154  }
1155 
1156  if (good)
1157  {
1158  break;
1159  }
1160  }
1161 
1162  uint16_t aid = 0;
1163 
1164  if (!aids.empty())
1165  {
1166  // one of the AIDs already assigned to an STA can be assigned to all the other
1167  // STAs affiliated with the non-AP MLD we are associating with
1168  aid = *aids.begin();
1169  }
1170  else
1171  {
1172  std::list<uint8_t> linkIds;
1173  std::transform(linkIdStaAddrMap.cbegin(),
1174  linkIdStaAddrMap.cend(),
1175  std::back_inserter(linkIds),
1176  [](auto&& linkIdStaAddrPair) { return linkIdStaAddrPair.first; });
1177  aid = GetNextAssociationId(linkIds);
1178  }
1179 
1180  // store the MLD or link address in the AID-to-address map
1181  const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
1183  GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
1184 
1185  for (const auto& [id, staAddr] : linkIdStaAddrMap)
1186  {
1187  auto remoteStationManager = GetWifiRemoteStationManager(id);
1188  auto& link = GetLink(id);
1189 
1190  if (auto it = linkIdAidMap.find(id); it == linkIdAidMap.end() || it->second != aid)
1191  {
1192  // the STA on this link has no AID assigned or has a different AID assigned
1193  link.staList.insert(std::make_pair(aid, staAddr));
1194  m_assocLogger(aid, staAddr);
1195  remoteStationManager->SetAssociationId(staAddr, aid);
1196 
1197  if (it == linkIdAidMap.end())
1198  {
1199  // the STA on this link had no AID assigned
1200  if (remoteStationManager->GetDsssSupported(staAddr) &&
1201  !remoteStationManager->GetErpOfdmSupported(staAddr))
1202  {
1203  link.numNonErpStations++;
1204  }
1205  if (!remoteStationManager->GetHtSupported(staAddr))
1206  {
1207  link.numNonHtStations++;
1208  }
1211  }
1212  else
1213  {
1214  // the STA on this link had a different AID assigned
1215  link.staList.erase(it->second); // free the previous AID
1216  }
1217  }
1218  }
1219 
1220  // set the AID in all the Association Responses. NOTE that the Association
1221  // Responses included in the Per-STA Profile Subelements of the Multi-Link
1222  // Element must not contain the AID field. We set the AID field in such
1223  // Association Responses anyway, in order to ease future implementation of
1224  // the inheritance mechanism.
1225  if (assoc.GetStatusCode().IsSuccess())
1226  {
1227  assoc.SetAssociationId(aid);
1228  }
1229  if (const auto& mle = assoc.GetMultiLinkElement())
1230  {
1231  for (std::size_t idx = 0; idx < mle->GetNPerStaProfileSubelements(); idx++)
1232  {
1233  if (const auto& perStaProfile = mle->GetPerStaProfile(idx);
1234  perStaProfile.HasAssocResponse() &&
1235  perStaProfile.GetAssocResponse().GetStatusCode().IsSuccess())
1236  {
1237  perStaProfile.GetAssocResponse().SetAssociationId(aid);
1238  }
1239  }
1240  }
1241 }
1242 
1243 void
1244 ApWifiMac::SendAssocResp(Mac48Address to, bool isReassoc, uint8_t linkId)
1245 {
1246  NS_LOG_FUNCTION(this << to << isReassoc << +linkId);
1247  WifiMacHeader hdr;
1250  hdr.SetAddr1(to);
1253  hdr.SetDsNotFrom();
1254  hdr.SetDsNotTo();
1255 
1256  MgtAssocResponseHeader assoc = GetAssocResp(to, linkId);
1257 
1258  // The AP that is affiliated with the AP MLD and that responds to an (Re)Association
1259  // Request frame that carries a Basic Multi-Link element shall include a Basic
1260  // Multi-Link element in the (Re)Association Response frame that it transmits
1261  // (Sec. 35.3.5.4 of 802.11be D2.0)
1262  // If the STA included a Multi-Link Element in the (Re)Association Request, we
1263  // stored its MLD address in the remote station manager
1264  if (GetNLinks() > 1 && GetWifiRemoteStationManager(linkId)->GetMldAddress(to).has_value())
1265  {
1266  assoc.SetMultiLinkElement(GetMultiLinkElement(linkId, hdr.GetType(), to));
1267  }
1268 
1269  auto linkIdStaAddrMap = GetLinkIdStaAddrMap(assoc, to, linkId);
1270  SetAid(assoc, linkIdStaAddrMap);
1271 
1272  if (GetNLinks() > 1)
1273  {
1274  ConfigQueueScheduler(linkIdStaAddrMap, to, linkId);
1275  }
1276 
1277  Ptr<Packet> packet = Create<Packet>();
1278  packet->AddHeader(assoc);
1279 
1280  if (!GetQosSupported())
1281  {
1282  GetTxop()->Queue(packet, hdr);
1283  }
1284  // "A QoS STA that transmits a Management frame determines access category used
1285  // for medium access in transmission of the Management frame as follows
1286  // (If dot11QMFActivated is false or not present)
1287  // — If the Management frame is individually addressed to a non-QoS STA, category
1288  // AC_BE should be selected.
1289  // — If category AC_BE was not selected by the previous step, category AC_VO
1290  // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
1291  else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
1292  {
1293  GetBEQueue()->Queue(packet, hdr);
1294  }
1295  else
1296  {
1297  GetVOQueue()->Queue(packet, hdr);
1298  }
1299 }
1300 
1301 void
1303  const Mac48Address& to,
1304  uint8_t linkId)
1305 {
1306  NS_LOG_FUNCTION(this << to << +linkId);
1307 
1308  // get a list of the IDs of the links to setup
1309  std::list<uint8_t> linkIds;
1310  std::transform(linkIdStaAddrMap.cbegin(),
1311  linkIdStaAddrMap.cend(),
1312  std::back_inserter(linkIds),
1313  [](auto&& linkIdStaAddrPair) { return linkIdStaAddrPair.first; });
1314 
1315  // get the MLD address of the STA, if affiliated with a non-AP MLD, or the STA address
1316  auto staAddr = to;
1317  if (auto mldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(to))
1318  {
1319  staAddr = *mldAddr;
1320  }
1321 
1322  // configure the queue scheduler to only use the links that have been setup for
1323  // transmissions to this station
1324  for (const auto& [acIndex, wifiAc] : wifiAcList)
1325  {
1326  for (auto tid : {wifiAc.GetLowTid(), wifiAc.GetHighTid()})
1327  {
1328  WifiContainerQueueId queueId(WIFI_QOSDATA_UNICAST_QUEUE, staAddr, tid);
1329  m_scheduler->SetLinkIds(acIndex, queueId, linkIds);
1330  }
1331  }
1332 }
1333 
1334 void
1336 {
1337  NS_LOG_FUNCTION(this << +linkId);
1338  auto& link = GetLink(linkId);
1339  WifiMacHeader hdr;
1342  hdr.SetAddr2(link.feManager->GetAddress());
1343  hdr.SetAddr3(link.feManager->GetAddress());
1344  hdr.SetDsNotFrom();
1345  hdr.SetDsNotTo();
1346  Ptr<Packet> packet = Create<Packet>();
1347  MgtBeaconHeader beacon;
1348  beacon.SetSsid(GetSsid());
1349  beacon.SetSupportedRates(GetSupportedRates(linkId));
1350  beacon.SetBeaconIntervalUs(GetBeaconInterval().GetMicroSeconds());
1351  beacon.SetCapabilities(GetCapabilities(linkId));
1352  GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(link.shortPreambleEnabled);
1353  GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(link.shortSlotTimeEnabled);
1354  if (GetDsssSupported(linkId))
1355  {
1356  beacon.SetDsssParameterSet(GetDsssParameterSet(linkId));
1357  }
1358  if (GetErpSupported(linkId))
1359  {
1360  beacon.SetErpInformation(GetErpInformation(linkId));
1361  }
1362  if (GetQosSupported())
1363  {
1364  beacon.SetEdcaParameterSet(GetEdcaParameterSet(linkId));
1365  }
1366  if (GetHtSupported())
1367  {
1369  beacon.SetHtCapabilities(GetHtCapabilities(linkId));
1370  beacon.SetHtOperation(GetHtOperation(linkId));
1371  }
1372  if (GetVhtSupported(linkId))
1373  {
1374  beacon.SetVhtCapabilities(GetVhtCapabilities(linkId));
1375  beacon.SetVhtOperation(GetVhtOperation(linkId));
1376  }
1377  if (GetHeSupported())
1378  {
1379  beacon.SetHeCapabilities(GetHeCapabilities(linkId));
1380  beacon.SetHeOperation(GetHeOperation(linkId));
1381  if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
1382  {
1383  beacon.SetMuEdcaParameterSet(std::move(*muEdcaParameterSet));
1384  }
1385  }
1386  if (GetEhtSupported())
1387  {
1388  beacon.SetEhtCapabilities(GetEhtCapabilities(linkId));
1389  beacon.SetEhtOperation(GetEhtOperation(linkId));
1390 
1391  if (GetNLinks() > 1)
1392  {
1393  /*
1394  * If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
1395  * BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
1396  * include a TBTT Information field in a Reduced Neighbor Report element with the
1397  * TBTT Information Length field set to 16 or higher, for each of the other APs
1398  * (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
1399  */
1400  if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
1401  {
1402  beacon.SetReducedNeighborReport(std::move(*rnr));
1403  }
1404  /*
1405  * If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
1406  * shall include, in a Beacon frame or a Probe Response frame, which is not a
1407  * Multi-Link probe response, only the Common Info field of the Basic Multi-Link
1408  * element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
1409  * channel switching, extended channel switching, and channel quieting) are
1410  * satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
1411  */
1413  }
1414  }
1415  packet->AddHeader(beacon);
1416 
1417  // The beacon has it's own special queue, so we load it in there
1418  m_beaconTxop->Queue(packet, hdr);
1419  link.beaconEvent =
1421 
1422  // If a STA that does not support Short Slot Time associates,
1423  // the AP shall use long slot time beginning at the first Beacon
1424  // subsequent to the association of the long slot time STA.
1425  if (GetErpSupported(linkId))
1426  {
1427  if (link.shortSlotTimeEnabled)
1428  {
1429  // Enable short slot time
1430  GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1431  }
1432  else
1433  {
1434  // Disable short slot time
1435  GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1436  }
1437  }
1438 }
1439 
1440 void
1442 {
1443  NS_LOG_FUNCTION(this << *mpdu);
1444  const WifiMacHeader& hdr = mpdu->GetHeader();
1445 
1446  if (hdr.IsAssocResp() || hdr.IsReassocResp())
1447  {
1448  auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1449  NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1450 
1452  {
1453  NS_LOG_DEBUG("AP=" << hdr.GetAddr2() << " associated with STA=" << hdr.GetAddr1());
1455  }
1456 
1457  if (auto staMldAddress =
1459  staMldAddress.has_value())
1460  {
1461  // the STA is affiliated with an MLD
1462  for (uint8_t i = 0; i < GetNLinks(); i++)
1463  {
1464  auto stationManager = GetWifiRemoteStationManager(i);
1465  if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1466  staAddress.has_value() && i != *linkId &&
1467  stationManager->IsWaitAssocTxOk(*staAddress))
1468  {
1470  << " associated with STA=" << *staAddress);
1471  stationManager->RecordGotAssocTxOk(*staAddress);
1472  }
1473  }
1474  }
1475  }
1476 }
1477 
1478 void
1480 {
1481  NS_LOG_FUNCTION(this << +timeoutReason << *mpdu);
1482  const WifiMacHeader& hdr = mpdu->GetHeader();
1483 
1484  if (hdr.IsAssocResp() || hdr.IsReassocResp())
1485  {
1486  auto linkId = GetLinkIdByAddress(hdr.GetAddr2());
1487  NS_ABORT_MSG_IF(!linkId.has_value(), "No link ID matching the TA");
1488 
1490  {
1491  NS_LOG_DEBUG("AP=" << hdr.GetAddr2()
1492  << " association failed with STA=" << hdr.GetAddr1());
1494  }
1495 
1496  if (auto staMldAddress =
1498  staMldAddress.has_value())
1499  {
1500  // the STA is affiliated with an MLD
1501  for (uint8_t i = 0; i < GetNLinks(); i++)
1502  {
1503  auto stationManager = GetWifiRemoteStationManager(i);
1504  if (auto staAddress = stationManager->GetAffiliatedStaAddress(*staMldAddress);
1505  staAddress.has_value() && i != *linkId &&
1506  stationManager->IsWaitAssocTxOk(*staAddress))
1507  {
1509  << " association failed with STA=" << *staAddress);
1510  stationManager->RecordGotAssocTxFailed(*staAddress);
1511  }
1512  }
1513  }
1514  }
1515 }
1516 
1517 std::optional<uint8_t>
1519 {
1520  for (uint8_t linkId = 0; linkId < GetNLinks(); linkId++)
1521  {
1523  {
1524  return linkId;
1525  }
1526  }
1527  NS_LOG_DEBUG(address << " is not associated");
1528  return std::nullopt;
1529 }
1530 
1533 {
1534  auto linkId = IsAssociated(remoteAddr);
1535  NS_ASSERT_MSG(linkId, remoteAddr << " is not associated");
1536  return GetFrameExchangeManager(*linkId)->GetAddress();
1537 }
1538 
1539 std::optional<Mac48Address>
1541 {
1542  if (const auto staIt = m_aidToMldOrLinkAddress.find(aid);
1543  staIt != m_aidToMldOrLinkAddress.cend())
1544  {
1545  return staIt->second;
1546  }
1547  return std::nullopt;
1548 }
1549 
1550 void
1552 {
1553  NS_LOG_FUNCTION(this << *mpdu << +linkId);
1554  // consider the MAC header of the original MPDU (makes a difference for data frames only)
1555  const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1556  Ptr<const Packet> packet = mpdu->GetPacket();
1557  Mac48Address from = hdr->GetAddr2();
1558  if (hdr->IsData())
1559  {
1560  std::optional<uint8_t> apLinkId;
1561  if (!hdr->IsFromDs() && hdr->IsToDs() &&
1562  (apLinkId = IsAssociated(mpdu->GetHeader().GetAddr2())) &&
1563  mpdu->GetHeader().GetAddr1() == GetFrameExchangeManager(*apLinkId)->GetAddress())
1564  {
1565  Mac48Address to = hdr->GetAddr3();
1566  // Address3 can be our MLD address (e.g., this is an MPDU containing a single MSDU
1567  // addressed to us) or a BSSID (e.g., this is an MPDU containing an A-MSDU)
1568  if (to == GetAddress() ||
1569  (hdr->IsQosData() && hdr->IsQosAmsdu() && to == mpdu->GetHeader().GetAddr1()))
1570  {
1571  NS_LOG_DEBUG("frame for me from=" << from);
1572  if (hdr->IsQosData())
1573  {
1574  if (hdr->IsQosAmsdu())
1575  {
1576  NS_LOG_DEBUG("Received A-MSDU from=" << from
1577  << ", size=" << packet->GetSize());
1579  packet = nullptr;
1580  }
1581  else
1582  {
1583  ForwardUp(packet, from, GetAddress());
1584  }
1585  }
1586  else if (hdr->HasData())
1587  {
1588  ForwardUp(packet, from, GetAddress());
1589  }
1590  }
1591  else if (to.IsGroup() || IsAssociated(to))
1592  {
1593  NS_LOG_DEBUG("forwarding frame from=" << from << ", to=" << to);
1594  Ptr<Packet> copy = packet->Copy();
1595 
1596  // If the frame we are forwarding is of type QoS Data,
1597  // then we need to preserve the UP in the QoS control
1598  // header...
1599  if (hdr->IsQosData())
1600  {
1601  ForwardDown(copy, from, to, hdr->GetQosTid());
1602  }
1603  else
1604  {
1605  ForwardDown(copy, from, to);
1606  }
1607  ForwardUp(packet, from, to);
1608  }
1609  else
1610  {
1611  ForwardUp(packet, from, to);
1612  }
1613  }
1614  else if (hdr->IsFromDs() && hdr->IsToDs())
1615  {
1616  // this is an AP-to-AP frame
1617  // we ignore for now.
1618  NotifyRxDrop(packet);
1619  }
1620  else
1621  {
1622  // we can ignore these frames since
1623  // they are not targeted at the AP
1624  NotifyRxDrop(packet);
1625  }
1626  return;
1627  }
1628  else if (hdr->IsMgt())
1629  {
1630  if (hdr->IsProbeReq() && (hdr->GetAddr1().IsGroup() ||
1631  hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress()))
1632  {
1633  // In the case where the Address 1 field contains a group address, the
1634  // Address 3 field also is validated to verify that the group addressed
1635  // frame originated from a STA in the BSS of which the receiving STA is
1636  // a member (Section 9.3.3.1 of 802.11-2020)
1637  if (hdr->GetAddr1().IsGroup() && !hdr->GetAddr3().IsBroadcast() &&
1638  hdr->GetAddr3() != GetFrameExchangeManager(linkId)->GetAddress())
1639  {
1640  // not addressed to us
1641  return;
1642  }
1643  MgtProbeRequestHeader probeRequestHeader;
1644  packet->PeekHeader(probeRequestHeader);
1645  const Ssid& ssid = probeRequestHeader.GetSsid();
1646  if (ssid == GetSsid() || ssid.IsBroadcast())
1647  {
1648  NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
1649  SendProbeResp(from, linkId);
1650  }
1651  return;
1652  }
1653  else if (hdr->GetAddr1() == GetFrameExchangeManager(linkId)->GetAddress())
1654  {
1655  if (hdr->IsAssocReq() || hdr->IsReassocReq())
1656  {
1657  NS_LOG_DEBUG(((hdr->IsAssocReq()) ? "Association" : "Reassociation")
1658  << " request received from " << from
1659  << ((GetNLinks() > 1) ? " on link ID " + std::to_string(linkId) : ""));
1660 
1661  MgtAssocRequestHeader assocReq;
1662  MgtReassocRequestHeader reassocReq;
1663  AssocReqRefVariant frame = assocReq;
1664  if (hdr->IsAssocReq())
1665  {
1666  packet->PeekHeader(assocReq);
1667  }
1668  else
1669  {
1670  packet->PeekHeader(reassocReq);
1671  frame = reassocReq;
1672  }
1673  ReceiveAssocRequest(frame, from, linkId);
1674  if (GetNLinks() > 1)
1675  {
1676  ParseReportedStaInfo(frame, from, linkId);
1677  }
1678  SendAssocResp(hdr->GetAddr2(), hdr->IsReassocReq(), linkId);
1679  return;
1680  }
1681  else if (hdr->IsDisassociation())
1682  {
1683  NS_LOG_DEBUG("Disassociation received from " << from);
1685  auto& staList = GetLink(linkId).staList;
1686  for (auto it = staList.begin(); it != staList.end(); ++it)
1687  {
1688  if (it->second == from)
1689  {
1690  staList.erase(it);
1691  m_deAssocLogger(it->first, it->second);
1692  if (GetWifiRemoteStationManager(linkId)->GetDsssSupported(from) &&
1693  !GetWifiRemoteStationManager(linkId)->GetErpOfdmSupported(from))
1694  {
1695  GetLink(linkId).numNonErpStations--;
1696  }
1697  if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from))
1698  {
1699  GetLink(linkId).numNonHtStations--;
1700  }
1703  break;
1704  }
1705  }
1706  return;
1707  }
1708  }
1709  }
1710 
1711  // Invoke the receive handler of our parent class to deal with any
1712  // other frames. Specifically, this will handle Block Ack-related
1713  // Management Action frames.
1714  WifiMac::Receive(Create<WifiMpdu>(packet, *hdr), linkId);
1715 }
1716 
1717 bool
1719  const Mac48Address& from,
1720  uint8_t linkId)
1721 {
1722  NS_LOG_FUNCTION(this << from << +linkId);
1723 
1724  auto remoteStationManager = GetWifiRemoteStationManager(linkId);
1725 
1726  auto failure = [&](const std::string& msg) -> bool {
1727  NS_LOG_DEBUG("Association Request from " << from << " refused: " << msg);
1728  remoteStationManager->RecordAssocRefused(from);
1729  return false;
1730  };
1731 
1732  // lambda to process received (Re)Association Request
1733  auto recvAssocRequest = [&](auto&& frameRefWrapper) -> bool {
1734  const auto& frame = frameRefWrapper.get();
1735 
1736  // first, verify that the the station's supported
1737  // rate set is compatible with our Basic Rate set
1738  const CapabilityInformation& capabilities = frame.GetCapabilities();
1739  remoteStationManager->AddSupportedPhyPreamble(from, capabilities.IsShortPreamble());
1740  const SupportedRates& rates = frame.GetSupportedRates();
1741 
1742  if (rates.GetNRates() == 0)
1743  {
1744  return failure("STA's supported rate set not compatible with our Basic Rate set");
1745  }
1746 
1747  if (GetHtSupported())
1748  {
1749  // check whether the HT STA supports all MCSs in Basic MCS Set
1750  const auto& htCapabilities = frame.GetHtCapabilities();
1751  if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
1752  {
1753  for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
1754  {
1755  WifiMode mcs = remoteStationManager->GetBasicMcs(i);
1756  if (!htCapabilities->IsSupportedMcs(mcs.GetMcsValue()))
1757  {
1758  return failure("HT STA does not support all MCSs in Basic MCS Set");
1759  }
1760  }
1761  }
1762  }
1763  if (GetVhtSupported(linkId))
1764  {
1765  // check whether the VHT STA supports all MCSs in Basic MCS Set
1766  const auto& vhtCapabilities = frame.GetVhtCapabilities();
1767  if (vhtCapabilities.has_value() && vhtCapabilities->GetVhtCapabilitiesInfo() != 0)
1768  {
1769  for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
1770  {
1771  WifiMode mcs = remoteStationManager->GetBasicMcs(i);
1772  if (!vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
1773  {
1774  return failure("VHT STA does not support all MCSs in Basic MCS Set");
1775  }
1776  }
1777  }
1778  }
1779  if (GetHeSupported())
1780  {
1781  // check whether the HE STA supports all MCSs in Basic MCS Set
1782  const auto& heCapabilities = frame.GetHeCapabilities();
1783  if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1784  {
1785  for (uint8_t i = 0; i < remoteStationManager->GetNBasicMcs(); i++)
1786  {
1787  WifiMode mcs = remoteStationManager->GetBasicMcs(i);
1788  if (!heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
1789  {
1790  return failure("HE STA does not support all MCSs in Basic MCS Set");
1791  }
1792  }
1793  }
1794  }
1795  if (GetEhtSupported())
1796  {
1797  // check whether the EHT STA supports all MCSs in Basic MCS Set
1798  // const auto& ehtCapabilities = frame.GetEhtCapabilities ();
1799  // TODO: to be completed
1800  }
1801 
1802  // The association request from the station can be accepted.
1803  // Record all its supported modes in its associated WifiRemoteStation
1804  auto phy = GetWifiPhy(linkId);
1805 
1806  for (const auto& mode : phy->GetModeList())
1807  {
1808  if (rates.IsSupportedRate(mode.GetDataRate(phy->GetChannelWidth())))
1809  {
1810  remoteStationManager->AddSupportedMode(from, mode);
1811  }
1812  }
1813  if (GetErpSupported(linkId) && remoteStationManager->GetErpOfdmSupported(from) &&
1814  capabilities.IsShortSlotTime())
1815  {
1816  remoteStationManager->AddSupportedErpSlotTime(from, true);
1817  }
1818  if (GetHtSupported())
1819  {
1820  const auto& htCapabilities = frame.GetHtCapabilities();
1821  if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
1822  {
1823  remoteStationManager->AddStationHtCapabilities(from, *htCapabilities);
1824  }
1825  // const ExtendedCapabilities& extendedCapabilities = frame.GetExtendedCapabilities ();
1826  // TODO: to be completed
1827  }
1828  if (GetVhtSupported(linkId))
1829  {
1830  const auto& vhtCapabilities = frame.GetVhtCapabilities();
1831  // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1832  // to check whether it supports VHT
1833  if (vhtCapabilities.has_value() &&
1834  vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1835  {
1836  remoteStationManager->AddStationVhtCapabilities(from, *vhtCapabilities);
1837  for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_VHT))
1838  {
1839  if (vhtCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
1840  {
1841  remoteStationManager->AddSupportedMcs(from, mcs);
1842  // here should add a control to add basic MCS when it is implemented
1843  }
1844  }
1845  }
1846  }
1847  if (GetHeSupported())
1848  {
1849  const auto& heCapabilities = frame.GetHeCapabilities();
1850  if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1851  {
1852  remoteStationManager->AddStationHeCapabilities(from, *heCapabilities);
1853  for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_HE))
1854  {
1855  if (heCapabilities->IsSupportedTxMcs(mcs.GetMcsValue()))
1856  {
1857  remoteStationManager->AddSupportedMcs(from, mcs);
1858  // here should add a control to add basic MCS when it is implemented
1859  }
1860  }
1861  }
1862  }
1863  if (GetEhtSupported())
1864  {
1865  if (const auto& ehtCapabilities = frame.GetEhtCapabilities())
1866  {
1867  remoteStationManager->AddStationEhtCapabilities(from, *ehtCapabilities);
1868  }
1869  for (const auto& mcs : phy->GetMcsList(WIFI_MOD_CLASS_EHT))
1870  {
1871  // TODO: Add check whether MCS is supported from the capabilities
1872  remoteStationManager->AddSupportedMcs(from, mcs);
1873  // here should add a control to add basic MCS when it is implemented
1874  }
1875  }
1876 
1877  NS_LOG_DEBUG("Association Request from " << from << " accepted");
1878  remoteStationManager->RecordWaitAssocTxOk(from);
1879  return true;
1880  ;
1881  };
1882 
1883  return std::visit(recvAssocRequest, assoc);
1884 }
1885 
1886 void
1888 {
1889  NS_LOG_FUNCTION(this << from << +linkId);
1890 
1891  // lambda to process received Multi-Link Element
1892  auto recvMle = [&](auto&& frame) {
1893  const auto& mle = frame.get().GetMultiLinkElement();
1894 
1895  if (!mle.has_value())
1896  {
1897  return;
1898  }
1899 
1900  GetWifiRemoteStationManager(linkId)->SetMldAddress(from, mle->GetMldMacAddress());
1901 
1902  for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
1903  {
1904  auto& perStaProfile = mle->GetPerStaProfile(i);
1905  if (!perStaProfile.HasStaMacAddress())
1906  {
1907  NS_LOG_DEBUG("[i=" << i
1908  << "] Cannot setup a link if the STA MAC address is missing");
1909  continue;
1910  }
1911  uint8_t newLinkId = perStaProfile.GetLinkId();
1912  if (newLinkId == linkId || newLinkId >= GetNLinks())
1913  {
1914  NS_LOG_DEBUG("[i=" << i << "] Link ID " << newLinkId << " not valid");
1915  continue;
1916  }
1917  if (!perStaProfile.HasAssocRequest() && !perStaProfile.HasReassocRequest())
1918  {
1919  NS_LOG_DEBUG("[i=" << i << "] No (Re)Association Request frame body present");
1920  continue;
1921  }
1922 
1923  ReceiveAssocRequest(perStaProfile.GetAssocRequest(),
1924  perStaProfile.GetStaMacAddress(),
1925  newLinkId);
1926  GetWifiRemoteStationManager(newLinkId)->SetMldAddress(perStaProfile.GetStaMacAddress(),
1927  mle->GetMldMacAddress());
1928  }
1929  };
1930 
1931  std::visit(recvMle, assoc);
1932 }
1933 
1934 void
1936 {
1937  NS_LOG_FUNCTION(this << *mpdu);
1938  for (auto& i : *PeekPointer(mpdu))
1939  {
1940  auto from = i.second.GetSourceAddr();
1941  auto to = i.second.GetDestinationAddr();
1942 
1943  if (to.IsGroup() || IsAssociated(to))
1944  {
1945  NS_LOG_DEBUG("forwarding QoS frame from=" << from << ", to=" << to);
1946  ForwardDown(i.first->Copy(), from, to, mpdu->GetHeader().GetQosTid());
1947  }
1948 
1949  ForwardUp(i.first, from, to);
1950  }
1951 }
1952 
1953 void
1955 {
1956  NS_LOG_FUNCTION(this);
1958 
1959  for (uint8_t linkId = 0; linkId < GetNLinks(); ++linkId)
1960  {
1961  GetLink(linkId).beaconEvent.Cancel();
1963  {
1964  uint64_t jitterUs =
1966  ? static_cast<uint64_t>(m_beaconJitter->GetValue(0, 1) *
1968  : 0);
1969  NS_LOG_DEBUG("Scheduling initial beacon for access point "
1970  << GetAddress() << " at time " << jitterUs << "us");
1973  this,
1974  linkId);
1975  }
1978  }
1979 
1981  NS_ABORT_IF(
1984 }
1985 
1986 bool
1988 {
1989  bool useProtection = (GetLink(linkId).numNonErpStations > 0) && m_enableNonErpProtection;
1990  GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(useProtection);
1991  return useProtection;
1992 }
1993 
1994 uint16_t
1995 ApWifiMac::GetNextAssociationId(std::list<uint8_t> linkIds)
1996 {
1997  // Return the first AID value between 1 and 2007 that is free for all the given links
1998  for (uint16_t nextAid = 1; nextAid <= 2007; nextAid++)
1999  {
2000  if (std::all_of(linkIds.begin(), linkIds.end(), [&](auto&& linkId) {
2001  auto& staList = GetLink(linkId).staList;
2002  return staList.find(nextAid) == staList.end();
2003  }))
2004  {
2005  return nextAid;
2006  }
2007  }
2008  NS_FATAL_ERROR("No free association ID available!");
2009  return 0;
2010 }
2011 
2012 const std::map<uint16_t, Mac48Address>&
2013 ApWifiMac::GetStaList(uint8_t linkId) const
2014 {
2015  return GetLink(linkId).staList;
2016 }
2017 
2018 uint16_t
2019 ApWifiMac::GetAssociationId(Mac48Address addr, uint8_t linkId) const
2020 {
2021  return GetWifiRemoteStationManager(linkId)->GetAssociationId(addr);
2022 }
2023 
2024 uint8_t
2026 {
2027  auto it = m_bufferStatus.find(WifiAddressTidPair(address, tid));
2028  if (it == m_bufferStatus.end() || it->second.timestamp + m_bsrLifetime < Simulator::Now())
2029  {
2030  return 255;
2031  }
2032  return it->second.value;
2033 }
2034 
2035 void
2037 {
2038  if (size == 255)
2039  {
2040  // no point in storing an unspecified size
2042  }
2043  else
2044  {
2046  }
2047 }
2048 
2049 uint8_t
2051 {
2052  uint8_t maxSize = 0;
2053  bool found = false;
2054 
2055  for (uint8_t tid = 0; tid < 8; tid++)
2056  {
2057  uint8_t size = GetBufferStatus(tid, address);
2058  if (size != 255)
2059  {
2060  maxSize = std::max(maxSize, size);
2061  found = true;
2062  }
2063  }
2064 
2065  if (found)
2066  {
2067  return maxSize;
2068  }
2069  return 255;
2070 }
2071 
2072 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
Wi-Fi AP state machine.
Definition: ap-wifi-mac.h:64
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:142
Ptr< Txop > m_beaconTxop
Dedicated Txop for beacons.
Definition: ap-wifi-mac.h:495
void SetBeaconGeneration(bool enable)
Enable or disable beacon generation of the AP.
Definition: ap-wifi-mac.cc:179
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:242
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:126
void SetBeaconInterval(Time interval)
Definition: ap-wifi-mac.cc:217
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:305
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:482
Ptr< UniformRandomVariable > m_beaconJitter
UniformRandomVariable used to randomize the time of the first beacon.
Definition: ap-wifi-mac.h:499
SupportedRates 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:427
bool CanForwardPacketsTo(Mac48Address to) const override
Return true if packets can be forwarded to the given destination, false otherwise.
Definition: ap-wifi-mac.cc:390
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:501
EdcaParameterSet GetEdcaParameterSet(uint8_t linkId) const
Return the EDCA Parameter Set of the current AP for the given link.
Definition: ap-wifi-mac.cc:514
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:660
HtOperation GetHtOperation(uint8_t linkId) const
Return the HT operation of the current AP for the given link.
Definition: ap-wifi-mac.cc:709
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:265
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:204
TracedCallback< uint16_t, Mac48Address > m_deAssocLogger
deassociation logger
Definition: ap-wifi-mac.h:524
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:496
Time m_beaconInterval
Beacon interval.
Definition: ap-wifi-mac.h:497
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:500
std::unordered_map< WifiAddressTidPair, BsrType, WifiAddressTidHash > m_bufferStatus
Per (MAC address, TID) buffer status reports.
Definition: ap-wifi-mac.h:513
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:910
DsssParameterSet GetDsssParameterSet(uint8_t linkId) const
Return the DSSS Parameter Set that we support on the given link.
Definition: ap-wifi-mac.cc:472
TracedCallback< uint16_t, Mac48Address > m_assocLogger
association logger
Definition: ap-wifi-mac.h:523
Time GetBeaconInterval() const
Definition: ap-wifi-mac.cc:198
static TypeId GetTypeId()
Get the type ID.
Definition: ap-wifi-mac.cc:56
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:629
void Enqueue(Ptr< Packet > packet, Mac48Address to) override
Definition: ap-wifi-mac.cc:410
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:503
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:234
ApLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: ap-wifi-mac.cc:148
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:886
void ConfigureStandard(WifiStandard standard) override
Definition: ap-wifi-mac.cc:154
ErpInformation GetErpInformation(uint8_t linkId) const
Return the ERP information of the current AP for the given link.
Definition: ap-wifi-mac.cc:493
void SetLinkUpCallback(Callback< void > linkUp) override
Definition: ap-wifi-mac.cc:205
VhtOperation GetVhtOperation(uint8_t linkId) const
Return the VHT operation of the current AP for the given link.
Definition: ap-wifi-mac.cc:807
~ApWifiMac() override
Definition: ap-wifi-mac.cc:120
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:856
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:561
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:420
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:289
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:169
void ConfigQueueScheduler(const LinkIdStaAddrMap &linkIdStaAddrMap, const Mac48Address &to, uint8_t linkId)
Configure the queue scheduler so that frames stored in the container queues associated with the stati...
bool GetUseNonErpProtection(uint8_t linkId) const
Return whether protection for non-ERP stations is used in the BSS corresponding to the given link.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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.
EHT Operation Information Element.
Definition: eht-operation.h:67
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.
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 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:88
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.
Definition: ht-operation.cc:90
void SetSecondaryChannelOffset(uint8_t secondaryChannelOffset)
Set the secondary channel offset.
Definition: ht-operation.cc:78
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.
Definition: ht-operation.cc:96
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.
Definition: ht-operation.cc:84
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:72
void SetDualCtsProtection(uint8_t dualCtsProtection)
Set the dual CTS protection.
void SetPhase(uint8_t pcoPhase)
Set the PCO phase.
void SetStbcBeacon(uint8_t stbcBeacon)
Set the STBC beacon.
an EUI-48 address
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:55
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:447
void SetHeCapabilities(const HeCapabilities &heCapabilities)
Set the HE capabilities.
const std::optional< MultiLinkElement > & GetMultiLinkElement() const
Return the Multi-Link Element information element, if present.
StatusCode GetStatusCode()
Return the status code.
void SetHtOperation(const HtOperation &htOperation)
Set the HT operation.
void SetMuEdcaParameterSet(const MuEdcaParameterSet &muEdcaParameterSet)
Set the MU EDCA Parameter Set.
void SetEdcaParameterSet(const EdcaParameterSet &edcaParameterSet)
Set the EDCA Parameter Set.
void SetEhtCapabilities(const EhtCapabilities &ehtCapabilities)
Set the EHT capabilities.
void SetStatusCode(StatusCode code)
Set the status code.
void SetVhtOperation(const VhtOperation &vhtOperation)
Set the VHT operation.
void SetHeOperation(const HeOperation &heOperation)
Set the HE operation.
void SetAssociationId(uint16_t aid)
Set the association ID.
void SetCapabilities(const CapabilityInformation &capabilities)
Set the Capability information.
void SetEhtOperation(const EhtOperation &ehtOperation)
Set the EHT operation.
void SetVhtCapabilities(const VhtCapabilities &vhtCapabilities)
Set the VHT capabilities.
void SetSupportedRates(const SupportedRates &rates)
Set the supported rates.
void SetExtendedCapabilities(const ExtendedCapabilities &extendedCapabilities)
Set the extended capabilities.
void SetHtCapabilities(const HtCapabilities &htCapabilities)
Set the HT capabilities.
void SetMultiLinkElement(const MultiLinkElement &multiLinkElement)
Set the Multi-Link Element information element.
void SetErpInformation(const ErpInformation &erpInformation)
Set the ERP information.
Implement the header for management frames of type beacon.
Definition: mgt-headers.h:1257
Implement the header for management frames of type probe request.
Definition: mgt-headers.h:754
const Ssid & GetSsid() const
Return the Service Set Identifier (SSID).
Definition: mgt-headers.cc:53
Implement the header for management frames of type probe response.
Definition: mgt-headers.h:903
void SetVhtOperation(const VhtOperation &vhtOperation)
Set the VHT operation.
Definition: mgt-headers.cc:421
void SetHtOperation(const HtOperation &htOperation)
Set the HT operation.
Definition: mgt-headers.cc:385
void SetDsssParameterSet(const DsssParameterSet &dsssParameterSet)
Set the DSSS Parameter Set.
Definition: mgt-headers.cc:541
void SetCapabilities(const CapabilityInformation &capabilities)
Set the Capability information.
Definition: mgt-headers.cc:331
void SetReducedNeighborReport(const ReducedNeighborReport &reducedNeighborReport)
Set the Reduced Neighbor Report information element.
Definition: mgt-headers.cc:601
void SetEhtCapabilities(const EhtCapabilities &ehtCapabilities)
Set the EHT capabilities.
Definition: mgt-headers.cc:475
void SetVhtCapabilities(const VhtCapabilities &vhtCapabilities)
Set the VHT capabilities.
Definition: mgt-headers.cc:403
void SetHtCapabilities(const HtCapabilities &htCapabilities)
Set the HT capabilities.
Definition: mgt-headers.cc:367
void SetSsid(const Ssid &ssid)
Set the Service Set Identifier (SSID).
Definition: mgt-headers.cc:511
void SetSupportedRates(const SupportedRates &rates)
Set the supported rates.
Definition: mgt-headers.cc:529
void SetHeOperation(const HeOperation &heOperation)
Set the HE operation.
Definition: mgt-headers.cc:457
void SetErpInformation(const ErpInformation &erpInformation)
Set the ERP information.
Definition: mgt-headers.cc:559
void SetExtendedCapabilities(const ExtendedCapabilities &extendedCapabilities)
Set the extended capabilities.
Definition: mgt-headers.cc:349
void SetBeaconIntervalUs(uint64_t us)
Set the beacon interval in microseconds unit.
Definition: mgt-headers.cc:523
void SetEdcaParameterSet(const EdcaParameterSet &edcaParameterSet)
Set the EDCA Parameter Set.
Definition: mgt-headers.cc:577
void SetHeCapabilities(const HeCapabilities &heCapabilities)
Set the HE capabilities.
Definition: mgt-headers.cc:439
void SetMuEdcaParameterSet(const MuEdcaParameterSet &muEdcaParameterSet)
Set the MU EDCA Parameter Set.
Definition: mgt-headers.cc:589
void SetMultiLinkElement(const MultiLinkElement &multiLinkElement)
Set the Multi-Link Element information element.
Definition: mgt-headers.cc:613
void SetEhtOperation(const EhtOperation &ehtOperation)
Set the EHT operation.
Definition: mgt-headers.cc:493
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:248
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:311
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:863
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:78
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:251
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:229
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:240
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:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
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.
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.
uint8_t GetNRates() const
Return the number of supported rates.
void AddSupportedRate(uint64_t bs)
Add the given rate to the supported rates.
bool IsSupportedRate(uint64_t bs) const
Check if the given rate is supported.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:314
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
AttributeValue implementation for Time.
Definition: nstime.h:1423
Time Get() const
Definition: time.cc:532
Time GetTxopLimit() const
Return the TXOP limit.
Definition: txop.cc:473
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:220
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the wifi MAC this Txop is associated to.
Definition: txop.cc:195
void SetMaxCws(std::vector< uint32_t > maxCws)
Set the maximum contention window size for each link.
Definition: txop.cc:262
void SetTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set MacTxMiddle this Txop is associated to.
Definition: txop.cc:188
void SetMinCws(std::vector< uint32_t > minCws)
Set the minimum contention window size for each link.
Definition: txop.cc:233
void SetAifsns(std::vector< uint8_t > aifsns)
Set the number of slots that make up an AIFS for each link.
Definition: txop.cc:359
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:505
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
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 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.
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.
bool IsDisassociation() const
Return true if the header is a Disassociation header.
void SetQosTxopLimit(uint8_t txop)
Set TXOP limit in the QoS control field.
WifiMacType GetType() const
Return the type (enum 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.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetQosNoAmsdu()
Set that A-MSDU is not present.
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:94
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:840
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition: wifi-mac.cc:524
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1236
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1353
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition: wifi-mac.cc:484
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition: wifi-mac.cc:1590
bool GetQosSupported() const
Return whether the device supports QoS.
Definition: wifi-mac.cc:1006
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:906
Ptr< WifiMacQueueScheduler > m_scheduler
wifi MAC queue scheduler
Definition: wifi-mac.h:754
void DoInitialize() override
Initialize() implementation.
Definition: wifi-mac.cc:353
virtual void ConfigureStandard(WifiStandard standard)
Definition: wifi-mac.cc:724
Ssid GetSsid() const
Definition: wifi-mac.cc:456
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition: wifi-mac.cc:1012
bool GetHtSupported() const
Return whether the device supports HT.
Definition: wifi-mac.cc:1365
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition: wifi-mac.cc:512
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition: wifi-mac.cc:411
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:954
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition: wifi-mac.cc:1384
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1378
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition: wifi-mac.cc:1533
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:912
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition: wifi-mac.cc:1371
Ptr< MacTxMiddle > m_txMiddle
TX middle (aggregation etc.)
Definition: wifi-mac.h:752
Ptr< HtConfiguration > GetHtConfiguration() const
Definition: wifi-mac.cc:1341
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition: wifi-mac.cc:1522
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:536
bool GetShortSlotTimeSupported() const
Definition: wifi-mac.cc:1056
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:595
virtual void SetLinkUpCallback(Callback< void > linkUp)
Definition: wifi-mac.cc:1075
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:886
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition: wifi-mac.cc:1100
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:1107
Mac48Address GetAddress() const
Definition: wifi-mac.cc:443
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition: wifi-mac.cc:1727
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: wifi-mac.cc:898
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition: wifi-mac.cc:1671
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:490
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:577
void DoDispose() override
Destructor implementation.
Definition: wifi-mac.cc:369
bool GetDsssSupported(uint8_t linkId) const
Return whether the device supports DSSS on the given link.
Definition: wifi-mac.cc:1036
represent a single transmission mode
Definition: wifi-mode.h:50
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:1295
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition: wifi-phy.cc:780
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:1008
void SetShortSlotTimeEnabled(bool enable)
Enable or disable short slot time.
void AddBasicMode(WifiMode mode)
Invoked in a STA upon association to store the set of rates which belong to the BSSBasicRateSet of th...
uint16_t GetAssociationId(Mac48Address remoteAddress) const
Get the AID of a remote station.
uint8_t GetNBasicModes() const
Return the number of basic modes we support.
void SetUseNonErpProtection(bool enable)
Enable or disable protection for non-ERP stations.
std::optional< Mac48Address > GetAffiliatedStaAddress(const Mac48Address &mldAddress) const
Get the address of the remote station operating on this link and affiliated with the MLD having the g...
void SetShortPreambleEnabled(bool enable)
Enable or disable short PHY preambles.
bool IsAssociated(Mac48Address address) const
Return whether the station associated.
void SetMldAddress(const Mac48Address &address, const Mac48Address &mldAddress)
Set the address of the MLD the given station is affiliated with.
void RecordGotAssocTxOk(Mac48Address address)
Records that we got an ACK for the association response we sent.
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
void RecordDisassociated(Mac48Address address)
Records that the STA was disassociated.
void RecordGotAssocTxFailed(Mac48Address address)
Records that we missed an ACK for the association response we sent.
std::optional< Mac48Address > GetMldAddress(const Mac48Address &address) const
Get the address of the MLD the given station is affiliated with, if any.
bool IsWaitAssocTxOk(Mac48Address address) const
Return whether we are waiting for an ACK for the association response we sent.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:231
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1424
#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:1360
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
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:75
uint8_t QosUtilsGetTidForPacket(Ptr< const Packet > packet)
If a QoS tag is attached to the packet, returns a value < 8.
Definition: qos-utils.cc:160
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:72
@ 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:74
@ AC_VO
Voice.
Definition: qos-utils.h:80
@ AC_VI
Video.
Definition: qos-utils.h:78
@ AC_BK
Background.
Definition: qos-utils.h:76
@ AC_BEACON
Beacon queue.
Definition: qos-utils.h:84
address
Definition: first.py:40
Every class exported by the ns3 library is enclosed in the ns3 namespace.
@ AP
Definition: wifi-mac.h:63
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:707
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:54
@ 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:535
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition: wifi-utils.h:140
constexpr uint8_t WIFI_EHT_MAX_MCS_INDEX
IEEE 802.11be D2.0 Figure 9-1002ai.
Definition: eht-operation.h:33
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition: qos-utils.cc:126
WifiMacType
Combination of valid MAC header type/subtype.
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_PROBE_RESPONSE
@ WIFI_MAC_DATA
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
@ WIFI_MAC_QOSDATA
@ WIFI_QOSDATA_UNICAST_QUEUE
std::pair< Mac48Address, uint8_t > WifiAddressTidPair
(MAC address, TID) pair
Definition: qos-utils.h:33
std::tuple< WifiContainerQueueType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, Address, TID) identifying a container queue.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:488
ssid
Definition: third.py:86
phy
Definition: third.py:82