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