A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
emlsr-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 Universita' degli Studi di Napoli Federico II
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
20#include "emlsr-manager.h"
21
22#include "eht-configuration.h"
24
25#include "ns3/abort.h"
26#include "ns3/assert.h"
27#include "ns3/attribute-container.h"
28#include "ns3/log.h"
29#include "ns3/mgt-action-headers.h"
30#include "ns3/wifi-mpdu.h"
31#include "ns3/wifi-net-device.h"
32#include "ns3/wifi-phy-state-helper.h"
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("EmlsrManager");
38
39NS_OBJECT_ENSURE_REGISTERED(EmlsrManager);
40
41TypeId
43{
44 static TypeId tid =
45 TypeId("ns3::EmlsrManager")
47 .SetGroupName("Wifi")
48 .AddAttribute("EmlsrPaddingDelay",
49 "The EMLSR Paddind Delay (not used by AP MLDs). "
50 "Possible values are 0 us, 32 us, 64 us, 128 us or 256 us.",
54 .AddAttribute("EmlsrTransitionDelay",
55 "The EMLSR Transition Delay (not used by AP MLDs). "
56 "Possible values are 0 us, 16 us, 32 us, 64 us, 128 us or 256 us.",
60 .AddAttribute(
61 "MainPhyId",
62 "The ID of the main PHY (position in the vector of PHYs held by "
63 "WifiNetDevice). This attribute cannot be set after construction.",
64 TypeId::ATTR_GET | TypeId::ATTR_CONSTRUCT, // prevent setting after construction
67 MakeUintegerChecker<uint8_t>())
68 .AddAttribute("AuxPhyChannelWidth",
69 "The maximum channel width (MHz) supported by Aux PHYs. Note that the "
70 "maximum channel width is capped to the maximum channel width supported "
71 "by the configured maximum modulation class supported.",
73 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
74 UintegerValue(20),
76 MakeUintegerChecker<uint16_t>(20, 160))
77 .AddAttribute("AuxPhyMaxModClass",
78 "The maximum modulation class supported by Aux PHYs. Use "
79 "WIFI_MOD_CLASS_OFDM for non-HT.",
81 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
83 MakeEnumAccessor<WifiModulationClass>(&EmlsrManager::m_auxPhyMaxModClass),
85 "HR-DSSS",
87 "ERP-OFDM",
89 "OFDM",
91 "HT",
93 "VHT",
95 "HE",
97 "EHT"))
98 .AddAttribute("AuxPhyTxCapable",
99 "Whether Aux PHYs are capable of transmitting PPDUs.",
100 BooleanValue(true),
104 .AddAttribute(
105 "EmlsrLinkSet",
106 "IDs of the links on which EMLSR mode will be enabled. An empty set "
107 "indicates to disable EMLSR.",
109 MakeAttributeContainerAccessor<UintegerValue>(&EmlsrManager::SetEmlsrLinks),
110 MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()))
111 .AddAttribute("ResetCamState",
112 "Whether to reset the state of the ChannelAccessManager associated with "
113 "the link on which the main PHY has just switched to.",
114 BooleanValue(false),
118 return tid;
119}
120
122 // The STA initializes dot11MSDTimerDuration to aPPDUMaxTime defined in Table 36-70
123 // (Sec. 35.3.16.8.1 of 802.11be D3.1)
124 : m_mediumSyncDuration(MicroSeconds(DEFAULT_MSD_DURATION_USEC)),
125 // The default value of dot11MSDOFDMEDthreshold is –72 dBm and the default value of
126 // dot11MSDTXOPMax is 1, respectively (Sec. 35.3.16.8.1 of 802.11be D3.1)
127 m_msdOfdmEdThreshold(DEFAULT_MSD_OFDM_ED_THRESH),
128 m_msdMaxNTxops(DEFAULT_MSD_MAX_N_TXOPS)
129{
130 NS_LOG_FUNCTION(this);
131}
132
134{
136}
137
138void
140{
141 NS_LOG_FUNCTION(this);
145 m_staMac = nullptr;
147 for (auto& [id, status] : m_mediumSyncDelayStatus)
148 {
149 status.timer.Cancel();
150 }
152}
153
154void
156{
157 NS_LOG_FUNCTION(this << mac);
158 NS_ASSERT(mac);
159 m_staMac = mac;
160
161 NS_ABORT_MSG_IF(!m_staMac->GetEhtConfiguration(), "EmlsrManager requires EHT support");
162 NS_ABORT_MSG_IF(m_staMac->GetNLinks() <= 1, "EmlsrManager can only be installed on MLDs");
164 "EmlsrManager can only be installed on non-AP MLDs");
165
169}
170
171void
173{
174 NS_LOG_FUNCTION(this << mainPhyId);
175 NS_ABORT_MSG_IF(IsInitialized(), "Cannot be called once this object has been initialized");
176 m_mainPhyId = mainPhyId;
177}
178
179uint8_t
181{
182 return m_mainPhyId;
183}
184
185void
187{
188 m_resetCamState = enable;
189}
190
191bool
193{
194 return m_resetCamState;
195}
196
197void
199{
200 m_auxPhyTxCapable = capable;
201}
202
203bool
205{
206 return m_auxPhyTxCapable;
207}
208
209const std::set<uint8_t>&
211{
212 return m_emlsrLinks;
213}
214
217{
218 return m_staMac;
219}
220
222EmlsrManager::GetEhtFem(uint8_t linkId) const
223{
224 return StaticCast<EhtFrameExchangeManager>(m_staMac->GetFrameExchangeManager(linkId));
225}
226
227std::optional<Time>
229{
230 if (const auto statusIt = m_mediumSyncDelayStatus.find(linkId);
231 statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
232 {
233 return m_mediumSyncDuration - Simulator::GetDelayLeft(statusIt->second.timer);
234 }
235 return std::nullopt;
236}
237
238void
240{
243}
244
245std::optional<Time>
247{
249}
250
251void
253{
254 NS_LOG_FUNCTION(this << duration.As(Time::US));
255 m_mediumSyncDuration = duration;
256}
257
258Time
260{
262}
263
264void
266{
267 NS_LOG_FUNCTION(this << threshold);
268 m_msdOfdmEdThreshold = threshold;
269}
270
271int8_t
273{
275}
276
277void
278EmlsrManager::SetMediumSyncMaxNTxops(std::optional<uint8_t> nTxops)
279{
280 NS_LOG_FUNCTION(this << nTxops.has_value());
281 m_msdMaxNTxops = nTxops;
282}
283
284std::optional<uint8_t>
286{
287 return m_msdMaxNTxops;
288}
289
290void
291EmlsrManager::SetEmlsrLinks(const std::set<uint8_t>& linkIds)
292{
293 NS_LOG_FUNCTION(this);
294 NS_ABORT_MSG_IF(linkIds.size() == 1, "Cannot enable EMLSR mode on a single link");
295
296 if (linkIds != m_emlsrLinks)
297 {
298 m_nextEmlsrLinks = linkIds;
299 }
300
301 if (GetStaMac() && GetStaMac()->IsAssociated() && GetTransitionTimeout() && m_nextEmlsrLinks)
302 {
303 // Request to enable EMLSR mode on the given links, provided that they have been setup
304 SendEmlOmn();
305 }
306}
307
308void
310{
311 NS_LOG_FUNCTION(this << *mpdu << linkId);
312
313 const auto& hdr = mpdu->GetHeader();
314
315 DoNotifyMgtFrameReceived(mpdu, linkId);
316
317 if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
318 {
319 // we just completed ML setup with an AP MLD that supports EMLSR
321
322 if (m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
323 {
324 // a non-empty set of EMLSR links have been configured, hence enable EMLSR mode
325 // on those links
326 SendEmlOmn();
327 }
328 }
329
330 if (hdr.IsAction() && hdr.GetAddr2() == m_staMac->GetBssid(linkId))
331 {
332 // this is an action frame sent by an AP of the AP MLD we are associated with
333 auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
334 if (category == WifiActionHeader::PROTECTED_EHT &&
335 action.protectedEhtAction ==
337 {
339 {
340 // no need to wait until the expiration of the transition timeout
343 }
344 }
345 }
346}
347
348void
350{
351 NS_LOG_FUNCTION(this << linkId);
352
354
355 // block transmissions and suspend medium access on all other EMLSR links
356 for (auto id : m_staMac->GetLinkIds())
357 {
358 if (id != linkId && m_staMac->IsEmlsrLink(id))
359 {
362 }
363 }
364
365 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
366 auto auxPhy = m_staMac->GetWifiPhy(linkId);
367
368 if (m_staMac->GetWifiPhy(linkId) == mainPhy)
369 {
370 // nothing to do, we received an ICF from the main PHY
371 return;
372 }
373
374 Simulator::ScheduleNow([=, this]() {
375 SwitchMainPhy(linkId,
376 true, // channel switch should occur instantaneously
379
380 // aux PHY received the ICF but main PHY will send the response
381 auto uid = auxPhy->GetPreviouslyRxPpduUid();
382 mainPhy->SetPreviouslyRxPpduUid(uid);
383
384 DoNotifyIcfReceived(linkId);
385 });
386}
387
388void
389EmlsrManager::NotifyUlTxopStart(uint8_t linkId, std::optional<Time> timeToCtsEnd)
390{
391 NS_LOG_FUNCTION(this << linkId);
392
393 if (!m_staMac->IsEmlsrLink(linkId))
394 {
395 NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
396 return;
397 }
398
399 // block transmissions and suspend medium access on all other EMLSR links
400 for (auto id : m_staMac->GetLinkIds())
401 {
402 if (id != linkId && m_staMac->IsEmlsrLink(id))
403 {
406 }
407 }
408
409 // if this TXOP is being started by an aux PHY, schedule a channel switch for the main PHY
410 // such that the channel switch is completed by the time the CTS response is received. The
411 // delay has been passed by the FEM.
412 if (m_staMac->GetLinkForPhy(m_mainPhyId) != linkId)
413 {
414 auto stateHelper = m_staMac->GetWifiPhy(linkId)->GetState();
415 NS_ASSERT(stateHelper);
416 NS_ASSERT_MSG(stateHelper->GetState() == TX,
417 "Expecting the aux PHY to be transmitting (an RTS frame)");
418 NS_ASSERT_MSG(timeToCtsEnd.has_value(),
419 "Aux PHY is sending RTS, expected to get the time to CTS end");
420
421 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
422
423 // the main PHY shall terminate the channel switch at the end of CTS reception;
424 // the time remaining to the end of CTS reception includes two propagation delays
425 const auto delay = *timeToCtsEnd - mainPhy->GetChannelSwitchDelay();
426
427 NS_ASSERT(delay.IsPositive());
428 NS_LOG_DEBUG("Schedule main Phy switch in " << delay.As(Time::US));
431 this,
432 linkId,
433 false,
436 }
437
438 DoNotifyUlTxopStart(linkId);
439}
440
441void
443{
444 NS_LOG_FUNCTION(this << linkId);
445
446 if (!m_staMac->IsEmlsrLink(linkId))
447 {
448 NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
449 return;
450 }
451
452 DoNotifyTxopEnd(linkId);
453
454 Simulator::ScheduleNow([=, this]() {
455 // unblock transmissions and resume medium access on other EMLSR links
456 for (auto id : m_staMac->GetLinkIds())
457 {
458 if (m_staMac->IsEmlsrLink(id))
459 {
460 m_staMac->UnblockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
461 m_staMac->GetChannelAccessManager(id)->NotifyStopUsingOtherEmlsrLink();
462 }
463 }
464
466 });
467}
468
469void
470EmlsrManager::SetCcaEdThresholdOnLinkSwitch(Ptr<WifiPhy> phy, uint8_t linkId)
471{
472 NS_LOG_FUNCTION(this << phy << linkId);
473
474 // if a MediumSyncDelay timer is running for the link on which the main PHY is going to
475 // operate, set the CCA ED threshold to the MediumSyncDelay OFDM ED threshold
476 if (auto statusIt = m_mediumSyncDelayStatus.find(linkId);
477 statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
478 {
479 NS_LOG_DEBUG("Setting CCA ED threshold of PHY " << phy << " to " << +m_msdOfdmEdThreshold
480 << " on link " << +linkId);
481
482 // store the current CCA ED threshold in the m_prevCcaEdThreshold map, if not present
483 m_prevCcaEdThreshold.try_emplace(phy, phy->GetCcaEdThreshold());
484
485 phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
486 }
487 // otherwise, restore the previous value for the CCA ED threshold (if any)
488 else if (auto threshIt = m_prevCcaEdThreshold.find(phy);
489 threshIt != m_prevCcaEdThreshold.cend())
490 {
491 NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
492 << " on link " << +linkId);
493 phy->SetCcaEdThreshold(threshIt->second);
494 m_prevCcaEdThreshold.erase(threshIt);
495 }
496}
497
498void
499EmlsrManager::SwitchMainPhy(uint8_t linkId,
500 bool noSwitchDelay,
501 bool resetBackoff,
502 bool requestAccess)
503{
504 NS_LOG_FUNCTION(this << linkId << noSwitchDelay << resetBackoff << requestAccess);
505
506 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
507
508 NS_ASSERT_MSG(mainPhy != m_staMac->GetWifiPhy(linkId),
509 "Main PHY is already operating on link " << +linkId);
510
511 // find the link on which the main PHY is operating
512 auto currMainPhyLinkId = m_staMac->GetLinkForPhy(mainPhy);
513 NS_ASSERT_MSG(currMainPhyLinkId, "Current link ID for main PHY not found");
514
515 auto newMainPhyChannel = GetChannelForMainPhy(linkId);
516
517 NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel
518 << " to operate on link " << +linkId);
519
520 // notify the channel access manager of the upcoming channel switch(es)
521 m_staMac->GetChannelAccessManager(*currMainPhyLinkId)
522 ->NotifySwitchingEmlsrLink(mainPhy, newMainPhyChannel, linkId);
523
524 // this assert also ensures that the actual channel switch is not delayed
525 NS_ASSERT_MSG(!mainPhy->GetState()->IsStateTx(),
526 "We should not ask the main PHY to switch channel while transmitting");
527
528 // request the main PHY to switch channel
529 auto delay = mainPhy->GetChannelSwitchDelay();
530 NS_ASSERT_MSG(noSwitchDelay || delay <= m_lastAdvTransitionDelay,
531 "Transition delay (" << m_lastAdvTransitionDelay.As(Time::US)
532 << ") should exceed the channel switch delay ("
533 << delay.As(Time::US) << ")");
534 if (noSwitchDelay)
535 {
536 mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
537 }
538 mainPhy->SetOperatingChannel(newMainPhyChannel);
539 // restore previous channel switch delay
540 if (noSwitchDelay)
541 {
542 mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(delay));
543 }
544 // re-enable short time slot, if needed
545 if (m_staMac->GetWifiRemoteStationManager(linkId)->GetShortSlotTimeEnabled())
546 {
547 mainPhy->SetSlot(MicroSeconds(9));
548 }
549
550 if (resetBackoff)
551 {
552 // reset the backoffs on the link left by the main PHY
553 m_staMac->GetChannelAccessManager(*currMainPhyLinkId)->ResetAllBackoffs();
554 }
555
556 const auto timeToSwitchEnd = noSwitchDelay ? Seconds(0) : mainPhy->GetChannelSwitchDelay();
557
558 if (requestAccess)
559 {
560 // schedule channel access request on the new link when switch is completed
561 Simulator::Schedule(timeToSwitchEnd, [=, this]() {
562 for (const auto& [acIndex, ac] : wifiAcList)
563 {
564 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
565 linkId,
566 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
567 Txop::CHECK_MEDIUM_BUSY);
568 }
569 });
570 }
571
572 SetCcaEdThresholdOnLinkSwitch(mainPhy, linkId);
573 NotifyMainPhySwitch(*currMainPhyLinkId, linkId);
574}
575
576void
577EmlsrManager::SwitchAuxPhy(uint8_t currLinkId, uint8_t nextLinkId)
578{
579 NS_LOG_FUNCTION(this << currLinkId << nextLinkId);
580
581 auto auxPhy = GetStaMac()->GetWifiPhy(currLinkId);
582
583 auto newAuxPhyChannel = GetChannelForAuxPhy(nextLinkId);
584
585 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << newAuxPhyChannel
586 << " to operate on link " << +nextLinkId);
587
588 GetStaMac()
589 ->GetChannelAccessManager(currLinkId)
590 ->NotifySwitchingEmlsrLink(auxPhy, newAuxPhyChannel, nextLinkId);
591
592 auxPhy->SetOperatingChannel(newAuxPhyChannel);
593 // re-enable short time slot, if needed
594 if (m_staMac->GetWifiRemoteStationManager(nextLinkId)->GetShortSlotTimeEnabled())
595 {
596 auxPhy->SetSlot(MicroSeconds(9));
597 }
598
599 // schedule channel access request on the new link when switch is completed
600 Simulator::Schedule(auxPhy->GetChannelSwitchDelay(), [=, this]() {
601 for (const auto& [acIndex, ac] : wifiAcList)
602 {
603 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
604 nextLinkId,
605 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
606 Txop::CHECK_MEDIUM_BUSY);
607 }
608 });
609
610 SetCcaEdThresholdOnLinkSwitch(auxPhy, nextLinkId);
611}
612
613void
614EmlsrManager::StartMediumSyncDelayTimer(uint8_t linkId)
615{
616 NS_LOG_FUNCTION(this << linkId);
617
618 // iterate over all the other EMLSR links
619 for (auto id : m_staMac->GetLinkIds())
620 {
621 if (id != linkId && m_staMac->IsEmlsrLink(id))
622 {
623 const auto [it, inserted] = m_mediumSyncDelayStatus.try_emplace(id);
624
625 // reset the max number of TXOP attempts
626 it->second.msdNTxopsLeft = m_msdMaxNTxops;
627
628 // there are cases in which no PHY is operating on a link; e.g., the main PHY starts
629 // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS
630 // is not received and the UL TXOP ends before the main PHY channel switch is
631 // completed. The MSD timer is started on the link left "uncovered" by the main PHY
632 if (auto phy = m_staMac->GetWifiPhy(id); phy && !it->second.timer.IsRunning())
633 {
634 NS_LOG_DEBUG("Setting CCA ED threshold on link "
635 << +id << " to " << +m_msdOfdmEdThreshold << " PHY " << phy);
636 m_prevCcaEdThreshold[phy] = phy->GetCcaEdThreshold();
637 phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
638 }
639
640 // (re)start the timer
641 it->second.timer.Cancel();
642 it->second.timer = Simulator::Schedule(m_mediumSyncDuration,
643 &EmlsrManager::MediumSyncDelayTimerExpired,
644 this,
645 id);
646 }
647 }
648}
649
650void
651EmlsrManager::CancelMediumSyncDelayTimer(uint8_t linkId)
652{
653 NS_LOG_FUNCTION(this << linkId);
654
655 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
656
657 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
658
659 timerIt->second.timer.Cancel();
660 MediumSyncDelayTimerExpired(linkId);
661}
662
663void
664EmlsrManager::MediumSyncDelayTimerExpired(uint8_t linkId)
665{
666 NS_LOG_FUNCTION(this << linkId);
667
668 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
669
670 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && !timerIt->second.timer.IsRunning());
671
672 // reset the MSD OFDM ED threshold
673 auto phy = m_staMac->GetWifiPhy(linkId);
674
675 if (!phy)
676 {
677 // no PHY is operating on this link. This may happen when a MediumSyncDelay timer expires
678 // on the link left "uncovered" by the main PHY that is operating on another link (and the
679 // aux PHY of that link did not switch). In this case, do nothing, since the CCA ED
680 // threshold on the main PHY will be restored once the main PHY switches back to its link
681 return;
682 }
683
684 auto threshIt = m_prevCcaEdThreshold.find(phy);
685 NS_ASSERT_MSG(threshIt != m_prevCcaEdThreshold.cend(),
686 "No value to restore for CCA ED threshold on PHY " << phy);
687 NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
688 << " on link " << +linkId);
689 phy->SetCcaEdThreshold(threshIt->second);
690 m_prevCcaEdThreshold.erase(threshIt);
691}
692
693void
694EmlsrManager::DecrementMediumSyncDelayNTxops(uint8_t linkId)
695{
696 NS_LOG_FUNCTION(this << linkId);
697
698 const auto timerIt = m_mediumSyncDelayStatus.find(linkId);
699
700 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
701 NS_ASSERT(timerIt->second.msdNTxopsLeft != 0);
702
703 if (timerIt->second.msdNTxopsLeft)
704 {
705 --timerIt->second.msdNTxopsLeft.value();
706 }
707}
708
709void
710EmlsrManager::ResetMediumSyncDelayNTxops(uint8_t linkId)
711{
712 NS_LOG_FUNCTION(this << linkId);
713
714 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
715
716 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
717 timerIt->second.msdNTxopsLeft.reset();
718}
719
720bool
721EmlsrManager::MediumSyncDelayNTxopsExceeded(uint8_t linkId)
722{
723 NS_LOG_FUNCTION(this << linkId);
724
725 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
726
727 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
728 return timerIt->second.msdNTxopsLeft == 0;
729}
730
732EmlsrManager::GetEmlOmn()
733{
734 MgtEmlOmn frame;
735
736 // Add the EMLSR Parameter Update field if needed
737 if (m_lastAdvPaddingDelay != m_emlsrPaddingDelay ||
738 m_lastAdvTransitionDelay != m_emlsrTransitionDelay)
739 {
740 m_lastAdvPaddingDelay = m_emlsrPaddingDelay;
741 m_lastAdvTransitionDelay = m_emlsrTransitionDelay;
744 frame.m_emlsrParamUpdate->paddingDelay =
745 CommonInfoBasicMle::EncodeEmlsrPaddingDelay(m_lastAdvPaddingDelay);
746 frame.m_emlsrParamUpdate->transitionDelay =
747 CommonInfoBasicMle::EncodeEmlsrTransitionDelay(m_lastAdvTransitionDelay);
748 }
749
750 // We must verify that the links included in the given EMLSR link set (if any) have been setup.
751 auto setupLinkIds = m_staMac->GetSetupLinkIds();
752
753 for (auto emlsrLinkIt = m_nextEmlsrLinks->begin(); emlsrLinkIt != m_nextEmlsrLinks->end();)
754 {
755 if (auto setupLinkIt = setupLinkIds.find(*emlsrLinkIt); setupLinkIt != setupLinkIds.cend())
756 {
757 setupLinkIds.erase(setupLinkIt);
758 frame.SetLinkIdInBitmap(*emlsrLinkIt);
759 emlsrLinkIt++;
760 }
761 else
762 {
763 NS_LOG_DEBUG("Link ID " << +(*emlsrLinkIt) << " has not been setup");
764 emlsrLinkIt = m_nextEmlsrLinks->erase(emlsrLinkIt);
765 }
766 }
767
768 // EMLSR Mode is enabled if and only if the set of EMLSR links is not empty
769 frame.m_emlControl.emlsrMode = m_nextEmlsrLinks->empty() ? 0 : 1;
770
771 return frame;
772}
773
774void
775EmlsrManager::SendEmlOmn()
776{
777 NS_LOG_FUNCTION(this);
778
779 NS_ABORT_MSG_IF(!m_emlsrTransitionTimeout,
780 "AP did not advertise a Transition Timeout, cannot send EML notification");
781 NS_ASSERT_MSG(m_nextEmlsrLinks, "Need to set EMLSR links before calling this method");
782
783 // TODO if this is a single radio non-AP MLD and not all setup links are in the EMLSR link
784 // set, we have to put setup links that are not included in the given EMLSR link set (i.e.,
785 // those remaining in setupLinkIds, if m_nextEmlsrLinks is not empty) in the sleep mode:
786 // For the EMLSR mode enabled in a single radio non-AP MLD, the STA(s) affiliated with
787 // the non-AP MLD that operates on the enabled link(s) that corresponds to the bit
788 // position(s) of the EMLSR Link Bitmap subfield set to 0 shall be in doze state if a
789 // non-AP STA affiliated with the non-AP MLD that operates on one of the EMLSR links is
790 // in awake state. (Sec. 35.3.17 of 802.11be D3.0)
791
792 auto frame = GetEmlOmn();
793 auto linkId = GetLinkToSendEmlOmn();
794 GetEhtFem(linkId)->SendEmlOmn(m_staMac->GetBssid(linkId), frame);
795}
796
797void
798EmlsrManager::TxOk(Ptr<const WifiMpdu> mpdu)
799{
800 NS_LOG_FUNCTION(this << *mpdu);
801
802 const auto& hdr = mpdu->GetHeader();
803
804 if (hdr.IsAssocReq())
805 {
806 // store padding delay and transition delay advertised in AssocReq
807 MgtAssocRequestHeader assocReq;
808 mpdu->GetPacket()->PeekHeader(assocReq);
809 auto& mle = assocReq.Get<MultiLinkElement>();
810 NS_ASSERT_MSG(mle, "AssocReq should contain a Multi-Link Element");
811 m_lastAdvPaddingDelay = mle->GetEmlsrPaddingDelay();
812 m_lastAdvTransitionDelay = mle->GetEmlsrTransitionDelay();
813 }
814
815 if (hdr.IsMgt() && hdr.IsAction())
816 {
817 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
818 category == WifiActionHeader::PROTECTED_EHT &&
819 action.protectedEhtAction ==
820 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
821 {
822 // the EML Operating Mode Notification frame that we sent has been acknowledged.
823 // Start the transition timeout to wait until the request can be made effective
824 NS_ASSERT_MSG(m_emlsrTransitionTimeout, "No transition timeout received from AP");
825 m_transitionTimeoutEvent = Simulator::Schedule(*m_emlsrTransitionTimeout,
826 &EmlsrManager::ChangeEmlsrMode,
827 this);
828 }
829 }
830}
831
832void
833EmlsrManager::TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu)
834{
835 NS_LOG_FUNCTION(this << reason << *mpdu);
836
837 const auto& hdr = mpdu->GetHeader();
838
839 if (hdr.IsMgt() && hdr.IsAction())
840 {
841 auto pkt = mpdu->GetPacket()->Copy();
842 if (auto [category, action] = WifiActionHeader::Remove(pkt);
843 category == WifiActionHeader::PROTECTED_EHT &&
844 action.protectedEhtAction ==
845 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
846 {
847 // the EML Operating Mode Notification frame has been dropped. Ask the subclass
848 // whether the frame needs to be resent
849 auto linkId = ResendNotification(mpdu);
850 if (linkId)
851 {
852 MgtEmlOmn frame;
853 pkt->RemoveHeader(frame);
854 GetEhtFem(*linkId)->SendEmlOmn(m_staMac->GetBssid(*linkId), frame);
855 }
856 else
857 {
858 m_nextEmlsrLinks.reset();
859 }
860 }
861 }
862}
863
864void
865EmlsrManager::ChangeEmlsrMode()
866{
867 NS_LOG_FUNCTION(this);
868
869 // After the successful transmission of the EML Operating Mode Notification frame by the
870 // non-AP STA affiliated with the non-AP MLD, the non-AP MLD shall operate in the EMLSR mode
871 // and the other non-AP STAs operating on the corresponding EMLSR links shall transition to
872 // active mode after the transition delay indicated in the Transition Timeout subfield in the
873 // EML Capabilities subfield of the Basic Multi-Link element or immediately after receiving an
874 // EML Operating Mode Notification frame from one of the APs operating on the EMLSR links and
875 // affiliated with the AP MLD. (Sec. 35.3.17 of 802.11be D3.0)
876 NS_ASSERT_MSG(m_nextEmlsrLinks, "No set of EMLSR links stored");
877 m_emlsrLinks.swap(*m_nextEmlsrLinks);
878 m_nextEmlsrLinks.reset();
879
880 // Make other non-AP STAs operating on the corresponding EMLSR links transition to
881 // active mode or passive mode (depending on whether EMLSR mode has been enabled or disabled)
882 m_staMac->NotifyEmlsrModeChanged(m_emlsrLinks);
883 // Enforce the limit on the max channel width supported by aux PHYs
884 ApplyMaxChannelWidthAndModClassOnAuxPhys();
885
886 NotifyEmlsrModeChanged();
887}
888
889void
890EmlsrManager::ApplyMaxChannelWidthAndModClassOnAuxPhys()
891{
892 NS_LOG_FUNCTION(this);
893 auto currMainPhyLinkId = m_staMac->GetLinkForPhy(m_mainPhyId);
894 NS_ASSERT(currMainPhyLinkId);
895
896 for (const auto linkId : m_staMac->GetLinkIds())
897 {
898 auto auxPhy = m_staMac->GetWifiPhy(linkId);
899 auto channel = GetChannelForAuxPhy(linkId);
900
901 if (linkId == currMainPhyLinkId || !m_staMac->IsEmlsrLink(linkId) ||
902 auxPhy->GetOperatingChannel() == channel)
903 {
904 continue;
905 }
906
907 auxPhy->SetMaxModulationClassSupported(m_auxPhyMaxModClass);
908
909 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << channel
910 << " to operate on link " << +linkId);
911 // We cannot simply set the new channel, because otherwise the MAC will disable
912 // the setup link. We need to inform the MAC (via the Channel Access Manager) that
913 // this channel switch must not have such a consequence. We already have a method
914 // for doing so, i.e., inform the MAC that the PHY is switching channel to operate
915 // on the "same" link.
916 auto cam = m_staMac->GetChannelAccessManager(linkId);
917 cam->NotifySwitchingEmlsrLink(auxPhy, channel, linkId);
918
919 void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel;
920 Simulator::ScheduleNow(fp, auxPhy, channel);
921
922 // the way the ChannelAccessManager handles EMLSR link switch implies that a PHY listener
923 // is removed when the channel switch starts and another one is attached when the channel
924 // switch ends. In the meantime, no PHY is connected to the ChannelAccessManager. Inform
925 // the ChannelAccessManager that this channel switch is related to EMLSR operations, so
926 // that the ChannelAccessManager does not complain if events requiring access to the PHY
927 // occur during the channel switch.
928 cam->NotifyStartUsingOtherEmlsrLink();
929 Simulator::Schedule(auxPhy->GetChannelSwitchDelay(),
930 &ChannelAccessManager::NotifyStopUsingOtherEmlsrLink,
931 cam);
932 }
933}
934
935void
936EmlsrManager::ComputeOperatingChannels()
937{
938 NS_LOG_FUNCTION(this);
939
940 m_mainPhyChannels.clear();
941 m_auxPhyChannels.clear();
942
943 auto linkIds = m_staMac->GetSetupLinkIds();
944
945 for (auto linkId : linkIds)
946 {
947 const auto& channel = m_staMac->GetWifiPhy(linkId)->GetOperatingChannel();
948 m_mainPhyChannels.emplace(linkId, channel);
949
950 auto mainPhyChWidth = channel.GetWidth();
951 auto auxPhyMaxWidth =
952 std::min(m_auxPhyMaxWidth, GetMaximumChannelWidth(m_auxPhyMaxModClass));
953 if (auxPhyMaxWidth >= mainPhyChWidth)
954 {
955 // same channel can be used by aux PHYs
956 m_auxPhyChannels.emplace(linkId, channel);
957 continue;
958 }
959 // aux PHYs will operate on a primary subchannel
960 auto freq = channel.GetPrimaryChannelCenterFrequency(auxPhyMaxWidth);
961 auto chIt = WifiPhyOperatingChannel::FindFirst(0,
962 freq,
963 auxPhyMaxWidth,
965 channel.GetPhyBand());
966 NS_ASSERT_MSG(chIt != WifiPhyOperatingChannel::m_frequencyChannels.end(),
967 "Primary" << auxPhyMaxWidth << " channel not found");
968 m_auxPhyChannels.emplace(linkId, chIt);
969 // find the P20 index for the channel used by the aux PHYs
970 auto p20Index = channel.GetPrimaryChannelIndex(20);
971 while (mainPhyChWidth > auxPhyMaxWidth)
972 {
973 mainPhyChWidth /= 2;
974 p20Index /= 2;
975 }
976 m_auxPhyChannels[linkId].SetPrimary20Index(p20Index);
977 }
978}
979
981EmlsrManager::GetChannelForMainPhy(uint8_t linkId) const
982{
983 auto it = m_mainPhyChannels.find(linkId);
984 NS_ASSERT_MSG(it != m_mainPhyChannels.end(),
985 "Channel for main PHY on link ID " << +linkId << " not found");
986 return it->second;
987}
988
990EmlsrManager::GetChannelForAuxPhy(uint8_t linkId) const
991{
992 auto it = m_auxPhyChannels.find(linkId);
993 NS_ASSERT_MSG(it != m_auxPhyChannels.end(),
994 "Channel for aux PHY on link ID " << +linkId << " not found");
995 return it->second;
996}
997
998} // namespace ns3
A container for one type of attribute.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
void NotifyStartUsingOtherEmlsrLink()
Notify that another EMLSR link is being used, hence medium access should be disabled.
void SendEmlOmn()
Send an EML Operating Mode Notification frame.
Time GetMediumSyncDuration() const
void ComputeOperatingChannels()
Compute the operating channels that the main PHY and the aux PHY(s) must switch to in order to operat...
void SetTransitionTimeout(Time timeout)
Set the Transition Timeout advertised by the associated AP with EMLSR activated.
bool m_auxPhyTxCapable
whether Aux PHYs are capable of transmitting PPDUs
std::optional< Time > GetTransitionTimeout() const
Ptr< EhtFrameExchangeManager > GetEhtFem(uint8_t linkId) const
void TxDropped(WifiMacDropReason reason, Ptr< const WifiMpdu > mpdu)
Notify that the given MPDU has been discarded for the given reason.
void TxOk(Ptr< const WifiMpdu > mpdu)
Notify the acknowledgment of the given MPDU.
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay, bool resetBackoff, bool requestAccess)
Switch channel on the Main PHY so that it operates on the given link.
bool GetCamStateReset() const
void NotifyUlTxopStart(uint8_t linkId, std::optional< Time > timeToCtsEnd)
Notify the start of an UL TXOP on the given link.
void SetEmlsrLinks(const std::set< uint8_t > &linkIds)
Take actions to enable EMLSR mode on the given set of links, if non-empty, or disable EMLSR mode,...
void SetMediumSyncOfdmEdThreshold(int8_t threshold)
Set the Medium Synchronization OFDM ED threshold (dBm) to use while the MediumSyncDelay timer is runn...
uint8_t m_mainPhyId
ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
int8_t GetMediumSyncOfdmEdThreshold() const
void NotifyIcfReceived(uint8_t linkId)
Notify the reception of an initial Control frame on the given link.
std::map< uint8_t, MediumSyncDelayStatus > m_mediumSyncDelayStatus
the status of MediumSyncDelay timers (link ID-indexed)
void NotifyMgtFrameReceived(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Notify the reception of a management frame addressed to us.
virtual void DoNotifyUlTxopStart(uint8_t linkId)=0
Notify the subclass of the start of an UL TXOP on the given link.
Ptr< StaWifiMac > m_staMac
the MAC of the managed non-AP MLD
virtual void DoNotifyMgtFrameReceived(Ptr< const WifiMpdu > mpdu, uint8_t linkId)=0
Notify the subclass of the reception of a management frame addressed to us.
Time m_emlsrPaddingDelay
EMLSR Padding delay.
void SetMediumSyncMaxNTxops(std::optional< uint8_t > nTxops)
Set the maximum number of TXOPs a non-AP STA is allowed to attempt to initiate while the MediumSyncDe...
void NotifyTxopEnd(uint8_t linkId)
Notify the end of a TXOP on the given link.
Time m_emlsrTransitionDelay
EMLSR Transition delay.
void SetWifiMac(Ptr< StaWifiMac > mac)
Set the wifi MAC.
bool GetAuxPhyTxCapable() const
const std::set< uint8_t > & GetEmlsrLinks() const
Time m_mediumSyncDuration
duration of the MediumSyncDelay timer
std::optional< Time > m_emlsrTransitionTimeout
Transition timeout advertised by APs with EMLSR activated.
std::optional< Time > GetElapsedMediumSyncDelayTimer(uint8_t linkId) const
Check whether the MediumSyncDelay timer is running for the STA operating on the given link.
virtual void DoNotifyTxopEnd(uint8_t linkId)=0
Notify the subclass of the end of a TXOP on the given link.
void SetAuxPhyTxCapable(bool capable)
Set the member variable indicating whether Aux PHYs are capable of transmitting PPDUs.
std::optional< std::set< uint8_t > > m_nextEmlsrLinks
ID of the links that will become the EMLSR links when the pending notification frame is acknowledged.
void SetMainPhyId(uint8_t mainPhyId)
Set the ID of main PHY (position in the vector of PHYs held by WifiNetDevice).
~EmlsrManager() override
void SetMediumSyncDuration(Time duration)
Set the duration of the MediumSyncDelay timer.
static constexpr bool RESET_BACKOFF
reset backoff on main PHY switch
static constexpr bool DONT_REQUEST_ACCESS
do not request channel access when PHY switch ends
void DoDispose() override
Destructor implementation.
void StartMediumSyncDelayTimer(uint8_t linkId)
Start the MediumSyncDelay timer and take the appropriate actions, if the timer is not already running...
int8_t m_msdOfdmEdThreshold
MediumSyncDelay OFDM ED threshold.
std::optional< uint8_t > m_msdMaxNTxops
MediumSyncDelay max number of TXOPs.
Ptr< StaWifiMac > GetStaMac() const
WifiModulationClass m_auxPhyMaxModClass
max modulation class supported by aux PHYs
uint8_t GetMainPhyId() const
std::optional< uint8_t > GetMediumSyncMaxNTxops() const
void SetCamStateReset(bool enable)
Set the member variable indicating whether the state of the CAM should be reset when the main PHY swi...
EventId m_transitionTimeoutEvent
Timer started after the successful transmission of an EML Operating Mode Notification frame.
uint16_t m_auxPhyMaxWidth
max channel width (MHz) supported by aux PHYs
virtual void DoNotifyIcfReceived(uint8_t linkId)=0
Notify the subclass of the reception of an initial Control frame on the given link.
bool m_resetCamState
whether to reset the state of CAM when main PHY switches channel
static TypeId GetTypeId()
Get the type ID.
std::set< uint8_t > m_emlsrLinks
ID of the EMLSR links (empty if EMLSR mode is disabled)
Hold variables of type enum.
Definition: enum.h:62
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
EventImpl * PeekEventImpl() const
Definition: event-id.cc:83
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
void Invoke()
Called by the simulation engine to notify the event that it is time to execute.
Definition: event-impl.cc:47
Implement the header for management frames of type association request.
Definition: mgt-headers.h:157
Implement the header for Action frames of type EML Operating Mode Notification.
void SetLinkIdInBitmap(uint8_t linkId)
Set the bit position in the link bitmap corresponding to the given link.
EmlControl m_emlControl
EML Control field.
std::optional< EmlsrParamUpdate > m_emlsrParamUpdate
EMLSR Parameter Update field.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:315
bool TraceDisconnectWithoutContext(std::string name, const CallbackBase &cb)
Disconnect from a TraceSource a Callback previously connected without a context.
Definition: object-base.cc:343
A base class which provides memory management and object aggregation.
Definition: object.h:89
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
bool IsInitialized() const
Check if the object has been initialized.
Definition: object.cc:212
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:217
void BlockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
Block transmissions on the given link for the given reason.
bool IsEmlsrLink(uint8_t linkId) const
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
@ US
microsecond
Definition: nstime.h:118
AttributeValue implementation for Time.
Definition: nstime.h:1413
a unique identifier for an interface.
Definition: type-id.h:59
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:64
@ ATTR_CONSTRUCT
The attribute can be written at construction-time.
Definition: type-id.h:66
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
static std::pair< CategoryValue, ActionValue > Peek(Ptr< const Packet > pkt)
Peek an Action header from the given packet.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition: wifi-mac.cc:864
Mac48Address GetBssid(uint8_t linkId) const
Definition: wifi-mac.cc:478
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:422
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:933
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1171
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition: wifi-mac.cc:1755
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:439
std::optional< uint8_t > GetLinkForPhy(Ptr< const WifiPhy > phy) const
Get the ID of the link (if any) on which the given PHY is operating.
Definition: wifi-mac.cc:974
const std::set< uint8_t > & GetLinkIds() const
Definition: wifi-mac.cc:939
Ptr< ChannelAccessManager > GetChannelAccessManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Channel Access Manager associated with the given link.
Definition: wifi-mac.cc:870
Ptr< WifiPhy > GetPhy() const
802.11 PHY layer model
Definition: wifi-phy.h:53
Time GetChannelSwitchDelay() const
Definition: wifi-phy.cc:690
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition: wifi-phy.cc:443
Class that keeps track of all information about the current PHY operating channel.
#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 AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1434
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
WifiMacDropReason
The reason why an MPDU was dropped.
Definition: wifi-mac.h:77
@ STA
Definition: wifi-mac.h:65
@ WIFI_STANDARD_UNSPECIFIED
@ WIFI_MOD_CLASS_OFDM
OFDM (Clause 17)
@ 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)
@ WIFI_MOD_CLASS_ERP_OFDM
ERP-OFDM (18.4)
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr uint8_t DEFAULT_MSD_MAX_N_TXOPS
default MediumSyncDelay max number of TXOP attempts
uint16_t GetMaximumChannelWidth(WifiModulationClass modulation)
Get the maximum channel width in MHz allowed for the given modulation class.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:194
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition: qos-utils.cc:126
static constexpr int8_t DEFAULT_MSD_OFDM_ED_THRESH
default MediumSyncDelay timer OFDM ED threshold
static constexpr uint16_t DEFAULT_MSD_DURATION_USEC
default MediumSyncDelay timer duration (max PPDU TX time rounded to a multiple of 32 us)
ns3::Time timeout
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
EMLSR Parameter Update field.
@ TX
The PHY layer is sending a packet.