A Discrete-Event Network Simulator
API
sta-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 "sta-wifi-mac.h"
23 
24 #include "channel-access-manager.h"
25 #include "frame-exchange-manager.h"
26 #include "mgt-action-headers.h"
27 #include "mgt-headers.h"
28 #include "qos-txop.h"
29 #include "snr-tag.h"
30 #include "wifi-assoc-manager.h"
31 #include "wifi-mac-queue.h"
32 #include "wifi-net-device.h"
33 #include "wifi-phy.h"
34 
35 #include "ns3/attribute-container.h"
36 #include "ns3/eht-configuration.h"
37 #include "ns3/emlsr-manager.h"
38 #include "ns3/he-configuration.h"
39 #include "ns3/ht-configuration.h"
40 #include "ns3/log.h"
41 #include "ns3/packet.h"
42 #include "ns3/pair.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 #include <numeric>
49 
50 namespace ns3
51 {
52 
53 NS_LOG_COMPONENT_DEFINE("StaWifiMac");
54 
55 NS_OBJECT_ENSURE_REGISTERED(StaWifiMac);
56 
57 TypeId
59 {
60  static TypeId tid =
61  TypeId("ns3::StaWifiMac")
62  .SetParent<WifiMac>()
63  .SetGroupName("Wifi")
64  .AddConstructor<StaWifiMac>()
65  .AddAttribute("ProbeRequestTimeout",
66  "The duration to actively probe the channel.",
67  TimeValue(Seconds(0.05)),
70  .AddAttribute("WaitBeaconTimeout",
71  "The duration to dwell on a channel while passively scanning for beacon",
72  TimeValue(MilliSeconds(120)),
75  .AddAttribute("AssocRequestTimeout",
76  "The interval between two consecutive association request attempts.",
77  TimeValue(Seconds(0.5)),
80  .AddAttribute("MaxMissedBeacons",
81  "Number of beacons which much be consecutively missed before "
82  "we attempt to restart association.",
83  UintegerValue(10),
85  MakeUintegerChecker<uint32_t>())
86  .AddAttribute(
87  "ActiveProbing",
88  "If true, we send probe requests. If false, we don't."
89  "NOTE: if more than one STA in your simulation is using active probing, "
90  "you should enable it at a different simulation time for each STA, "
91  "otherwise all the STAs will start sending probes at the same time resulting in "
92  "collisions. "
93  "See bug 1060 for more info.",
94  BooleanValue(false),
97  .AddAttribute("ProbeDelay",
98  "Delay (in microseconds) to be used prior to transmitting a "
99  "Probe frame during active scanning.",
100  StringValue("ns3::UniformRandomVariable[Min=50.0|Max=250.0]"),
102  MakePointerChecker<RandomVariableStream>())
103  .AddAttribute(
104  "PowerSaveMode",
105  "Enable/disable power save mode on the given link. The power management mode is "
106  "actually changed when the AP acknowledges a frame sent with the Power Management "
107  "field set to the value corresponding to the requested mode",
108  TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
110  MakePairAccessor<BooleanValue, UintegerValue>(&StaWifiMac::SetPowerSaveMode),
111  MakePairChecker<BooleanValue, UintegerValue>(MakeBooleanChecker(),
112  MakeUintegerChecker<uint8_t>()))
113  .AddAttribute("PmModeSwitchTimeout",
114  "If switching to a new Power Management mode is not completed within "
115  "this amount of time, make another attempt at switching Power "
116  "Management mode.",
117  TimeValue(Seconds(0.1)),
119  MakeTimeChecker())
120  .AddTraceSource("Assoc",
121  "Associated with an access point. If this is an MLD that associated "
122  "with an AP MLD, the AP MLD address is provided.",
124  "ns3::Mac48Address::TracedCallback")
125  .AddTraceSource("LinkSetupCompleted",
126  "A link was setup in the context of ML setup with an AP MLD. "
127  "Provides ID of the setup link and AP MAC address",
129  "ns3::StaWifiMac::LinkSetupCallback")
130  .AddTraceSource("DeAssoc",
131  "Association with an access point lost. If this is an MLD "
132  "that disassociated with an AP MLD, the AP MLD address is provided.",
134  "ns3::Mac48Address::TracedCallback")
135  .AddTraceSource("LinkSetupCanceled",
136  "A link setup in the context of ML setup with an AP MLD was torn down. "
137  "Provides ID of the setup link and AP MAC address",
139  "ns3::StaWifiMac::LinkSetupCallback",
141  "Disassociation only occurs at MLD level; use DeAssoc trace.")
142  .AddTraceSource("BeaconArrival",
143  "Time of beacons arrival from associated AP",
145  "ns3::Time::TracedCallback")
146  .AddTraceSource("ReceivedBeaconInfo",
147  "Information about every received Beacon frame",
149  "ns3::ApInfo::TracedCallback");
150  return tid;
151 }
152 
154  : m_state(UNASSOCIATED),
155  m_aid(0),
156  m_assocRequestEvent()
157 {
158  NS_LOG_FUNCTION(this);
159 
160  // Let the lower layers know that we are acting as a non-AP STA in
161  // an infrastructure BSS.
163 }
164 
165 void
167 {
168  NS_LOG_FUNCTION(this);
169  // an EMLSR client must perform ML setup by using its main PHY
171  {
172  auto mainPhyId = m_emlsrManager->GetMainPhyId();
173  auto linkId = GetLinkForPhy(mainPhyId);
174  NS_ASSERT(linkId);
175  m_assocManager->SetAttribute(
176  "AllowedLinks",
177  AttributeContainerValue<UintegerValue>(std::list<uint8_t>{*linkId}));
178  }
179  if (m_emlsrManager)
180  {
181  m_emlsrManager->Initialize();
182  }
183  StartScanning();
186 }
187 
188 void
190 {
191  NS_LOG_FUNCTION(this);
192  if (m_assocManager)
193  {
194  m_assocManager->Dispose();
195  }
196  m_assocManager = nullptr;
197  if (m_emlsrManager)
198  {
199  m_emlsrManager->Dispose();
200  }
201  m_emlsrManager = nullptr;
203 }
204 
206 {
207  NS_LOG_FUNCTION(this);
208 }
209 
211 {
213 }
214 
215 std::unique_ptr<WifiMac::LinkEntity>
217 {
218  return std::make_unique<StaLinkEntity>();
219 }
220 
222 StaWifiMac::GetLink(uint8_t linkId) const
223 {
224  return static_cast<StaLinkEntity&>(WifiMac::GetLink(linkId));
225 }
226 
228 StaWifiMac::GetStaLink(const std::unique_ptr<WifiMac::LinkEntity>& link) const
229 {
230  return static_cast<StaLinkEntity&>(*link);
231 }
232 
233 int64_t
235 {
236  NS_LOG_FUNCTION(this << stream);
237  m_probeDelay->SetStream(stream);
238  return 1;
239 }
240 
241 void
243 {
244  NS_LOG_FUNCTION(this << assocManager);
245  m_assocManager = assocManager;
246  m_assocManager->SetStaWifiMac(this);
247 }
248 
249 void
251 {
252  NS_LOG_FUNCTION(this << emlsrManager);
253  m_emlsrManager = emlsrManager;
254  m_emlsrManager->SetWifiMac(this);
255 }
256 
259 {
260  return m_emlsrManager;
261 }
262 
263 uint16_t
265 {
266  NS_ASSERT_MSG(IsAssociated(), "This station is not associated to any AP");
267  return m_aid;
268 }
269 
270 void
272 {
273  NS_LOG_FUNCTION(this << enable);
274  m_activeProbing = enable;
275  if (m_state == SCANNING)
276  {
277  NS_LOG_DEBUG("STA is still scanning, reset scanning process");
278  StartScanning();
279  }
280 }
281 
282 bool
284 {
285  return m_activeProbing;
286 }
287 
288 void
289 StaWifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
290 {
291  NS_LOG_FUNCTION(this);
292  WifiMac::SetWifiPhys(phys);
293  for (auto& phy : phys)
294  {
295  phy->SetCapabilitiesChangedCallback(
297  }
298 }
299 
301 StaWifiMac::GetCurrentChannel(uint8_t linkId) const
302 {
303  auto phy = GetWifiPhy(linkId);
304  uint16_t width = phy->GetOperatingChannel().IsOfdm() ? 20 : phy->GetChannelWidth();
305  uint8_t ch = phy->GetOperatingChannel().GetPrimaryChannelNumber(width, phy->GetStandard());
306  return {ch, phy->GetPhyBand()};
307 }
308 
309 void
310 StaWifiMac::NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds)
311 {
312  NS_LOG_FUNCTION(this << linkIds.size());
313 
314  for (const auto& [linkId, lnk] : GetLinks())
315  {
316  auto& link = GetStaLink(lnk);
317 
318  if (linkIds.count(linkId) > 0)
319  {
320  // EMLSR mode enabled
321  link.emlsrEnabled = true;
322  link.pmMode = WIFI_PM_ACTIVE;
323  }
324  else
325  {
326  // EMLSR mode disabled
327  if (link.emlsrEnabled)
328  {
329  link.pmMode = WIFI_PM_POWERSAVE;
330  }
331  link.emlsrEnabled = false;
332  }
333  }
334 }
335 
336 bool
337 StaWifiMac::IsEmlsrLink(uint8_t linkId) const
338 {
339  return GetLink(linkId).emlsrEnabled;
340 }
341 
342 void
344 {
345  NS_LOG_FUNCTION(this << linkId);
346  WifiMacHeader hdr;
351  hdr.SetDsNotFrom();
352  hdr.SetDsNotTo();
353  Ptr<Packet> packet = Create<Packet>();
354  MgtProbeRequestHeader probe;
355  probe.Get<Ssid>() = GetSsid();
356  auto supportedRates = GetSupportedRates(linkId);
357  probe.Get<SupportedRates>() = supportedRates.rates;
358  probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
359  if (GetHtSupported())
360  {
362  probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
363  }
364  if (GetVhtSupported(linkId))
365  {
366  probe.Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
367  }
368  if (GetHeSupported())
369  {
370  probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
371  }
372  if (GetEhtSupported())
373  {
374  probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
375  }
376  packet->AddHeader(probe);
377 
378  if (!GetQosSupported())
379  {
380  GetTxop()->Queue(packet, hdr);
381  }
382  // "A QoS STA that transmits a Management frame determines access category used
383  // for medium access in transmission of the Management frame as follows
384  // (If dot11QMFActivated is false or not present)
385  // — If the Management frame is individually addressed to a non-QoS STA, category
386  // AC_BE should be selected.
387  // — If category AC_BE was not selected by the previous step, category AC_VO
388  // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
389  else
390  {
391  GetVOQueue()->Queue(packet, hdr);
392  }
393 }
394 
395 std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader>
396 StaWifiMac::GetAssociationRequest(bool isReassoc, uint8_t linkId) const
397 {
398  NS_LOG_FUNCTION(this << isReassoc << +linkId);
399 
400  std::variant<MgtAssocRequestHeader, MgtReassocRequestHeader> mgtFrame;
401 
402  if (isReassoc)
403  {
404  MgtReassocRequestHeader reassoc;
405  reassoc.SetCurrentApAddress(GetBssid(linkId));
406  mgtFrame = std::move(reassoc);
407  }
408  else
409  {
410  mgtFrame = MgtAssocRequestHeader();
411  }
412 
413  // lambda to set the fields of the (Re)Association Request
414  auto fill = [&](auto&& frame) {
415  frame.template Get<Ssid>() = GetSsid();
416  auto supportedRates = GetSupportedRates(linkId);
417  frame.template Get<SupportedRates>() = supportedRates.rates;
418  frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
419  frame.Capabilities() = GetCapabilities(linkId);
420  frame.SetListenInterval(0);
421  if (GetHtSupported())
422  {
423  frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
424  frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
425  }
426  if (GetVhtSupported(linkId))
427  {
428  frame.template Get<VhtCapabilities>() = GetVhtCapabilities(linkId);
429  }
430  if (GetHeSupported())
431  {
432  frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
433  }
434  if (GetEhtSupported())
435  {
436  frame.template Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
437  }
438  };
439 
440  std::visit(fill, mgtFrame);
441  return mgtFrame;
442 }
443 
445 StaWifiMac::GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
446 {
447  NS_LOG_FUNCTION(this << isReassoc << +linkId);
448 
450  // The Common info field of the Basic Multi-Link element carried in the (Re)Association
451  // Request frame shall include the MLD MAC address, the MLD Capabilities and Operations,
452  // and the EML Capabilities subfields, and shall not include the Link ID Info, the BSS
453  // Parameters Change Count, and the Medium Synchronization Delay Information subfields
454  // (Sec. 35.3.5.4 of 802.11be D2.0)
455  // TODO Add the MLD Capabilities and Operations subfield
456  multiLinkElement.SetMldMacAddress(GetAddress());
457 
458  if (m_emlsrManager) // EMLSR Manager is only installed if EMLSR is activated
459  {
460  multiLinkElement.SetEmlsrSupported(true);
461  TimeValue time;
462  m_emlsrManager->GetAttribute("EmlsrPaddingDelay", time);
463  multiLinkElement.SetEmlsrPaddingDelay(time.Get());
464  m_emlsrManager->GetAttribute("EmlsrTransitionDelay", time);
465  multiLinkElement.SetEmlsrTransitionDelay(time.Get());
466  // When the Transition Timeout subfield is included in a frame sent by a non-AP STA
467  // affiliated with a non-AP MLD, the Transition Timeout subfield is reserved
468  // (Section 9.4.2.312.2.3 of 802.11be D2.3)
469  // The Medium Synchronization Delay Information subfield in the Common Info subfield is
470  // not present if the Basic Multi-Link element is sent by a non-AP STA. (Section
471  // 9.4.2.312.2.3 of 802.11be D3.1)
472  }
473 
474  // The MLD Capabilities And Operations subfield is present in the Common Info field of the
475  // Basic Multi-Link element carried in Beacon, Probe Response, (Re)Association Request, and
476  // (Re)Association Response frames. (Sec. 9.4.2.312.2.3 of 802.11be D3.1)
477  auto& mldCapabilities = multiLinkElement.GetCommonInfoBasic().m_mldCapabilities;
478  mldCapabilities.emplace();
479  mldCapabilities->maxNSimultaneousLinks = GetNLinks() - 1; // assuming STR for now
480  mldCapabilities->srsSupport = 0;
481 
482  auto ehtConfiguration = GetEhtConfiguration();
483  NS_ASSERT(ehtConfiguration);
485  ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
486 
487  mldCapabilities->tidToLinkMappingSupport = negSupport.Get();
488  mldCapabilities->freqSepForStrApMld = 0; // not supported yet
489  mldCapabilities->aarSupport = 0; // not supported yet
490 
491  // For each requested link in addition to the link on which the (Re)Association Request
492  // frame is transmitted, the Link Info field of the Basic Multi-Link element carried
493  // in the (Re)Association Request frame shall contain the corresponding Per-STA Profile
494  // subelement(s).
495  for (const auto& [index, link] : GetLinks())
496  {
497  const auto& staLink = GetStaLink(link);
498 
499  if (index != linkId && staLink.bssid.has_value())
500  {
501  multiLinkElement.AddPerStaProfileSubelement();
502  auto& perStaProfile = multiLinkElement.GetPerStaProfile(
503  multiLinkElement.GetNPerStaProfileSubelements() - 1);
504  // The Link ID subfield of the STA Control field of the Per-STA Profile subelement
505  // for the corresponding non-AP STA that requests a link for multi-link (re)setup
506  // with the AP MLD is set to the link ID of the AP affiliated with the AP MLD that
507  // is operating on that link. The link ID is obtained during multi-link discovery
508  perStaProfile.SetLinkId(index);
509  // For each Per-STA Profile subelement included in the Link Info field, the
510  // Complete Profile subfield of the STA Control field shall be set to 1
511  perStaProfile.SetCompleteProfile();
512  // The MAC Address Present subfield indicates the presence of the STA MAC Address
513  // subfield in the STA Info field and is set to 1 if the STA MAC Address subfield
514  // is present in the STA Info field; otherwise set to 0. An STA sets this subfield
515  // to 1 when the element carries complete profile.
516  perStaProfile.SetStaMacAddress(staLink.feManager->GetAddress());
517  perStaProfile.SetAssocRequest(GetAssociationRequest(isReassoc, index));
518  }
519  }
520 
521  return multiLinkElement;
522 }
523 
524 std::vector<TidToLinkMapping>
526 {
527  NS_LOG_FUNCTION(this << apNegSupport);
528 
529  auto ehtConfig = GetEhtConfiguration();
530  NS_ASSERT(ehtConfig);
531 
533  ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
534 
535  NS_ABORT_MSG_IF(negSupport.Get() == 0,
536  "Cannot request TID-to-Link Mapping if negotiation is not supported");
537 
538  // store the mappings, so that we can enforce them when the AP MLD accepts them
539  m_dlTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
540  m_ulTidLinkMappingInAssocReq = ehtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
541 
542  bool mappingValidForNegType1 = TidToLinkMappingValidForNegType1(m_dlTidLinkMappingInAssocReq,
545  negSupport.Get() == 1 && !mappingValidForNegType1,
546  "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
547 
548  if (apNegSupport == 1 && !mappingValidForNegType1)
549  {
550  // If the TID-to-link Mapping Negotiation Support subfield value received from a peer
551  // MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
552  // peer MLD shall send only the TID-to-link Mapping element where all TIDs are mapped to
553  // the same link set (Sec. 35.3.7.1.3 of 802.11be D3.1). We use default mapping to meet
554  // this requirement.
555  NS_LOG_DEBUG("Using default mapping because AP MLD advertised negotiation support of 1");
558  }
559 
560  std::vector<TidToLinkMapping> ret(1);
561 
562  ret.back().m_control.direction = WifiDirection::DOWNLINK;
563 
564  // lambda to fill the last TID-to-Link Mapping IE in the vector to return
565  auto fillIe = [&ret](const auto& mapping) {
566  ret.back().m_control.defaultMapping = mapping.empty();
567 
568  for (const auto& [tid, linkSet] : mapping)
569  {
570  // At any point in time, a TID shall always be mapped to at least one setup link both
571  // in DL and UL, which means that a TID-to-link mapping change is only valid and
572  // successful if it will not result in having any TID for which the link set for DL
573  // or UL is made of zero setup links (Sec. 35.3.7.1.1 of 802.11be D3.1)
574  NS_ABORT_MSG_IF(linkSet.empty(), "Cannot map a TID to an empty link set");
575  ret.back().SetLinkMappingOfTid(tid, linkSet);
576  }
577  };
578 
580 
582  {
583  ret.back().m_control.direction = WifiDirection::BOTH_DIRECTIONS;
584  return ret;
585  }
586 
587  ret.emplace_back();
588  ret.back().m_control.direction = WifiDirection::UPLINK;
590 
591  return ret;
592 }
593 
594 void
596 {
597  // find the link where the (Re)Association Request has to be sent
598  auto it = GetLinks().cbegin();
599  while (it != GetLinks().cend())
600  {
601  if (GetStaLink(it->second).sendAssocReq)
602  {
603  break;
604  }
605  it++;
606  }
607  NS_ABORT_MSG_IF(it == GetLinks().cend(),
608  "No link selected to send the (Re)Association Request");
609  uint8_t linkId = it->first;
610  auto& link = GetLink(linkId);
611  NS_ABORT_MSG_IF(!link.bssid.has_value(),
612  "No BSSID set for the link on which the (Re)Association Request is to be sent");
613 
614  NS_LOG_FUNCTION(this << *link.bssid << isReassoc);
615  WifiMacHeader hdr;
617  hdr.SetAddr1(*link.bssid);
618  hdr.SetAddr2(link.feManager->GetAddress());
619  hdr.SetAddr3(*link.bssid);
620  hdr.SetDsNotFrom();
621  hdr.SetDsNotTo();
622  Ptr<Packet> packet = Create<Packet>();
623 
624  auto frame = GetAssociationRequest(isReassoc, linkId);
625 
626  // include a Multi-Link Element if this device has multiple links (independently
627  // of how many links will be setup) and the AP is a multi-link device;
628  // if the AP MLD has indicated a support of TID-to-link mapping negotiation, also
629  // include the TID-to-link Mapping element(s)
630  if (GetNLinks() > 1 &&
631  GetWifiRemoteStationManager(linkId)->GetMldAddress(*link.bssid).has_value())
632  {
633  auto addMle = [&](auto&& frame) {
634  frame.template Get<MultiLinkElement>() = GetMultiLinkElement(isReassoc, linkId);
635  };
636  std::visit(addMle, frame);
637 
638  uint8_t negSupport;
639  if (const auto& mldCapabilities =
640  GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
641  mldCapabilities && (negSupport = mldCapabilities->get().tidToLinkMappingSupport) > 0)
642  {
643  auto addTlm = [&](auto&& frame) {
644  frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
645  };
646  std::visit(addTlm, frame);
647  }
648  }
649 
650  if (!isReassoc)
651  {
652  packet->AddHeader(std::get<MgtAssocRequestHeader>(frame));
653  }
654  else
655  {
656  packet->AddHeader(std::get<MgtReassocRequestHeader>(frame));
657  }
658 
659  if (!GetQosSupported())
660  {
661  GetTxop()->Queue(packet, hdr);
662  }
663  // "A QoS STA that transmits a Management frame determines access category used
664  // for medium access in transmission of the Management frame as follows
665  // (If dot11QMFActivated is false or not present)
666  // — If the Management frame is individually addressed to a non-QoS STA, category
667  // AC_BE should be selected.
668  // — If category AC_BE was not selected by the previous step, category AC_VO
669  // shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
670  else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(*link.bssid))
671  {
672  GetBEQueue()->Queue(packet, hdr);
673  }
674  else
675  {
676  GetVOQueue()->Queue(packet, hdr);
677  }
678 
680  {
682  }
685 }
686 
687 void
689 {
690  NS_LOG_FUNCTION(this);
691  switch (m_state)
692  {
693  case ASSOCIATED:
694  return;
695  case SCANNING:
696  /* we have initiated active or passive scanning, continue to wait
697  and gather beacons or probe responses until the scanning timeout
698  */
699  break;
700  case UNASSOCIATED:
701  /* we were associated but we missed a bunch of beacons
702  * so we should assume we are not associated anymore.
703  * We try to initiate a scan now.
704  */
705  m_linkDown();
706  StartScanning();
707  break;
708  case WAIT_ASSOC_RESP:
709  /* we have sent an association request so we do not need to
710  re-send an association request right now. We just need to
711  wait until either assoc-request-timeout or until
712  we get an association response.
713  */
714  break;
715  case REFUSED:
716  /* we have sent an association request and received a negative
717  association response. We wait until someone restarts an
718  association with a given SSID.
719  */
720  break;
721  }
722 }
723 
724 void
726 {
727  NS_LOG_FUNCTION(this);
730 
731  WifiScanParams scanParams;
732  scanParams.ssid = GetSsid();
733  for (const auto& [id, link] : GetLinks())
734  {
736  (link->phy->HasFixedPhyBand()) ? WifiScanParams::Channel{0, link->phy->GetPhyBand()}
738 
739  scanParams.channelList.push_back(channel);
740  }
741  if (m_activeProbing)
742  {
743  scanParams.type = WifiScanType::ACTIVE;
744  scanParams.probeDelay = MicroSeconds(m_probeDelay->GetValue());
745  scanParams.minChannelTime = scanParams.maxChannelTime = m_probeRequestTimeout;
746  }
747  else
748  {
749  scanParams.type = WifiScanType::PASSIVE;
750  scanParams.maxChannelTime = m_waitBeaconTimeout;
751  }
752 
753  m_assocManager->StartScanning(std::move(scanParams));
754 }
755 
756 void
757 StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& bestAp)
758 {
759  NS_LOG_FUNCTION(this);
760 
761  if (!bestAp.has_value())
762  {
763  NS_LOG_DEBUG("Exhausted list of candidate AP; restart scanning");
764  StartScanning();
765  return;
766  }
767 
768  NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp);
769  UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId);
770  // reset info on links to setup
771  for (auto& [id, link] : GetLinks())
772  {
773  auto& staLink = GetStaLink(link);
774  staLink.sendAssocReq = false;
775  staLink.bssid = std::nullopt;
776  }
777  // send Association Request on the link where the Beacon/Probe Response was received
778  GetLink(bestAp->m_linkId).sendAssocReq = true;
779  GetLink(bestAp->m_linkId).bssid = bestAp->m_bssid;
780  std::shared_ptr<CommonInfoBasicMle> mleCommonInfo;
781  // update info on links to setup (11be MLDs only)
782  const auto& mle =
783  std::visit([](auto&& frame) { return frame.template Get<MultiLinkElement>(); },
784  bestAp->m_frame);
785  std::map<uint8_t, uint8_t> swapInfo;
786  for (const auto& [localLinkId, apLinkId, bssid] : bestAp->m_setupLinks)
787  {
788  NS_ASSERT_MSG(mle, "We get here only for ML setup");
789  NS_LOG_DEBUG("Setting up link (local ID=" << +localLinkId << ", AP ID=" << +apLinkId
790  << ")");
791  GetLink(localLinkId).bssid = bssid;
792  if (!mleCommonInfo)
793  {
794  mleCommonInfo = std::make_shared<CommonInfoBasicMle>(mle->GetCommonInfoBasic());
795  }
796  GetWifiRemoteStationManager(localLinkId)->AddStationMleCommonInfo(bssid, mleCommonInfo);
797  swapInfo.emplace(localLinkId, apLinkId);
798  }
799 
800  SwapLinks(swapInfo);
801 
802  // lambda to get beacon interval from Beacon or Probe Response
803  auto getBeaconInterval = [](auto&& frame) {
804  using T = std::decay_t<decltype(frame)>;
805  if constexpr (std::is_same_v<T, MgtBeaconHeader> ||
806  std::is_same_v<T, MgtProbeResponseHeader>)
807  {
808  return MicroSeconds(frame.GetBeaconIntervalUs());
809  }
810  else
811  {
812  NS_ABORT_MSG("Unexpected frame type");
813  return Seconds(0);
814  }
815  };
816  Time beaconInterval = std::visit(getBeaconInterval, bestAp->m_frame);
817  Time delay = beaconInterval * m_maxMissedBeacons;
818  // restart beacon watchdog
819  RestartBeaconWatchdog(delay);
820 
822  SendAssociationRequest(false);
823 }
824 
825 void
827 {
828  NS_LOG_FUNCTION(this);
830  SendAssociationRequest(false);
831 }
832 
833 void
835 {
836  NS_LOG_FUNCTION(this);
837 
839  {
841  {
843  }
846  this);
847  return;
848  }
849  NS_LOG_DEBUG("beacon missed");
850  // We need to switch to the UNASSOCIATED state. However, if we are receiving a frame, wait
851  // until the RX is completed (otherwise, crashes may occur if we are receiving a MU frame
852  // because its reception requires the STA-ID). We need to check that a PHY is operating on
853  // the given link, because this may (temporarily) not be the case for EMLSR clients.
854  Time delay = Seconds(0);
855  for (const auto& [id, link] : GetLinks())
856  {
857  if (link->phy && link->phy->IsStateRx())
858  {
859  delay = std::max(delay, link->phy->GetDelayUntilIdle());
860  }
861  }
863 }
864 
865 void
867 {
868  NS_LOG_FUNCTION(this);
869 
870  Mac48Address apAddr; // the AP address to trace (MLD address in case of ML setup)
871 
872  for (const auto& [id, link] : GetLinks())
873  {
874  auto& bssid = GetStaLink(link).bssid;
875  if (bssid)
876  {
877  apAddr = GetWifiRemoteStationManager(id)->GetMldAddress(*bssid).value_or(*bssid);
878  }
879  bssid = std::nullopt; // link is no longer setup
880  }
881 
882  NS_LOG_DEBUG("Set state to UNASSOCIATED and start scanning");
884  // cancel the association request timer (see issue #862)
886  m_deAssocLogger(apAddr);
887  m_aid = 0; // reset AID
889 }
890 
891 void
893 {
894  NS_LOG_FUNCTION(this << delay);
895 
898  {
899  NS_LOG_DEBUG("really restart watchdog.");
901  }
902 }
903 
904 bool
906 {
907  return m_state == ASSOCIATED;
908 }
909 
910 bool
912 {
913  return m_state == WAIT_ASSOC_RESP;
914 }
915 
916 std::set<uint8_t>
918 {
919  if (!IsAssociated())
920  {
921  return {};
922  }
923 
924  std::set<uint8_t> linkIds;
925  for (const auto& [id, link] : GetLinks())
926  {
927  if (GetStaLink(link).bssid)
928  {
929  linkIds.insert(id);
930  }
931  }
932  return linkIds;
933 }
934 
937 {
938  auto linkIds = GetSetupLinkIds();
939  NS_ASSERT_MSG(!linkIds.empty(), "Not associated");
940  uint8_t linkId = *linkIds.begin();
941  return GetFrameExchangeManager(linkId)->GetAddress();
942 }
943 
944 bool
946 {
947  return IsAssociated();
948 }
949 
950 void
952 {
953  NS_LOG_FUNCTION(this << packet << to);
954  if (!CanForwardPacketsTo(to))
955  {
956  NotifyTxDrop(packet);
958  return;
959  }
960  WifiMacHeader hdr;
961 
962  // If we are not a QoS AP then we definitely want to use AC_BE to
963  // transmit the packet. A TID of zero will map to AC_BE (through \c
964  // QosUtilsMapTidToAc()), so we use that as our default here.
965  uint8_t tid = 0;
966 
967  // For now, an AP that supports QoS does not support non-QoS
968  // associations, and vice versa. In future the AP model should
969  // support simultaneously associated QoS and non-QoS STAs, at which
970  // point there will need to be per-association QoS state maintained
971  // by the association state machine, and consulted here.
972  if (GetQosSupported())
973  {
976  hdr.SetQosNoEosp();
977  hdr.SetQosNoAmsdu();
978  // Transmission of multiple frames in the same TXOP is not
979  // supported for now
980  hdr.SetQosTxopLimit(0);
981 
982  // Fill in the QoS control field in the MAC header
983  tid = QosUtilsGetTidForPacket(packet);
984  // Any value greater than 7 is invalid and likely indicates that
985  // the packet had no QoS tag, so we revert to zero, which'll
986  // mean that AC_BE is used.
987  if (tid > 7)
988  {
989  tid = 0;
990  }
991  hdr.SetQosTid(tid);
992  }
993  else
994  {
995  hdr.SetType(WIFI_MAC_DATA);
996  }
997  if (GetQosSupported())
998  {
999  hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
1000  // yet implemented (set it to 1 when implemented)
1001  }
1002 
1003  // the Receiver Address (RA) and the Transmitter Address (TA) are the MLD addresses only for
1004  // non-broadcast data frames exchanged between two MLDs
1005  auto linkIds = GetSetupLinkIds();
1006  NS_ASSERT(!linkIds.empty());
1007  uint8_t linkId = *linkIds.begin();
1008  if (const auto apMldAddr = GetWifiRemoteStationManager(linkId)->GetMldAddress(GetBssid(linkId)))
1009  {
1010  hdr.SetAddr1(*apMldAddr);
1011  hdr.SetAddr2(GetAddress());
1012  }
1013  else
1014  {
1015  hdr.SetAddr1(GetBssid(linkId));
1017  }
1018 
1019  hdr.SetAddr3(to);
1020  hdr.SetDsNotFrom();
1021  hdr.SetDsTo();
1022 
1023  if (GetQosSupported())
1024  {
1025  // Sanity check that the TID is valid
1026  NS_ASSERT(tid < 8);
1027  GetQosTxop(tid)->Queue(packet, hdr);
1028  }
1029  else
1030  {
1031  GetTxop()->Queue(packet, hdr);
1032  }
1033 }
1034 
1035 void
1037 {
1038  NS_LOG_FUNCTION(this << linkId << reason);
1039 
1040  auto bssid = GetBssid(linkId);
1041  auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1042 
1043  BlockUnicastTxOnLinks(reason, apAddress, {linkId});
1044  // the only type of broadcast frames that a non-AP STA can send are management frames
1045  for (const auto& [acIndex, ac] : wifiAcList)
1046  {
1047  GetMacQueueScheduler()->BlockQueues(reason,
1048  acIndex,
1049  {WIFI_MGT_QUEUE},
1051  GetFrameExchangeManager(linkId)->GetAddress(),
1052  {},
1053  {linkId});
1054  }
1055 }
1056 
1057 void
1059 {
1060  NS_LOG_FUNCTION(this << linkId << reason);
1061 
1062  auto bssid = GetBssid(linkId);
1063  auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
1064 
1065  UnblockUnicastTxOnLinks(reason, apAddress, {linkId});
1066  // the only type of broadcast frames that a non-AP STA can send are management frames
1067  for (const auto& [acIndex, ac] : wifiAcList)
1068  {
1069  GetMacQueueScheduler()->UnblockQueues(reason,
1070  acIndex,
1071  {WIFI_MGT_QUEUE},
1073  GetFrameExchangeManager(linkId)->GetAddress(),
1074  {},
1075  {linkId});
1076  }
1077 }
1078 
1079 void
1081 {
1082  NS_LOG_FUNCTION(this << *mpdu << +linkId);
1083  // consider the MAC header of the original MPDU (makes a difference for data frames only)
1084  const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
1085  Ptr<const Packet> packet = mpdu->GetPacket();
1086  NS_ASSERT(!hdr->IsCtl());
1088  : GetFrameExchangeManager(linkId)->GetAddress();
1089  if (hdr->GetAddr3() == myAddr)
1090  {
1091  NS_LOG_LOGIC("packet sent by us.");
1092  return;
1093  }
1094  if (hdr->GetAddr1() != myAddr && !hdr->GetAddr1().IsGroup())
1095  {
1096  NS_LOG_LOGIC("packet is not for us");
1097  NotifyRxDrop(packet);
1098  return;
1099  }
1100  if (hdr->IsData())
1101  {
1102  if (!IsAssociated())
1103  {
1104  NS_LOG_LOGIC("Received data frame while not associated: ignore");
1105  NotifyRxDrop(packet);
1106  return;
1107  }
1108  if (!(hdr->IsFromDs() && !hdr->IsToDs()))
1109  {
1110  NS_LOG_LOGIC("Received data frame not from the DS: ignore");
1111  NotifyRxDrop(packet);
1112  return;
1113  }
1114  std::set<Mac48Address> apAddresses; // link addresses of AP
1115  for (auto id : GetSetupLinkIds())
1116  {
1117  apAddresses.insert(GetBssid(id));
1118  }
1119  if (apAddresses.count(mpdu->GetHeader().GetAddr2()) == 0)
1120  {
1121  NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
1122  NotifyRxDrop(packet);
1123  return;
1124  }
1125  if (!hdr->HasData())
1126  {
1127  NS_LOG_LOGIC("Received (QoS) Null Data frame: ignore");
1128  NotifyRxDrop(packet);
1129  return;
1130  }
1131  if (hdr->IsQosData())
1132  {
1133  if (hdr->IsQosAmsdu())
1134  {
1135  NS_ASSERT(apAddresses.count(mpdu->GetHeader().GetAddr3()) != 0);
1137  packet = nullptr;
1138  }
1139  else
1140  {
1141  ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1142  }
1143  }
1144  else
1145  {
1146  ForwardUp(packet, hdr->GetAddr3(), hdr->GetAddr1());
1147  }
1148  return;
1149  }
1150 
1151  switch (hdr->GetType())
1152  {
1156  // This is a frame aimed at an AP, so we can safely ignore it.
1157  NotifyRxDrop(packet);
1158  break;
1159 
1160  case WIFI_MAC_MGT_BEACON:
1161  ReceiveBeacon(mpdu, linkId);
1162  break;
1163 
1165  ReceiveProbeResp(mpdu, linkId);
1166  break;
1167 
1170  ReceiveAssocResp(mpdu, linkId);
1171  break;
1172 
1173  case WIFI_MAC_MGT_ACTION:
1174  if (auto [category, action] = WifiActionHeader::Peek(packet);
1175  category == WifiActionHeader::PROTECTED_EHT &&
1176  action.protectedEhtAction ==
1178  {
1179  // this is handled by the EMLSR Manager
1180  break;
1181  }
1182 
1183  default:
1184  // Invoke the receive handler of our parent class to deal with any
1185  // other frames. Specifically, this will handle Block Ack-related
1186  // Management Action frames.
1187  WifiMac::Receive(mpdu, linkId);
1188  }
1189 
1190  if (m_emlsrManager)
1191  {
1192  m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
1193  }
1194 }
1195 
1196 void
1198 {
1199  NS_LOG_FUNCTION(this << *mpdu << +linkId);
1200  const WifiMacHeader& hdr = mpdu->GetHeader();
1201  NS_ASSERT(hdr.IsBeacon());
1202 
1203  NS_LOG_DEBUG("Beacon received");
1204  MgtBeaconHeader beacon;
1205  mpdu->GetPacket()->PeekHeader(beacon);
1206  const auto& capabilities = beacon.Capabilities();
1207  NS_ASSERT(capabilities.IsEss());
1208  bool goodBeacon;
1209  if (IsWaitAssocResp() || IsAssociated())
1210  {
1211  // we have to process this Beacon only if sent by the AP we are associated
1212  // with or from which we are waiting an Association Response frame
1213  auto bssid = GetLink(linkId).bssid;
1214  goodBeacon = bssid.has_value() && (hdr.GetAddr3() == *bssid);
1215  }
1216  else
1217  {
1218  // we retain this Beacon as candidate AP if the supported rates fit the
1219  // configured BSS membership selector
1220  goodBeacon = CheckSupportedRates(beacon, linkId);
1221  }
1222 
1223  SnrTag snrTag;
1224  bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1225  NS_ASSERT(found);
1226  ApInfo apInfo = {.m_bssid = hdr.GetAddr3(),
1227  .m_apAddr = hdr.GetAddr2(),
1228  .m_snr = snrTag.Get(),
1229  .m_frame = std::move(beacon),
1230  .m_channel = {GetCurrentChannel(linkId)},
1231  .m_linkId = linkId};
1232 
1233  if (!m_beaconInfo.IsEmpty())
1234  {
1235  m_beaconInfo(apInfo);
1236  }
1237 
1238  if (!goodBeacon)
1239  {
1240  NS_LOG_LOGIC("Beacon is not for us");
1241  return;
1242  }
1243  if (m_state == ASSOCIATED)
1244  {
1246  Time delay = MicroSeconds(std::get<MgtBeaconHeader>(apInfo.m_frame).GetBeaconIntervalUs() *
1248  RestartBeaconWatchdog(delay);
1249  UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1250  }
1251  else
1252  {
1253  NS_LOG_DEBUG("Beacon received from " << hdr.GetAddr2());
1254  m_assocManager->NotifyApInfo(std::move(apInfo));
1255  }
1256 }
1257 
1258 void
1260 {
1261  NS_LOG_FUNCTION(this << *mpdu << +linkId);
1262  const WifiMacHeader& hdr = mpdu->GetHeader();
1263  NS_ASSERT(hdr.IsProbeResp());
1264 
1265  NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2());
1266  MgtProbeResponseHeader probeResp;
1267  mpdu->GetPacket()->PeekHeader(probeResp);
1268  if (!CheckSupportedRates(probeResp, linkId))
1269  {
1270  return;
1271  }
1272  SnrTag snrTag;
1273  bool found = mpdu->GetPacket()->PeekPacketTag(snrTag);
1274  NS_ASSERT(found);
1275  m_assocManager->NotifyApInfo(ApInfo{.m_bssid = hdr.GetAddr3(),
1276  .m_apAddr = hdr.GetAddr2(),
1277  .m_snr = snrTag.Get(),
1278  .m_frame = std::move(probeResp),
1279  .m_channel = {GetCurrentChannel(linkId)},
1280  .m_linkId = linkId});
1281 }
1282 
1283 void
1285 {
1286  NS_LOG_FUNCTION(this << *mpdu << +linkId);
1287  const WifiMacHeader& hdr = mpdu->GetHeader();
1288  NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp());
1289 
1290  if (m_state != WAIT_ASSOC_RESP)
1291  {
1292  return;
1293  }
1294 
1295  std::optional<Mac48Address> apMldAddress;
1296  MgtAssocResponseHeader assocResp;
1297  mpdu->GetPacket()->PeekHeader(assocResp);
1299  {
1301  }
1302  if (assocResp.GetStatusCode().IsSuccess())
1303  {
1304  m_aid = assocResp.GetAssociationId();
1305  NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed"));
1306  UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId);
1307  NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3());
1308  SetBssid(hdr.GetAddr3(), linkId);
1310  if ((GetNLinks() > 1) && assocResp.Get<MultiLinkElement>().has_value())
1311  {
1312  // this is an ML setup, trace the setup link
1313  m_setupCompleted(linkId, hdr.GetAddr3());
1314  apMldAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr3());
1315  NS_ASSERT(apMldAddress);
1316 
1317  if (const auto& mldCapabilities =
1318  GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
1319  mldCapabilities && mldCapabilities->get().tidToLinkMappingSupport > 0)
1320  {
1321  // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
1322  // TID-to-Link Mapping element(s) in the Association Request.
1323  if (assocResp.Get<TidToLinkMapping>().empty())
1324  {
1325  // The AP MLD did not include a TID-to-Link Mapping element in the Association
1326  // Response, hence it accepted the mapping, which we can now store.
1327  UpdateTidToLinkMapping(*apMldAddress,
1330  UpdateTidToLinkMapping(*apMldAddress,
1333 
1334  // Apply the negotiated TID-to-Link Mapping (if any) for UL direction
1336  }
1337  }
1338  }
1339  else
1340  {
1341  m_assocLogger(hdr.GetAddr3());
1342  }
1343  if (!m_linkUp.IsNull())
1344  {
1345  m_linkUp();
1346  }
1347  }
1348  else
1349  {
1350  // If the link on which the (Re)Association Request frame was received cannot be
1351  // accepted by the AP MLD, the AP MLD shall treat the multi-link (re)setup as a
1352  // failure and shall not accept any requested links. If the link on which the
1353  // (Re)Association Request frame was received is accepted by the AP MLD, the
1354  // multi-link (re)setup is successful. (Sec. 35.3.5.1 of 802.11be D3.1)
1355  NS_LOG_DEBUG("association refused");
1356  SetState(REFUSED);
1357  StartScanning();
1358  return;
1359  }
1360 
1361  // if this is an MLD, check if we can setup (other) links
1362  if (GetNLinks() > 1)
1363  {
1364  // create a list of all local Link IDs. IDs are removed as we find a corresponding
1365  // Per-STA Profile Subelements indicating successful association. Links with
1366  // remaining IDs are not setup
1367  std::list<uint8_t> setupLinks;
1368  for (const auto& [id, link] : GetLinks())
1369  {
1370  setupLinks.push_back(id);
1371  }
1372  if (assocResp.GetStatusCode().IsSuccess())
1373  {
1374  setupLinks.remove(linkId);
1375  }
1376 
1377  // if a Multi-Link Element is present, check its content
1378  if (const auto& mle = assocResp.Get<MultiLinkElement>())
1379  {
1380  NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
1381  "The link on which the Association Response was received "
1382  "is not a link we requested to setup");
1383  NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
1384  "The link ID of the AP that transmitted the Association "
1385  "Response does not match the stored link ID");
1387  mle->GetMldMacAddress(),
1388  "The AP MLD MAC address in the received Multi-Link Element does not "
1389  "match the address stored in the station manager for link "
1390  << +linkId);
1391  // process the Per-STA Profile Subelements in the Multi-Link Element
1392  for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
1393  {
1394  auto& perStaProfile = mle->GetPerStaProfile(elem);
1395  uint8_t apLinkId = perStaProfile.GetLinkId();
1396  auto it = GetLinks().find(apLinkId);
1397  uint8_t staLinkid = 0;
1398  std::optional<Mac48Address> bssid;
1399  NS_ABORT_MSG_IF(it == GetLinks().cend() ||
1400  !(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
1401  "Setup for AP link ID " << apLinkId << " was not requested");
1402  NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
1403  "The BSSID in the Per-STA Profile for link ID "
1404  << +staLinkid << " does not match the stored BSSID");
1407  perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
1408  "The AP MLD MAC address in the received Multi-Link Element does not "
1409  "match the address stored in the station manager for link "
1410  << +staLinkid);
1411  // process the Association Response contained in this Per-STA Profile
1412  MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
1413  if (assoc.GetStatusCode().IsSuccess())
1414  {
1415  NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
1416  "AID should be the same for all the links");
1417  m_aid = assoc.GetAssociationId();
1418  NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
1419  UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
1420  SetBssid(*bssid, staLinkid);
1421  m_setupCompleted(staLinkid, *bssid);
1423  apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
1424  if (!m_linkUp.IsNull())
1425  {
1426  m_linkUp();
1427  }
1428  }
1429  // remove the ID of the link we setup
1430  setupLinks.remove(staLinkid);
1431  }
1432  }
1433  // remaining links in setupLinks are not setup and hence must be disabled
1434  for (const auto& id : setupLinks)
1435  {
1436  GetLink(id).bssid = std::nullopt;
1437  GetLink(id).phy->SetOffMode();
1438  }
1439  if (apMldAddress)
1440  {
1441  // this is an ML setup, trace the MLD address of the AP (only once)
1442  m_assocLogger(*apMldAddress);
1443  }
1444  }
1445 
1446  // the station that associated with the AP may have dissociated and then associated again.
1447  // In this case, the station may store packets from the previous period in which it was
1448  // associated. Have the station restart access if it has packets queued.
1449  for (const auto& [id, link] : GetLinks())
1450  {
1451  if (GetStaLink(link).bssid)
1452  {
1453  if (const auto txop = GetTxop())
1454  {
1455  txop->StartAccessAfterEvent(id,
1458  }
1459  for (const auto [acIndex, ac] : wifiAcList)
1460  {
1461  if (const auto edca = GetQosTxop(acIndex))
1462  {
1463  edca->StartAccessAfterEvent(id,
1466  }
1467  }
1468  }
1469  }
1470 
1471  SetPmModeAfterAssociation(linkId);
1472 }
1473 
1474 void
1476 {
1477  NS_LOG_FUNCTION(this << linkId);
1478 
1479  // STAs operating on setup links may need to transition to a new PM mode after the
1480  // acknowledgement of the Association Response. For this purpose, we connect a callback to
1481  // the PHY TX begin trace to catch the Ack transmitted after the Association Response.
1483  [=, this](WifiConstPsduMap psduMap, WifiTxVector txVector, double /* txPowerW */) {
1484  NS_ASSERT_MSG(psduMap.size() == 1 && psduMap.begin()->second->GetNMpdus() == 1 &&
1485  psduMap.begin()->second->GetHeader(0).IsAck(),
1486  "Expected a Normal Ack after Association Response frame");
1487 
1488  auto ackDuration =
1489  WifiPhy::CalculateTxDuration(psduMap, txVector, GetLink(linkId).phy->GetPhyBand());
1490 
1491  for (const auto& [id, lnk] : GetLinks())
1492  {
1493  auto& link = GetStaLink(lnk);
1494 
1495  if (!link.bssid)
1496  {
1497  // link has not been setup
1498  continue;
1499  }
1500 
1501  if (id == linkId)
1502  {
1511  // if the user requested this link to be in powersave mode, we have to
1512  // switch PM mode
1513  if (link.pmMode == WIFI_PM_POWERSAVE)
1514  {
1515  Simulator::Schedule(ackDuration,
1517  this,
1518  std::pair<bool, uint8_t>{true, id});
1519  }
1520  link.pmMode = WIFI_PM_ACTIVE;
1521  }
1522  else
1523  {
1532  // if the user requested this link to be in active mode, we have to
1533  // switch PM mode
1534  if (link.pmMode == WIFI_PM_ACTIVE)
1535  {
1536  Simulator::Schedule(ackDuration,
1538  this,
1539  std::pair<bool, uint8_t>{false, id});
1540  }
1541  link.pmMode = WIFI_PM_POWERSAVE;
1542  }
1543  }
1544  });
1545 
1546  // connect the callback to the PHY TX begin trace to catch the Ack and disconnect
1547  // after its transmission begins
1548  auto phy = GetLink(linkId).phy;
1549  phy->TraceConnectWithoutContext("PhyTxPsduBegin", cb);
1550  Simulator::Schedule(phy->GetSifs() + NanoSeconds(1),
1551  [=]() { phy->TraceDisconnectWithoutContext("PhyTxPsduBegin", cb); });
1552 }
1553 
1554 bool
1555 StaWifiMac::CheckSupportedRates(std::variant<MgtBeaconHeader, MgtProbeResponseHeader> frame,
1556  uint8_t linkId)
1557 {
1558  NS_LOG_FUNCTION(this << +linkId);
1559 
1560  // lambda to invoke on the current frame variant
1561  auto check = [&](auto&& mgtFrame) -> bool {
1562  // check supported rates
1563  NS_ASSERT(mgtFrame.template Get<SupportedRates>());
1564  const auto rates = AllSupportedRates{*mgtFrame.template Get<SupportedRates>(),
1565  mgtFrame.template Get<ExtendedSupportedRatesIE>()};
1566  for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1567  {
1568  if (!rates.IsBssMembershipSelectorRate(selector))
1569  {
1570  NS_LOG_DEBUG("Supported rates do not fit with the BSS membership selector");
1571  return false;
1572  }
1573  }
1574 
1575  return true;
1576  };
1577 
1578  return std::visit(check, frame);
1579 }
1580 
1581 void
1583  const Mac48Address& apAddr,
1584  const Mac48Address& bssid,
1585  uint8_t linkId)
1586 {
1587  NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId);
1588 
1589  // ERP Information is not present in Association Response frames
1590  const std::optional<ErpInformation>* erpInformation = nullptr;
1591 
1592  if (const auto* beacon = std::get_if<MgtBeaconHeader>(&frame))
1593  {
1594  erpInformation = &beacon->Get<ErpInformation>();
1595  }
1596  else if (const auto* probe = std::get_if<MgtProbeResponseHeader>(&frame))
1597  {
1598  erpInformation = &probe->Get<ErpInformation>();
1599  }
1600 
1601  // lambda processing Information Elements included in all frame types
1602  auto commonOps = [&](auto&& frame) {
1603  const auto& capabilities = frame.Capabilities();
1604  NS_ASSERT(frame.template Get<SupportedRates>());
1605  const auto rates = AllSupportedRates{*frame.template Get<SupportedRates>(),
1606  frame.template Get<ExtendedSupportedRatesIE>()};
1607  for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1608  {
1609  if (rates.IsSupportedRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1610  {
1611  GetWifiRemoteStationManager(linkId)->AddSupportedMode(apAddr, mode);
1612  if (rates.IsBasicRate(mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth())))
1613  {
1614  GetWifiRemoteStationManager(linkId)->AddBasicMode(mode);
1615  }
1616  }
1617  }
1618 
1619  bool isShortPreambleEnabled = capabilities.IsShortPreamble();
1620  if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId))
1621  {
1622  isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode();
1623  if ((*erpInformation)->GetUseProtection() != 0)
1624  {
1625  GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(true);
1626  }
1627  else
1628  {
1629  GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(false);
1630  }
1631  if (capabilities.IsShortSlotTime() == true)
1632  {
1633  // enable short slot time
1634  GetWifiPhy(linkId)->SetSlot(MicroSeconds(9));
1635  }
1636  else
1637  {
1638  // disable short slot time
1639  GetWifiPhy(linkId)->SetSlot(MicroSeconds(20));
1640  }
1641  }
1642  GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled);
1643  GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled(
1644  capabilities.IsShortSlotTime());
1645 
1646  if (!GetQosSupported())
1647  {
1648  return;
1649  }
1650  /* QoS station */
1651  bool qosSupported = false;
1652  const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
1653  if (edcaParameters.has_value())
1654  {
1655  qosSupported = true;
1656  // The value of the TXOP Limit field is specified as an unsigned integer, with the least
1657  // significant octet transmitted first, in units of 32 μs.
1659  edcaParameters->GetBeCWmin(),
1660  edcaParameters->GetBeCWmax(),
1661  edcaParameters->GetBeAifsn(),
1662  32 * MicroSeconds(edcaParameters->GetBeTxopLimit())},
1663  linkId);
1665  edcaParameters->GetBkCWmin(),
1666  edcaParameters->GetBkCWmax(),
1667  edcaParameters->GetBkAifsn(),
1668  32 * MicroSeconds(edcaParameters->GetBkTxopLimit())},
1669  linkId);
1671  edcaParameters->GetViCWmin(),
1672  edcaParameters->GetViCWmax(),
1673  edcaParameters->GetViAifsn(),
1674  32 * MicroSeconds(edcaParameters->GetViTxopLimit())},
1675  linkId);
1677  edcaParameters->GetVoCWmin(),
1678  edcaParameters->GetVoCWmax(),
1679  edcaParameters->GetVoAifsn(),
1680  32 * MicroSeconds(edcaParameters->GetVoTxopLimit())},
1681  linkId);
1682  }
1683  GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
1684 
1685  if (!GetHtSupported())
1686  {
1687  return;
1688  }
1689  /* HT station */
1690  if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
1691  htCapabilities.has_value())
1692  {
1693  if (!htCapabilities->IsSupportedMcs(0))
1694  {
1695  GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
1696  }
1697  else
1698  {
1699  GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
1700  *htCapabilities);
1701  }
1702  }
1703  // TODO: process ExtendedCapabilities
1704  // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
1705 
1706  // we do not return if VHT is not supported because HE STAs operating in
1707  // the 2.4 GHz band do not support VHT
1708  if (GetVhtSupported(linkId))
1709  {
1710  const auto& vhtCapabilities = frame.template Get<VhtCapabilities>();
1711  // we will always fill in RxHighestSupportedLgiDataRate field at TX, so this can be used
1712  // to check whether it supports VHT
1713  if (vhtCapabilities.has_value() &&
1714  vhtCapabilities->GetRxHighestSupportedLgiDataRate() > 0)
1715  {
1716  GetWifiRemoteStationManager(linkId)->AddStationVhtCapabilities(apAddr,
1717  *vhtCapabilities);
1718  // const auto& vhtOperation = frame.GetVhtOperation ();
1719  for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_VHT))
1720  {
1721  if (vhtCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1722  {
1723  GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1724  }
1725  }
1726  }
1727  }
1728 
1729  if (!GetHeSupported())
1730  {
1731  return;
1732  }
1733  /* HE station */
1734  const auto& heCapabilities = frame.template Get<HeCapabilities>();
1735  if (heCapabilities.has_value() && heCapabilities->GetSupportedMcsAndNss() != 0)
1736  {
1737  GetWifiRemoteStationManager(linkId)->AddStationHeCapabilities(apAddr, *heCapabilities);
1738  for (const auto& mcs : GetWifiPhy(linkId)->GetMcsList(WIFI_MOD_CLASS_HE))
1739  {
1740  if (heCapabilities->IsSupportedRxMcs(mcs.GetMcsValue()))
1741  {
1742  GetWifiRemoteStationManager(linkId)->AddSupportedMcs(apAddr, mcs);
1743  }
1744  }
1745  if (const auto& heOperation = frame.template Get<HeOperation>();
1746  heOperation.has_value())
1747  {
1748  GetHeConfiguration()->SetAttribute("BssColor",
1749  UintegerValue(heOperation->GetBssColor()));
1750  }
1751  }
1752 
1753  const auto& muEdcaParameters = frame.template Get<MuEdcaParameterSet>();
1754  if (muEdcaParameters.has_value())
1755  {
1757  muEdcaParameters->GetMuCwMin(AC_BE),
1758  muEdcaParameters->GetMuCwMax(AC_BE),
1759  muEdcaParameters->GetMuAifsn(AC_BE),
1760  muEdcaParameters->GetMuEdcaTimer(AC_BE)},
1761  linkId);
1763  muEdcaParameters->GetMuCwMin(AC_BK),
1764  muEdcaParameters->GetMuCwMax(AC_BK),
1765  muEdcaParameters->GetMuAifsn(AC_BK),
1766  muEdcaParameters->GetMuEdcaTimer(AC_BK)},
1767  linkId);
1769  muEdcaParameters->GetMuCwMin(AC_VI),
1770  muEdcaParameters->GetMuCwMax(AC_VI),
1771  muEdcaParameters->GetMuAifsn(AC_VI),
1772  muEdcaParameters->GetMuEdcaTimer(AC_VI)},
1773  linkId);
1775  muEdcaParameters->GetMuCwMin(AC_VO),
1776  muEdcaParameters->GetMuCwMax(AC_VO),
1777  muEdcaParameters->GetMuAifsn(AC_VO),
1778  muEdcaParameters->GetMuEdcaTimer(AC_VO)},
1779  linkId);
1780  }
1781 
1782  if (!GetEhtSupported())
1783  {
1784  return;
1785  }
1786  /* EHT station */
1787  const auto& ehtCapabilities = frame.template Get<EhtCapabilities>();
1788  // TODO: once we support non constant rate managers, we should add checks here whether EHT
1789  // is supported by the peer
1790  GetWifiRemoteStationManager(linkId)->AddStationEhtCapabilities(apAddr, *ehtCapabilities);
1791 
1792  if (const auto& mle = frame.template Get<MultiLinkElement>(); mle && m_emlsrManager)
1793  {
1794  if (mle->HasEmlCapabilities())
1795  {
1796  m_emlsrManager->SetTransitionTimeout(mle->GetTransitionTimeout());
1797  }
1798  if (const auto& common = mle->GetCommonInfoBasic(); common.m_mediumSyncDelayInfo)
1799  {
1800  m_emlsrManager->SetMediumSyncDuration(common.GetMediumSyncDelayTimer());
1801  m_emlsrManager->SetMediumSyncOfdmEdThreshold(common.GetMediumSyncOfdmEdThreshold());
1802  m_emlsrManager->SetMediumSyncMaxNTxops(common.GetMediumSyncMaxNTxops());
1803  }
1804  }
1805  };
1806 
1807  // process Information Elements included in the current frame variant
1808  std::visit(commonOps, frame);
1809 }
1810 
1811 void
1812 StaWifiMac::SetPowerSaveMode(const std::pair<bool, uint8_t>& enableLinkIdPair)
1813 {
1814  const auto [enable, linkId] = enableLinkIdPair;
1815  NS_LOG_FUNCTION(this << enable << linkId);
1816 
1817  auto& link = GetLink(linkId);
1818 
1819  if (!IsAssociated())
1820  {
1821  NS_LOG_DEBUG("Not associated yet, record the PM mode to switch to upon association");
1822  link.pmMode = enable ? WIFI_PM_POWERSAVE : WIFI_PM_ACTIVE;
1823  return;
1824  }
1825 
1826  if (!link.bssid)
1827  {
1828  NS_LOG_DEBUG("Link " << +linkId << " has not been setup, ignore request");
1829  return;
1830  }
1831 
1832  if ((enable && link.pmMode == WIFI_PM_POWERSAVE) || (!enable && link.pmMode == WIFI_PM_ACTIVE))
1833  {
1834  NS_LOG_DEBUG("No PM mode change needed");
1835  return;
1836  }
1837 
1839 
1840  // reschedule a call to this function to make sure that the PM mode switch
1841  // is eventually completed
1844  this,
1845  enableLinkIdPair);
1846 
1847  if (HasFramesToTransmit(linkId))
1848  {
1849  NS_LOG_DEBUG("Next transmitted frame will be sent with PM=" << enable);
1850  return;
1851  }
1852 
1853  // No queued frames. Enqueue a Data Null frame to inform the AP of the PM mode change
1855 
1856  hdr.SetAddr1(GetBssid(linkId));
1858  hdr.SetAddr3(GetBssid(linkId));
1859  hdr.SetDsNotFrom();
1860  hdr.SetDsTo();
1861  enable ? hdr.SetPowerManagement() : hdr.SetNoPowerManagement();
1862  if (GetQosSupported())
1863  {
1864  GetQosTxop(AC_BE)->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1865  }
1866  else
1867  {
1868  m_txop->Queue(Create<WifiMpdu>(Create<Packet>(), hdr));
1869  }
1870 }
1871 
1873 StaWifiMac::GetPmMode(uint8_t linkId) const
1874 {
1875  return GetLink(linkId).pmMode;
1876 }
1877 
1878 void
1880 {
1881  NS_LOG_FUNCTION(this << *mpdu);
1882 
1883  auto linkId = GetLinkIdByAddress(mpdu->GetHeader().GetAddr2());
1884 
1885  if (!linkId)
1886  {
1887  // the given MPDU may be the original copy containing MLD addresses and not carrying
1888  // a valid PM bit (which is set on the aliases).
1889  auto linkIds = mpdu->GetInFlightLinkIds();
1890  NS_ASSERT_MSG(!linkIds.empty(),
1891  "The TA of the acked MPDU (" << *mpdu
1892  << ") is not a link "
1893  "address and the MPDU is not inflight");
1894  // in case the ack'ed MPDU is inflight on multiple links, we cannot really know if
1895  // it was received by the AP on all links or only on some links. Hence, we only
1896  // consider the first link ID in the set, given that in the most common case of MPDUs
1897  // that cannot be sent concurrently on multiple links, there will be only one link ID
1898  linkId = *linkIds.begin();
1899  mpdu = GetTxopQueue(mpdu->GetQueueAc())->GetAlias(mpdu, *linkId);
1900  }
1901 
1902  auto& link = GetLink(*linkId);
1903  const WifiMacHeader& hdr = mpdu->GetHeader();
1904 
1905  // we received an acknowledgment while switching PM mode; the PM mode change is effective now
1906  if (hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_PS)
1907  {
1908  link.pmMode = WIFI_PM_POWERSAVE;
1909  }
1910  else if (!hdr.IsPowerManagement() && link.pmMode == WIFI_PM_SWITCHING_TO_ACTIVE)
1911  {
1912  link.pmMode = WIFI_PM_ACTIVE;
1913  }
1914 }
1915 
1917 StaWifiMac::GetSupportedRates(uint8_t linkId) const
1918 {
1919  AllSupportedRates rates;
1920  for (const auto& mode : GetWifiPhy(linkId)->GetModeList())
1921  {
1922  uint64_t modeDataRate = mode.GetDataRate(GetWifiPhy(linkId)->GetChannelWidth());
1923  NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
1924  rates.AddSupportedRate(modeDataRate);
1925  }
1926  if (GetHtSupported())
1927  {
1928  for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
1929  {
1930  rates.AddBssMembershipSelectorRate(selector);
1931  }
1932  }
1933  return rates;
1934 }
1935 
1937 StaWifiMac::GetCapabilities(uint8_t linkId) const
1938 {
1939  CapabilityInformation capabilities;
1940  capabilities.SetShortPreamble(GetWifiPhy(linkId)->GetShortPhyPreambleSupported() ||
1941  GetErpSupported(linkId));
1942  capabilities.SetShortSlotTime(GetShortSlotTimeSupported() && GetErpSupported(linkId));
1943  return capabilities;
1944 }
1945 
1946 void
1948 {
1949  m_state = value;
1950 }
1951 
1952 void
1954 {
1955  Ptr<QosTxop> edca = GetQosTxop(params.ac);
1956  edca->SetMinCw(params.cwMin, linkId);
1957  edca->SetMaxCw(params.cwMax, linkId);
1958  edca->SetAifsn(params.aifsn, linkId);
1959  edca->SetTxopLimit(params.txopLimit, linkId);
1960 }
1961 
1962 void
1964 {
1965  Ptr<QosTxop> edca = GetQosTxop(params.ac);
1966  edca->SetMuCwMin(params.cwMin, linkId);
1967  edca->SetMuCwMax(params.cwMax, linkId);
1968  edca->SetMuAifsn(params.aifsn, linkId);
1969  edca->SetMuEdcaTimer(params.muEdcaTimer, linkId);
1970 }
1971 
1972 void
1974 {
1975  NS_LOG_FUNCTION(this);
1976  if (IsAssociated())
1977  {
1978  NS_LOG_DEBUG("PHY capabilities changed: send reassociation request");
1980  SendAssociationRequest(true);
1981  }
1982 }
1983 
2030 void
2032 {
2033  NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
2034 
2035  // If the PHY is switching channel to operate on another link, then it is no longer operating
2036  // on the current link. If any link (other than the current link) points to the PHY that is
2037  // switching channel, reset the phy pointer of the link
2038  for (auto& [id, link] : GetLinks())
2039  {
2040  if (link->phy == phy && id != linkId)
2041  {
2042  link->phy = nullptr;
2043  }
2044  }
2045 
2046  // lambda to connect the PHY to the new link
2047  auto connectPhy = [=, this]() mutable {
2048  auto& newLink = GetLink(linkId);
2049  // The MAC stack associated with the new link uses the given PHY
2050  newLink.phy = phy;
2051  // Setup a PHY listener for the given PHY on the CAM associated with the new link
2052  newLink.channelAccessManager->SetupPhyListener(phy);
2054  if (m_emlsrManager->GetCamStateReset())
2055  {
2056  newLink.channelAccessManager->ResetState();
2057  }
2058  // Disconnect the FEM on the new link from the current PHY
2059  newLink.feManager->ResetPhy();
2060  // Connect the FEM on the new link to the given PHY
2061  newLink.feManager->SetWifiPhy(phy);
2062  // Connect the station manager on the new link to the given PHY
2063  newLink.stationManager->SetupPhy(phy);
2064  };
2065 
2066  // if there is no PHY operating on the new link, connect the PHY to the new link now.
2067  // Otherwise, wait until the channel switch is completed, so that the PHY operating on the new
2068  // link can possibly continue receiving frames in the meantime.
2069  if (!GetLink(linkId).phy)
2070  {
2071  connectPhy();
2072  }
2073  else
2074  {
2075  Simulator::Schedule(delay, connectPhy);
2076  }
2077 }
2078 
2079 void
2081 {
2082  NS_LOG_FUNCTION(this << +linkId);
2083 
2085 
2086  if (IsInitialized() && IsAssociated())
2087  {
2088  Disassociated();
2089  }
2090 
2091  // notify association manager
2092  m_assocManager->NotifyChannelSwitched(linkId);
2093 }
2094 
2095 std::ostream&
2096 operator<<(std::ostream& os, const StaWifiMac::ApInfo& apInfo)
2097 {
2098  os << "BSSID=" << apInfo.m_bssid << ", AP addr=" << apInfo.m_apAddr << ", SNR=" << apInfo.m_snr
2099  << ", Channel={" << apInfo.m_channel.number << "," << apInfo.m_channel.band
2100  << "}, Link ID=" << +apInfo.m_linkId << ", Frame=[";
2101  std::visit([&os](auto&& frame) { frame.Print(os); }, apInfo.m_frame);
2102  os << "]";
2103  return os;
2104 }
2105 
2106 } // namespace ns3
#define max(a, b)
Definition: 80211b.c:42
A container for one type of attribute.
Base class for Callback class.
Definition: callback.h:360
Callback template class.
Definition: callback.h:438
bool IsNull() const
Check for null implementation.
Definition: callback.h:569
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.
The IEEE 802.11be EHT Capabilities.
Hold variables of type enum.
Definition: enum.h:62
T Get() const
Definition: enum.h:102
The ErpInformation Information Element.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:69
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
The Extended Capabilities Information Element.
The Extended Supported Rates Information Element.
The IEEE 802.11ax HE Capabilities.
The HT Capabilities Information Element.
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address GetBroadcast()
Implement the header for management frames of type association request.
Definition: mgt-headers.h:157
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:334
StatusCode GetStatusCode()
Return the status code.
Definition: mgt-headers.cc:456
uint16_t GetAssociationId() const
Return the association ID.
Definition: mgt-headers.cc:486
Implement the header for management frames of type beacon.
Definition: mgt-headers.h:512
Implement the header for management frames of type probe request.
Definition: mgt-headers.h:432
Implement the header for management frames of type probe response.
Definition: mgt-headers.h:451
CapabilityInformation & Capabilities()
Definition: mgt-headers.cc:93
Implement the header for management frames of type reassociation request.
Definition: mgt-headers.h:241
void SetCurrentApAddress(Mac48Address currentApAddr)
Set the address of the current access point.
Definition: mgt-headers.cc:331
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:315
bool IsInitialized() const
Check if the object has been initialized.
Definition: object.cc:212
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
Hold objects of type std::pair<A, B>.
Definition: pair.h:56
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
void SetMuCwMin(uint16_t cwMin, uint8_t linkId)
Set the minimum contention window size to use while the MU EDCA Timer is running for the given link.
Definition: qos-txop.cc:198
void SetMuCwMax(uint16_t cwMax, uint8_t linkId)
Set the maximum contention window size to use while the MU EDCA Timer is running for the given link.
Definition: qos-txop.cc:205
void SetMuAifsn(uint8_t aifsn, uint8_t linkId)
Set the number of slots that make up an AIFS while the MU EDCA Timer is running for the given link.
Definition: qos-txop.cc:212
void SetMuEdcaTimer(Time timer, uint8_t linkId)
Set the MU EDCA Timer for the given link.
Definition: qos-txop.cc:219
virtual double GetValue()=0
Get the next random value drawn from the distribution.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:217
double Get() const
Return the SNR value.
Definition: snr-tag.cc:90
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
The Wifi MAC high model for a non-AP STA in a BSS.
Definition: sta-wifi-mac.h:142
std::set< uint8_t > GetSetupLinkIds() const
Get the IDs of the setup links (if any).
void ScanningTimeout(const std::optional< ApInfo > &bestAp)
This method is called after wait beacon timeout or wait probe request timeout has occurred.
Time m_waitBeaconTimeout
wait beacon timeout
Definition: sta-wifi-mac.h:615
void SetPowerSaveMode(const std::pair< bool, uint8_t > &enableLinkIdPair)
Enable or disable Power Save mode on the given link.
Ptr< WifiAssocManager > m_assocManager
Association Manager.
Definition: sta-wifi-mac.h:613
bool m_activeProbing
active probing
Definition: sta-wifi-mac.h:622
void DoInitialize() override
Initialize() implementation.
void SetAssocManager(Ptr< WifiAssocManager > assocManager)
Set the Association Manager.
bool CanForwardPacketsTo(Mac48Address to) const override
Return true if packets can be forwarded to the given destination, false otherwise.
std::unique_ptr< LinkEntity > CreateLinkEntity() const override
Create a LinkEntity object.
void SetState(MacState value)
Set the current MAC state.
Time m_beaconWatchdogEnd
beacon watchdog end
Definition: sta-wifi-mac.h:621
AllSupportedRates GetSupportedRates(uint8_t linkId) const
Return an instance of SupportedRates that contains all rates that we support including HT rates.
void SetEdcaParameters(const EdcaParams &params, uint8_t linkId)
Set the EDCA parameters for the given link.
void UnblockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
Unblock transmissions on the given link for the given reason.
TracedCallback< Mac48Address > m_deAssocLogger
disassociation logger
Definition: sta-wifi-mac.h:634
MacState
The current MAC state of the STA.
Definition: sta-wifi-mac.h:382
void NotifyChannelSwitching(uint8_t linkId) override
Notify that channel on the given link has been switched.
bool GetActiveProbing() const
Return whether active probing is enabled.
EventId m_beaconWatchdog
beacon watchdog
Definition: sta-wifi-mac.h:620
void PhyCapabilitiesChanged()
Indicate that PHY capabilities have changed.
StaLinkEntity & GetStaLink(const std::unique_ptr< WifiMac::LinkEntity > &link) const
Cast the given LinkEntity object to StaLinkEntity.
void ReceiveProbeResp(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Probe Response frame received on the given link.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
void SetPmModeAfterAssociation(uint8_t linkId)
Set the Power Management mode of the setup links after association.
WifiScanParams::Channel GetCurrentChannel(uint8_t linkId) const
Get the current primary20 channel used on the given link as a (channel number, PHY band) pair.
uint16_t GetAssociationId() const
Return the association ID.
void TryToEnsureAssociated()
Try to ensure that we are associated with an AP by taking an appropriate action depending on the curr...
void ReceiveAssocResp(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the (Re)Association Response frame received on the given link.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, uint8_t linkId, Time delay)
Notify that the given PHY switched channel to operate on another EMLSR link.
std::variant< MgtAssocRequestHeader, MgtReassocRequestHeader > GetAssociationRequest(bool isReassoc, uint8_t linkId) const
Get the (Re)Association Request frame to send on a given link.
static TypeId GetTypeId()
Get the type ID.
Definition: sta-wifi-mac.cc:58
void DoDispose() override
Destructor implementation.
void SendProbeRequest(uint8_t linkId)
Enqueue a probe request packet for transmission on the given link.
void BlockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
Block transmissions on the given link for the given reason.
StaLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
uint32_t m_maxMissedBeacons
maximum missed beacons
Definition: sta-wifi-mac.h:619
TracedCallback< uint8_t, Mac48Address > m_setupCompleted
link setup completed logger
Definition: sta-wifi-mac.h:633
TracedCallback< Mac48Address > m_assocLogger
association logger
Definition: sta-wifi-mac.h:632
void SetMuEdcaParameters(const MuEdcaParams &params, uint8_t linkId)
Set the MU EDCA parameters for the given link.
TracedCallback< uint8_t, Mac48Address > m_setupCanceled
link setup canceled logger
Definition: sta-wifi-mac.h:635
void NotifyEmlsrModeChanged(const std::set< uint8_t > &linkIds)
Notify the MAC that EMLSR mode has changed on the given set of links.
bool CheckSupportedRates(std::variant< MgtBeaconHeader, MgtProbeResponseHeader > frame, uint8_t linkId)
Determine whether the supported rates indicated in a given Beacon frame or Probe Response frame fit w...
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...
void RestartBeaconWatchdog(Time delay)
Restarts the beacon timer.
void SetEmlsrManager(Ptr< EmlsrManager > emlsrManager)
Set the EMLSR Manager.
Time m_pmModeSwitchTimeout
PM mode switch timeout.
Definition: sta-wifi-mac.h:625
void Disassociated()
Set the state to unassociated and try to associate again.
Ptr< EmlsrManager > GetEmlsrManager() const
void TxOk(Ptr< const WifiMpdu > mpdu)
Notify that the MPDU we sent was successfully received by the receiver (i.e.
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...
WifiTidLinkMapping m_ulTidLinkMappingInAssocReq
store the UL TID-to-Link Mapping included in the Association Request frame
Definition: sta-wifi-mac.h:630
WifiPowerManagementMode GetPmMode(uint8_t linkId) const
Ptr< RandomVariableStream > m_probeDelay
RandomVariable used to randomize the time of the first Probe Response on each channel.
Definition: sta-wifi-mac.h:623
TracedCallback< ApInfo > m_beaconInfo
beacon info logger
Definition: sta-wifi-mac.h:637
void MissedBeacons()
This method is called after we have not received a beacon from the AP on any link.
uint16_t m_aid
Association AID.
Definition: sta-wifi-mac.h:612
MacState m_state
MAC state.
Definition: sta-wifi-mac.h:611
bool IsEmlsrLink(uint8_t linkId) const
void Enqueue(Ptr< Packet > packet, Mac48Address to) override
void StartScanning()
Start the scanning process which trigger active or passive scanning based on the active probing flag.
void SetWifiPhys(const std::vector< Ptr< WifiPhy >> &phys) override
TracedCallback< Time > m_beaconArrival
beacon arrival logger
Definition: sta-wifi-mac.h:636
void AssocRequestTimeout()
This method is called after the association timeout occurred.
Ptr< EmlsrManager > m_emlsrManager
EMLSR Manager.
Definition: sta-wifi-mac.h:614
void UpdateApInfo(const MgtFrameType &frame, const Mac48Address &apAddr, const Mac48Address &bssid, uint8_t linkId)
Update associated AP's information from the given management frame (Beacon, Probe Response or Associa...
Time m_assocRequestTimeout
association request timeout
Definition: sta-wifi-mac.h:617
void ReceiveBeacon(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Process the Beacon frame received on the given link.
Time m_probeRequestTimeout
probe request timeout
Definition: sta-wifi-mac.h:616
void SetActiveProbing(bool enable)
Enable or disable active probing.
CapabilityInformation GetCapabilities(uint8_t linkId) const
Return the Capability information for the given link.
bool IsAssociated() const
Return whether we are associated with an AP.
~StaWifiMac() override
std::variant< MgtBeaconHeader, MgtProbeResponseHeader, MgtAssocResponseHeader > MgtFrameType
type of the management frames used to get info about APs
Definition: sta-wifi-mac.h:151
bool IsWaitAssocResp() const
Return whether we are waiting for an association response from an AP.
std::vector< TidToLinkMapping > GetTidToLinkMappingElements(uint8_t apNegSupport)
MultiLinkElement GetMultiLinkElement(bool isReassoc, uint8_t linkId) const
Return the Multi-Link Element to include in the management frames transmitted on the given link.
EventId m_assocRequestEvent
association request event
Definition: sta-wifi-mac.h:618
void SendAssociationRequest(bool isReassoc)
Forward an association or reassociation request packet to the DCF.
WifiTidLinkMapping m_dlTidLinkMappingInAssocReq
store the DL TID-to-Link Mapping included in the Association Request frame
Definition: sta-wifi-mac.h:628
bool IsSuccess() const
Return whether the status code is success.
Definition: status-code.cc:42
Hold variables of type string.
Definition: string.h:56
The Supported Rates Information Element.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
@ US
microsecond
Definition: nstime.h:118
Time Get() const
Definition: time.cc:530
void SetMaxCw(uint32_t maxCw)
Set the maximum contention window size.
Definition: txop.cc:267
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition: txop.h:417
void SetTxopLimit(Time txopLimit)
Set the TXOP limit.
Definition: txop.cc:389
void SetAifsn(uint8_t aifsn)
Set the number of slots that make up an AIFS.
Definition: txop.cc:365
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
Definition: txop.h:419
void SetMinCw(uint32_t minCw)
Set the minimum contention window size.
Definition: txop.cc:237
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:523
a unique identifier for an interface.
Definition: type-id.h:59
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:64
@ ATTR_SET
The attribute can be written.
Definition: type-id.h:65
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
@ OBSOLETE
Attribute or trace source is not used anymore; simulation fails.
Definition: type-id.h:76
Hold an unsigned integer type.
Definition: uinteger.h:45
The IEEE 802.11ac VHT Capabilities.
static std::pair< CategoryValue, ActionValue > Peek(Ptr< const Packet > pkt)
Peek an Action header from the given packet.
Implements the IEEE 802.11 MAC header.
void SetQosAckPolicy(QosAckPolicy policy)
Set the QoS Ack policy in the QoS control field.
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 IsBeacon() const
Return true if the header is a Beacon header.
bool IsAssocResp() const
Return true if the header is an Association Response header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
void SetQosTxopLimit(uint8_t txop)
Set TXOP limit in the QoS control field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
bool IsCtl() const
Return true if the Type is Control.
void SetNoOrder()
Unset order bit in the frame control field.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsProbeResp() const
Return true if the header is a Probe Response header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetQosNoAmsdu()
Set that A-MSDU is not present.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
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 SetDsTo()
Set the To 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.
bool IsPowerManagement() const
Return if the Power Management bit is set.
void SetPowerManagement()
Set the Power Management bit in the Frame Control field.
void SetNoPowerManagement()
Un-set the Power Management bit in the Frame Control field.
base class for all MAC-level wifi objects.
Definition: wifi-mac.h:96
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition: wifi-mac.cc:864
Ptr< QosTxop > GetBEQueue() const
Accessor for the AC_BE channel access function.
Definition: wifi-mac.cc:533
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition: wifi-mac.cc:582
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1632
Mac48Address GetBssid(uint8_t linkId) const
Definition: wifi-mac.cc:478
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1749
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition: wifi-mac.cc:918
Ptr< Txop > GetTxop() const
Accessor for the Txop object.
Definition: wifi-mac.cc:493
VhtCapabilities GetVhtCapabilities(uint8_t linkId) const
Return the VHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2018
Callback< void > m_linkDown
Callback when a link is down.
Definition: wifi-mac.h:898
bool GetQosSupported() const
Return whether the device supports QoS.
Definition: wifi-mac.cc:1222
Ptr< Txop > m_txop
TXOP used for transmission of frames to non-QoS peers.
Definition: wifi-mac.h:894
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:576
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:933
void SwapLinks(std::map< uint8_t, uint8_t > links)
Swap the links based on the information included in the given map.
Definition: wifi-mac.cc:995
void DoInitialize() override
Initialize() implementation.
Definition: wifi-mac.cc:349
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Definition: wifi-mac.cc:1428
Ssid GetSsid() const
Definition: wifi-mac.cc:465
bool GetErpSupported(uint8_t linkId) const
Return whether the device supports ERP on the given link.
Definition: wifi-mac.cc:1228
bool GetHtSupported() const
Return whether the device supports HT.
Definition: wifi-mac.cc:1761
Ptr< QosTxop > GetVOQueue() const
Accessor for the AC_VO channel access function.
Definition: wifi-mac.cc:521
void SetTypeOfStation(TypeOfStation type)
This method is invoked by a subclass to specify what type of station it is implementing.
Definition: wifi-mac.cc:415
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1171
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Definition: wifi-mac.cc:1387
bool GetEhtSupported() const
Return whether the device supports EHT.
Definition: wifi-mac.cc:1780
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1774
HtCapabilities GetHtCapabilities(uint8_t linkId) const
Return the HT capabilities of the device for the given link.
Definition: wifi-mac.cc:1959
virtual std::optional< uint8_t > GetLinkIdByAddress(const Mac48Address &address) const
Get the ID of the link having the given MAC address, if any.
Definition: wifi-mac.cc:961
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the MAC has frames to transmit over the given link.
Definition: wifi-mac.cc:552
virtual void SetWifiPhys(const std::vector< Ptr< WifiPhy >> &phys)
Definition: wifi-mac.cc:1146
void ApplyTidLinkMapping(const Mac48Address &mldAddr, WifiDirection dir)
Apply the TID-to-Link Mapping negotiated with the given MLD for the given direction by properly confi...
Definition: wifi-mac.cc:1305
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition: wifi-mac.cc:1755
bool GetVhtSupported(uint8_t linkId) const
Return whether the device supports VHT on the given link.
Definition: wifi-mac.cc:1767
virtual void DeaggregateAmsduAndForward(Ptr< const WifiMpdu > mpdu)
This method can be called to de-aggregate an A-MSDU and forward the constituent packets up the stack.
Definition: wifi-mac.cc:1620
void SetBssid(Mac48Address bssid, uint8_t linkId)
Definition: wifi-mac.cc:471
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:439
void UpdateTidToLinkMapping(const Mac48Address &mldAddr, WifiDirection dir, const WifiTidLinkMapping &mapping)
Update the TID-to-Link Mappings for the given MLD in the given direction based on the given negotiate...
Definition: wifi-mac.cc:1066
ExtendedCapabilities GetExtendedCapabilities() const
Return the extended capabilities of the device.
Definition: wifi-mac.cc:1948
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition: wifi-mac.cc:545
std::optional< uint8_t > GetLinkForPhy(Ptr< const WifiPhy > phy) const
Get the ID of the link (if any) on which the given PHY is operating.
Definition: wifi-mac.cc:974
bool GetShortSlotTimeSupported() const
Definition: wifi-mac.cc:1272
void NotifyRxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:619
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:906
void ForwardUp(Ptr< const Packet > packet, Mac48Address from, Mac48Address to)
Forward the packet up to the device.
Definition: wifi-mac.cc:1490
virtual void Receive(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
This method acts as the MacRxMiddle receive callback and is invoked to notify us that a frame has bee...
Definition: wifi-mac.cc:1497
Mac48Address GetAddress() const
Definition: wifi-mac.cc:452
EhtCapabilities GetEhtCapabilities(uint8_t linkId) const
Return the EHT capabilities of the device for the given link.
Definition: wifi-mac.cc:2158
Callback< void > m_linkUp
Callback when a link is up.
Definition: wifi-mac.h:897
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: wifi-mac.cc:924
HeCapabilities GetHeCapabilities(uint8_t linkId) const
Return the HE capabilities of the device for the given link.
Definition: wifi-mac.cc:2100
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
void NotifyTxDrop(Ptr< const Packet > packet)
Definition: wifi-mac.cc:601
void DoDispose() override
Destructor implementation.
Definition: wifi-mac.cc:373
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1507
void SetSlot(Time slot)
Set the slot duration for this PHY.
Definition: wifi-phy.cc:787
void SetOffMode()
Put in off mode.
Definition: wifi-phy.cc:1383
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#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_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiPowerManagementMode
Enumeration for power management modes.
Definition: sta-wifi-mac.h:90
uint8_t QosUtilsGetTidForPacket(Ptr< const Packet > packet)
If a QoS tag is attached to the packet, returns a value < 8.
Definition: qos-utils.cc:156
WifiQueueBlockedReason
Enumeration of the reasons to block container queues.
@ STA
Definition: wifi-mac.h:65
@ WIFI_PM_SWITCHING_TO_ACTIVE
Definition: sta-wifi-mac.h:94
@ WIFI_PM_POWERSAVE
Definition: sta-wifi-mac.h:93
@ WIFI_PM_SWITCHING_TO_PS
Definition: sta-wifi-mac.h:92
@ WIFI_PM_ACTIVE
Definition: sta-wifi-mac.h:91
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
Definition: wifi-phy-band.h:43
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
@ AC_VI
Video.
Definition: qos-utils.h:79
@ AC_BK
Background.
Definition: qos-utils.h:77
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:227
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
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
@ WIFI_MAC_MGT_PROBE_REQUEST
@ WIFI_MAC_DATA_NULL
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
@ WIFI_MAC_MGT_REASSOCIATION_REQUEST
@ WIFI_MAC_MGT_PROBE_RESPONSE
@ WIFI_MAC_DATA
@ WIFI_MAC_MGT_REASSOCIATION_RESPONSE
@ WIFI_MAC_QOSDATA
bool TidToLinkMappingValidForNegType1(const WifiTidLinkMapping &dlLinkMapping, const WifiTidLinkMapping &ulLinkMapping)
Check if the given TID-to-Link Mappings are valid for a negotiation type of 1.
Definition: wifi-utils.cc:148
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
channel
Definition: third.py:88
phy
Definition: third.py:89
params
Fit Fluctuating Two Ray model to the 3GPP TR 38.901 using the Anderson-Darling goodness-of-fit ##.
Struct containing all supported rates.
void AddBssMembershipSelectorRate(uint64_t bs)
Add a special value to the supported rate set, corresponding to a BSS membership selector.
void AddSupportedRate(uint64_t bs)
Add the given rate to the supported rates.
std::optional< MldCapabilities > m_mldCapabilities
MLD Capabilities.
Struct to hold information regarding observed AP through active/passive scanning.
Definition: sta-wifi-mac.h:158
MgtFrameType m_frame
The body of the management frame used to update AP info.
Definition: sta-wifi-mac.h:172
WifiScanParams::Channel m_channel
The channel the management frame was received on.
Definition: sta-wifi-mac.h:173
Mac48Address m_apAddr
AP MAC address.
Definition: sta-wifi-mac.h:170
uint8_t m_linkId
ID of the link used to communicate with the AP.
Definition: sta-wifi-mac.h:174
Mac48Address m_bssid
BSSID.
Definition: sta-wifi-mac.h:169
double m_snr
SNR in linear scale.
Definition: sta-wifi-mac.h:171
Struct identifying a channel to scan.
Definition: sta-wifi-mac.h:68
WifiPhyBand band
PHY band.
Definition: sta-wifi-mac.h:70
uint16_t number
channel number
Definition: sta-wifi-mac.h:69
Structure holding scan parameters.
Definition: sta-wifi-mac.h:60
std::list< Channel > ChannelList
typedef for a list of channels
Definition: sta-wifi-mac.h:74
std::vector< ChannelList > channelList
list of channels to scan, for each link
Definition: sta-wifi-mac.h:78
Time probeDelay
delay prior to transmitting a Probe Request
Definition: sta-wifi-mac.h:79
WifiScanType type
indicates either active or passive scanning
Definition: sta-wifi-mac.h:76
Time maxChannelTime
maximum time to spend on each channel
Definition: sta-wifi-mac.h:81
Ssid ssid
desired SSID or wildcard SSID
Definition: sta-wifi-mac.h:77
Time minChannelTime
minimum time to spend on each channel
Definition: sta-wifi-mac.h:80