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
34#include <iterator>
35#include <sstream>
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("EmlsrManager");
41
42NS_OBJECT_ENSURE_REGISTERED(EmlsrManager);
43
44TypeId
46{
47 static TypeId tid =
48 TypeId("ns3::EmlsrManager")
50 .SetGroupName("Wifi")
51 .AddAttribute("EmlsrPaddingDelay",
52 "The EMLSR Paddind Delay (not used by AP MLDs). "
53 "Possible values are 0 us, 32 us, 64 us, 128 us or 256 us.",
57 .AddAttribute("EmlsrTransitionDelay",
58 "The EMLSR Transition Delay (not used by AP MLDs). "
59 "Possible values are 0 us, 16 us, 32 us, 64 us, 128 us or 256 us.",
63 .AddAttribute(
64 "MainPhyId",
65 "The ID of the main PHY (position in the vector of PHYs held by "
66 "WifiNetDevice). This attribute cannot be set after construction.",
67 TypeId::ATTR_GET | TypeId::ATTR_CONSTRUCT, // prevent setting after construction
70 MakeUintegerChecker<uint8_t>())
71 .AddAttribute("AuxPhyChannelWidth",
72 "The maximum channel width (MHz) supported by Aux PHYs. Note that the "
73 "maximum channel width is capped to the maximum channel width supported "
74 "by the configured maximum modulation class supported.",
76 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
77 UintegerValue(20),
79 MakeUintegerChecker<uint16_t>(20, 160))
80 .AddAttribute("AuxPhyMaxModClass",
81 "The maximum modulation class supported by Aux PHYs. Use "
82 "WIFI_MOD_CLASS_OFDM for non-HT.",
84 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
86 MakeEnumAccessor<WifiModulationClass>(&EmlsrManager::m_auxPhyMaxModClass),
88 "HR-DSSS",
90 "ERP-OFDM",
92 "OFDM",
94 "HT",
96 "VHT",
98 "HE",
100 "EHT"))
101 .AddAttribute("AuxPhyTxCapable",
102 "Whether Aux PHYs are capable of transmitting PPDUs.",
103 BooleanValue(true),
107 .AddAttribute(
108 "EmlsrLinkSet",
109 "IDs of the links on which EMLSR mode will be enabled. An empty set "
110 "indicates to disable EMLSR.",
112 MakeAttributeContainerAccessor<UintegerValue>(&EmlsrManager::SetEmlsrLinks),
113 MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()))
114 .AddAttribute("ResetCamState",
115 "Whether to reset the state of the ChannelAccessManager associated with "
116 "the link on which the main PHY has just switched to.",
117 BooleanValue(false),
121 return tid;
122}
123
125 // The STA initializes dot11MSDTimerDuration to aPPDUMaxTime defined in Table 36-70
126 // (Sec. 35.3.16.8.1 of 802.11be D3.1)
127 : m_mediumSyncDuration(MicroSeconds(DEFAULT_MSD_DURATION_USEC)),
128 // The default value of dot11MSDOFDMEDthreshold is –72 dBm and the default value of
129 // dot11MSDTXOPMax is 1, respectively (Sec. 35.3.16.8.1 of 802.11be D3.1)
130 m_msdOfdmEdThreshold(DEFAULT_MSD_OFDM_ED_THRESH),
131 m_msdMaxNTxops(DEFAULT_MSD_MAX_N_TXOPS)
132{
133 NS_LOG_FUNCTION(this);
134}
135
137{
139}
140
141void
143{
144 NS_LOG_FUNCTION(this);
148 m_staMac = nullptr;
150 for (auto& [id, status] : m_mediumSyncDelayStatus)
151 {
152 status.timer.Cancel();
153 }
155}
156
157void
159{
160 NS_LOG_FUNCTION(this << mac);
161 NS_ASSERT(mac);
162 m_staMac = mac;
163
164 NS_ABORT_MSG_IF(!m_staMac->GetEhtConfiguration(), "EmlsrManager requires EHT support");
165 NS_ABORT_MSG_IF(m_staMac->GetNLinks() <= 1, "EmlsrManager can only be installed on MLDs");
167 "EmlsrManager can only be installed on non-AP MLDs");
168
172}
173
174void
176{
177 NS_LOG_FUNCTION(this << mainPhyId);
178 NS_ABORT_MSG_IF(IsInitialized(), "Cannot be called once this object has been initialized");
179 m_mainPhyId = mainPhyId;
180}
181
182uint8_t
184{
185 return m_mainPhyId;
186}
187
188void
190{
191 m_resetCamState = enable;
192}
193
194bool
196{
197 return m_resetCamState;
198}
199
200void
202{
203 m_auxPhyTxCapable = capable;
204}
205
206bool
208{
209 return m_auxPhyTxCapable;
210}
211
212const std::set<uint8_t>&
214{
215 return m_emlsrLinks;
216}
217
220{
221 return m_staMac;
222}
223
225EmlsrManager::GetEhtFem(uint8_t linkId) const
226{
227 return StaticCast<EhtFrameExchangeManager>(m_staMac->GetFrameExchangeManager(linkId));
228}
229
230std::optional<Time>
232{
233 if (const auto statusIt = m_mediumSyncDelayStatus.find(linkId);
234 statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
235 {
236 return m_mediumSyncDuration - Simulator::GetDelayLeft(statusIt->second.timer);
237 }
238 return std::nullopt;
239}
240
241void
243{
246}
247
248std::optional<Time>
250{
252}
253
254void
256{
257 NS_LOG_FUNCTION(this << duration.As(Time::US));
258 m_mediumSyncDuration = duration;
259}
260
261Time
263{
265}
266
267void
269{
270 NS_LOG_FUNCTION(this << threshold);
271 m_msdOfdmEdThreshold = threshold;
272}
273
274int8_t
276{
278}
279
280void
281EmlsrManager::SetMediumSyncMaxNTxops(std::optional<uint8_t> nTxops)
282{
283 NS_LOG_FUNCTION(this << nTxops.has_value());
284 m_msdMaxNTxops = nTxops;
285}
286
287std::optional<uint8_t>
289{
290 return m_msdMaxNTxops;
291}
292
293void
294EmlsrManager::SetEmlsrLinks(const std::set<uint8_t>& linkIds)
295{
296 std::stringstream ss;
297 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
298 {
299 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
300 }
301 NS_LOG_FUNCTION(this << ss.str());
302 NS_ABORT_MSG_IF(linkIds.size() == 1, "Cannot enable EMLSR mode on a single link");
303
304 if (linkIds != m_emlsrLinks)
305 {
306 m_nextEmlsrLinks = linkIds;
307 }
308
309 if (GetStaMac() && GetStaMac()->IsAssociated() && GetTransitionTimeout() && m_nextEmlsrLinks)
310 {
311 // Request to enable EMLSR mode on the given links, provided that they have been setup
312 SendEmlOmn();
313 }
314}
315
316void
318{
319 NS_LOG_FUNCTION(this << *mpdu << linkId);
320
321 const auto& hdr = mpdu->GetHeader();
322
323 DoNotifyMgtFrameReceived(mpdu, linkId);
324
325 if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
326 {
327 // we just completed ML setup with an AP MLD that supports EMLSR
329
330 if (m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
331 {
332 // a non-empty set of EMLSR links have been configured, hence enable EMLSR mode
333 // on those links
334 SendEmlOmn();
335 }
336 }
337
338 if (hdr.IsAction() && hdr.GetAddr2() == m_staMac->GetBssid(linkId))
339 {
340 // this is an action frame sent by an AP of the AP MLD we are associated with
341 auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
342 if (category == WifiActionHeader::PROTECTED_EHT &&
343 action.protectedEhtAction ==
345 {
347 {
348 // no need to wait until the expiration of the transition timeout
351 }
352 }
353 }
354}
355
356void
358{
359 NS_LOG_FUNCTION(this << linkId);
360
362
363 // block transmissions and suspend medium access on all other EMLSR links
364 for (auto id : m_staMac->GetLinkIds())
365 {
366 if (id != linkId && m_staMac->IsEmlsrLink(id))
367 {
370 }
371 }
372
373 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
374 auto auxPhy = m_staMac->GetWifiPhy(linkId);
375
376 if (m_staMac->GetWifiPhy(linkId) == mainPhy)
377 {
378 // nothing to do, we received an ICF from the main PHY
379 return;
380 }
381
382 Simulator::ScheduleNow([=, this]() {
383 SwitchMainPhy(linkId,
384 true, // channel switch should occur instantaneously
387
388 // aux PHY received the ICF but main PHY will send the response
389 auto uid = auxPhy->GetPreviouslyRxPpduUid();
390 mainPhy->SetPreviouslyRxPpduUid(uid);
391
392 DoNotifyIcfReceived(linkId);
393 });
394}
395
396void
397EmlsrManager::NotifyUlTxopStart(uint8_t linkId, std::optional<Time> timeToCtsEnd)
398{
399 NS_LOG_FUNCTION(this << linkId);
400
401 if (!m_staMac->IsEmlsrLink(linkId))
402 {
403 NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
404 return;
405 }
406
407 // block transmissions and suspend medium access on all other EMLSR links
408 for (auto id : m_staMac->GetLinkIds())
409 {
410 if (id != linkId && m_staMac->IsEmlsrLink(id))
411 {
414 }
415 }
416
417 // if this TXOP is being started by an aux PHY, schedule a channel switch for the main PHY
418 // such that the channel switch is completed by the time the CTS response is received. The
419 // delay has been passed by the FEM.
420 if (m_staMac->GetLinkForPhy(m_mainPhyId) != linkId)
421 {
422 auto stateHelper = m_staMac->GetWifiPhy(linkId)->GetState();
423 NS_ASSERT(stateHelper);
424 NS_ASSERT_MSG(stateHelper->GetState() == WifiPhyState::TX,
425 "Expecting the aux PHY to be transmitting (an RTS frame)");
426 NS_ASSERT_MSG(timeToCtsEnd.has_value(),
427 "Aux PHY is sending RTS, expected to get the time to CTS end");
428
429 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
430
431 // the main PHY shall terminate the channel switch at the end of CTS reception;
432 // the time remaining to the end of CTS reception includes two propagation delays
433 const auto delay = *timeToCtsEnd - mainPhy->GetChannelSwitchDelay();
434
435 NS_ASSERT(delay.IsPositive());
436 NS_LOG_DEBUG("Schedule main Phy switch in " << delay.As(Time::US));
439 this,
440 linkId,
441 false,
444 }
445
446 DoNotifyUlTxopStart(linkId);
447}
448
449void
451{
452 NS_LOG_FUNCTION(this << linkId);
453
454 if (!m_staMac->IsEmlsrLink(linkId))
455 {
456 NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
457 return;
458 }
459
460 DoNotifyTxopEnd(linkId);
461
462 Simulator::ScheduleNow([=, this]() {
463 // unblock transmissions and resume medium access on other EMLSR links
464 std::set<uint8_t> linkIds;
465 for (auto id : m_staMac->GetLinkIds())
466 {
467 if ((id != linkId) && m_staMac->IsEmlsrLink(id))
468 {
469 m_staMac->GetChannelAccessManager(id)->NotifyStopUsingOtherEmlsrLink();
470 linkIds.insert(id);
471 }
472 }
474
476 });
477}
478
479void
480EmlsrManager::SetCcaEdThresholdOnLinkSwitch(Ptr<WifiPhy> phy, uint8_t linkId)
481{
482 NS_LOG_FUNCTION(this << phy << linkId);
483
484 // if a MediumSyncDelay timer is running for the link on which the main PHY is going to
485 // operate, set the CCA ED threshold to the MediumSyncDelay OFDM ED threshold
486 if (auto statusIt = m_mediumSyncDelayStatus.find(linkId);
487 statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
488 {
489 NS_LOG_DEBUG("Setting CCA ED threshold of PHY " << phy << " to " << +m_msdOfdmEdThreshold
490 << " on link " << +linkId);
491
492 // store the current CCA ED threshold in the m_prevCcaEdThreshold map, if not present
493 m_prevCcaEdThreshold.try_emplace(phy, phy->GetCcaEdThreshold());
494
495 phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
496 }
497 // otherwise, restore the previous value for the CCA ED threshold (if any)
498 else if (auto threshIt = m_prevCcaEdThreshold.find(phy);
499 threshIt != m_prevCcaEdThreshold.cend())
500 {
501 NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
502 << " on link " << +linkId);
503 phy->SetCcaEdThreshold(threshIt->second);
504 m_prevCcaEdThreshold.erase(threshIt);
505 }
506}
507
508void
509EmlsrManager::SwitchMainPhy(uint8_t linkId,
510 bool noSwitchDelay,
511 bool resetBackoff,
512 bool requestAccess)
513{
514 NS_LOG_FUNCTION(this << linkId << noSwitchDelay << resetBackoff << requestAccess);
515
516 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
517
518 NS_ASSERT_MSG(mainPhy != m_staMac->GetWifiPhy(linkId),
519 "Main PHY is already operating on link " << +linkId);
520
521 // find the link on which the main PHY is operating
522 auto currMainPhyLinkId = m_staMac->GetLinkForPhy(mainPhy);
523 NS_ASSERT_MSG(currMainPhyLinkId, "Current link ID for main PHY not found");
524
525 auto newMainPhyChannel = GetChannelForMainPhy(linkId);
526
527 NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel
528 << " to operate on link " << +linkId);
529
530 // notify the channel access manager of the upcoming channel switch(es)
531 m_staMac->GetChannelAccessManager(*currMainPhyLinkId)
532 ->NotifySwitchingEmlsrLink(mainPhy, newMainPhyChannel, linkId);
533
534 // this assert also ensures that the actual channel switch is not delayed
535 NS_ASSERT_MSG(!mainPhy->GetState()->IsStateTx(),
536 "We should not ask the main PHY to switch channel while transmitting");
537
538 // request the main PHY to switch channel
539 const auto delay = mainPhy->GetChannelSwitchDelay();
540 const auto pifs = mainPhy->GetSifs() + mainPhy->GetSlot();
541 NS_ASSERT_MSG(noSwitchDelay || delay <= std::max(m_lastAdvTransitionDelay, pifs),
542 "Channel switch delay ("
543 << delay.As(Time::US)
544 << ") should be shorter than the maximum between the Transition delay ("
545 << m_lastAdvTransitionDelay.As(Time::US) << ") and a PIFS ("
546 << pifs.As(Time::US) << ")");
547 if (noSwitchDelay)
548 {
549 mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
550 }
551 mainPhy->SetOperatingChannel(newMainPhyChannel);
552 // restore previous channel switch delay
553 if (noSwitchDelay)
554 {
555 mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(delay));
556 }
557 // re-enable short time slot, if needed
558 if (m_staMac->GetWifiRemoteStationManager(linkId)->GetShortSlotTimeEnabled())
559 {
560 mainPhy->SetSlot(MicroSeconds(9));
561 }
562
563 if (resetBackoff)
564 {
565 // reset the backoffs on the link left by the main PHY
566 m_staMac->GetChannelAccessManager(*currMainPhyLinkId)->ResetAllBackoffs();
567 }
568
569 const auto timeToSwitchEnd = noSwitchDelay ? Seconds(0) : mainPhy->GetChannelSwitchDelay();
570
571 if (requestAccess)
572 {
573 // schedule channel access request on the new link when switch is completed
574 Simulator::Schedule(timeToSwitchEnd, [=, this]() {
575 for (const auto& [acIndex, ac] : wifiAcList)
576 {
577 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
578 linkId,
579 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
580 Txop::CHECK_MEDIUM_BUSY);
581 }
582 });
583 }
584
585 SetCcaEdThresholdOnLinkSwitch(mainPhy, linkId);
586 NotifyMainPhySwitch(*currMainPhyLinkId, linkId);
587}
588
589void
590EmlsrManager::SwitchAuxPhy(uint8_t currLinkId, uint8_t nextLinkId)
591{
592 NS_LOG_FUNCTION(this << currLinkId << nextLinkId);
593
594 auto auxPhy = GetStaMac()->GetWifiPhy(currLinkId);
595
596 auto newAuxPhyChannel = GetChannelForAuxPhy(nextLinkId);
597
598 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << newAuxPhyChannel
599 << " to operate on link " << +nextLinkId);
600
601 GetStaMac()
602 ->GetChannelAccessManager(currLinkId)
603 ->NotifySwitchingEmlsrLink(auxPhy, newAuxPhyChannel, nextLinkId);
604
605 auxPhy->SetOperatingChannel(newAuxPhyChannel);
606 // re-enable short time slot, if needed
607 if (m_staMac->GetWifiRemoteStationManager(nextLinkId)->GetShortSlotTimeEnabled())
608 {
609 auxPhy->SetSlot(MicroSeconds(9));
610 }
611
612 // schedule channel access request on the new link when switch is completed
613 Simulator::Schedule(auxPhy->GetChannelSwitchDelay(), [=, this]() {
614 for (const auto& [acIndex, ac] : wifiAcList)
615 {
616 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
617 nextLinkId,
618 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
619 Txop::CHECK_MEDIUM_BUSY);
620 }
621 });
622
623 SetCcaEdThresholdOnLinkSwitch(auxPhy, nextLinkId);
624}
625
626void
627EmlsrManager::StartMediumSyncDelayTimer(uint8_t linkId)
628{
629 NS_LOG_FUNCTION(this << linkId);
630
631 // iterate over all the other EMLSR links
632 for (auto id : m_staMac->GetLinkIds())
633 {
634 if (id != linkId && m_staMac->IsEmlsrLink(id))
635 {
636 const auto [it, inserted] = m_mediumSyncDelayStatus.try_emplace(id);
637
638 // reset the max number of TXOP attempts
639 it->second.msdNTxopsLeft = m_msdMaxNTxops;
640
641 // there are cases in which no PHY is operating on a link; e.g., the main PHY starts
642 // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS
643 // is not received and the UL TXOP ends before the main PHY channel switch is
644 // completed. The MSD timer is started on the link left "uncovered" by the main PHY
645 if (auto phy = m_staMac->GetWifiPhy(id); phy && !it->second.timer.IsRunning())
646 {
647 NS_LOG_DEBUG("Setting CCA ED threshold on link "
648 << +id << " to " << +m_msdOfdmEdThreshold << " PHY " << phy);
649 m_prevCcaEdThreshold[phy] = phy->GetCcaEdThreshold();
650 phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
651 }
652
653 // (re)start the timer
654 it->second.timer.Cancel();
655 it->second.timer = Simulator::Schedule(m_mediumSyncDuration,
656 &EmlsrManager::MediumSyncDelayTimerExpired,
657 this,
658 id);
659 }
660 }
661}
662
663void
664EmlsrManager::CancelMediumSyncDelayTimer(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 timerIt->second.timer.Cancel();
673 MediumSyncDelayTimerExpired(linkId);
674}
675
676void
677EmlsrManager::MediumSyncDelayTimerExpired(uint8_t linkId)
678{
679 NS_LOG_FUNCTION(this << linkId);
680
681 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
682
683 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && !timerIt->second.timer.IsRunning());
684
685 // reset the MSD OFDM ED threshold
686 auto phy = m_staMac->GetWifiPhy(linkId);
687
688 if (!phy)
689 {
690 // no PHY is operating on this link. This may happen when a MediumSyncDelay timer expires
691 // on the link left "uncovered" by the main PHY that is operating on another link (and the
692 // aux PHY of that link did not switch). In this case, do nothing, since the CCA ED
693 // threshold on the main PHY will be restored once the main PHY switches back to its link
694 return;
695 }
696
697 auto threshIt = m_prevCcaEdThreshold.find(phy);
698 NS_ASSERT_MSG(threshIt != m_prevCcaEdThreshold.cend(),
699 "No value to restore for CCA ED threshold on PHY " << phy);
700 NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
701 << " on link " << +linkId);
702 phy->SetCcaEdThreshold(threshIt->second);
703 m_prevCcaEdThreshold.erase(threshIt);
704}
705
706void
707EmlsrManager::DecrementMediumSyncDelayNTxops(uint8_t linkId)
708{
709 NS_LOG_FUNCTION(this << linkId);
710
711 const auto timerIt = m_mediumSyncDelayStatus.find(linkId);
712
713 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
714 NS_ASSERT(timerIt->second.msdNTxopsLeft != 0);
715
716 if (timerIt->second.msdNTxopsLeft)
717 {
718 --timerIt->second.msdNTxopsLeft.value();
719 }
720}
721
722void
723EmlsrManager::ResetMediumSyncDelayNTxops(uint8_t linkId)
724{
725 NS_LOG_FUNCTION(this << linkId);
726
727 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
728
729 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
730 timerIt->second.msdNTxopsLeft.reset();
731}
732
733bool
734EmlsrManager::MediumSyncDelayNTxopsExceeded(uint8_t linkId)
735{
736 NS_LOG_FUNCTION(this << linkId);
737
738 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
739
740 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
741 return timerIt->second.msdNTxopsLeft == 0;
742}
743
745EmlsrManager::GetEmlOmn()
746{
747 MgtEmlOmn frame;
748
749 // Add the EMLSR Parameter Update field if needed
750 if (m_lastAdvPaddingDelay != m_emlsrPaddingDelay ||
751 m_lastAdvTransitionDelay != m_emlsrTransitionDelay)
752 {
753 m_lastAdvPaddingDelay = m_emlsrPaddingDelay;
754 m_lastAdvTransitionDelay = m_emlsrTransitionDelay;
757 frame.m_emlsrParamUpdate->paddingDelay =
758 CommonInfoBasicMle::EncodeEmlsrPaddingDelay(m_lastAdvPaddingDelay);
759 frame.m_emlsrParamUpdate->transitionDelay =
760 CommonInfoBasicMle::EncodeEmlsrTransitionDelay(m_lastAdvTransitionDelay);
761 }
762
763 // We must verify that the links included in the given EMLSR link set (if any) have been setup.
764 auto setupLinkIds = m_staMac->GetSetupLinkIds();
765
766 for (auto emlsrLinkIt = m_nextEmlsrLinks->begin(); emlsrLinkIt != m_nextEmlsrLinks->end();)
767 {
768 if (auto setupLinkIt = setupLinkIds.find(*emlsrLinkIt); setupLinkIt != setupLinkIds.cend())
769 {
770 setupLinkIds.erase(setupLinkIt);
771 frame.SetLinkIdInBitmap(*emlsrLinkIt);
772 emlsrLinkIt++;
773 }
774 else
775 {
776 NS_LOG_DEBUG("Link ID " << +(*emlsrLinkIt) << " has not been setup");
777 emlsrLinkIt = m_nextEmlsrLinks->erase(emlsrLinkIt);
778 }
779 }
780
781 // EMLSR Mode is enabled if and only if the set of EMLSR links is not empty
782 frame.m_emlControl.emlsrMode = m_nextEmlsrLinks->empty() ? 0 : 1;
783
784 return frame;
785}
786
787void
788EmlsrManager::SendEmlOmn()
789{
790 NS_LOG_FUNCTION(this);
791
792 NS_ABORT_MSG_IF(!m_emlsrTransitionTimeout,
793 "AP did not advertise a Transition Timeout, cannot send EML notification");
794 NS_ASSERT_MSG(m_nextEmlsrLinks, "Need to set EMLSR links before calling this method");
795
796 // TODO if this is a single radio non-AP MLD and not all setup links are in the EMLSR link
797 // set, we have to put setup links that are not included in the given EMLSR link set (i.e.,
798 // those remaining in setupLinkIds, if m_nextEmlsrLinks is not empty) in the sleep mode:
799 // For the EMLSR mode enabled in a single radio non-AP MLD, the STA(s) affiliated with
800 // the non-AP MLD that operates on the enabled link(s) that corresponds to the bit
801 // position(s) of the EMLSR Link Bitmap subfield set to 0 shall be in doze state if a
802 // non-AP STA affiliated with the non-AP MLD that operates on one of the EMLSR links is
803 // in awake state. (Sec. 35.3.17 of 802.11be D3.0)
804
805 auto frame = GetEmlOmn();
806 auto linkId = GetLinkToSendEmlOmn();
807 GetEhtFem(linkId)->SendEmlOmn(m_staMac->GetBssid(linkId), frame);
808}
809
810void
811EmlsrManager::TxOk(Ptr<const WifiMpdu> mpdu)
812{
813 NS_LOG_FUNCTION(this << *mpdu);
814
815 const auto& hdr = mpdu->GetHeader();
816
817 if (hdr.IsAssocReq())
818 {
819 // store padding delay and transition delay advertised in AssocReq
820 MgtAssocRequestHeader assocReq;
821 mpdu->GetPacket()->PeekHeader(assocReq);
822 auto& mle = assocReq.Get<MultiLinkElement>();
823 NS_ASSERT_MSG(mle, "AssocReq should contain a Multi-Link Element");
824 m_lastAdvPaddingDelay = mle->GetEmlsrPaddingDelay();
825 m_lastAdvTransitionDelay = mle->GetEmlsrTransitionDelay();
826 }
827
828 if (hdr.IsMgt() && hdr.IsAction())
829 {
830 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
831 category == WifiActionHeader::PROTECTED_EHT &&
832 action.protectedEhtAction ==
833 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
834 {
835 // the EML Operating Mode Notification frame that we sent has been acknowledged.
836 // Start the transition timeout to wait until the request can be made effective
837 NS_ASSERT_MSG(m_emlsrTransitionTimeout, "No transition timeout received from AP");
838 m_transitionTimeoutEvent = Simulator::Schedule(*m_emlsrTransitionTimeout,
839 &EmlsrManager::ChangeEmlsrMode,
840 this);
841 }
842 }
843}
844
845void
846EmlsrManager::TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu)
847{
848 NS_LOG_FUNCTION(this << reason << *mpdu);
849
850 const auto& hdr = mpdu->GetHeader();
851
852 if (hdr.IsMgt() && hdr.IsAction())
853 {
854 auto pkt = mpdu->GetPacket()->Copy();
855 if (auto [category, action] = WifiActionHeader::Remove(pkt);
856 category == WifiActionHeader::PROTECTED_EHT &&
857 action.protectedEhtAction ==
858 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
859 {
860 // the EML Operating Mode Notification frame has been dropped. Ask the subclass
861 // whether the frame needs to be resent
862 auto linkId = ResendNotification(mpdu);
863 if (linkId)
864 {
865 MgtEmlOmn frame;
866 pkt->RemoveHeader(frame);
867 GetEhtFem(*linkId)->SendEmlOmn(m_staMac->GetBssid(*linkId), frame);
868 }
869 else
870 {
871 m_nextEmlsrLinks.reset();
872 }
873 }
874 }
875}
876
877void
878EmlsrManager::ChangeEmlsrMode()
879{
880 NS_LOG_FUNCTION(this);
881
882 // After the successful transmission of the EML Operating Mode Notification frame by the
883 // non-AP STA affiliated with the non-AP MLD, the non-AP MLD shall operate in the EMLSR mode
884 // and the other non-AP STAs operating on the corresponding EMLSR links shall transition to
885 // active mode after the transition delay indicated in the Transition Timeout subfield in the
886 // EML Capabilities subfield of the Basic Multi-Link element or immediately after receiving an
887 // EML Operating Mode Notification frame from one of the APs operating on the EMLSR links and
888 // affiliated with the AP MLD. (Sec. 35.3.17 of 802.11be D3.0)
889 NS_ASSERT_MSG(m_nextEmlsrLinks, "No set of EMLSR links stored");
890 m_emlsrLinks.swap(*m_nextEmlsrLinks);
891 m_nextEmlsrLinks.reset();
892
893 // Make other non-AP STAs operating on the corresponding EMLSR links transition to
894 // active mode or passive mode (depending on whether EMLSR mode has been enabled or disabled)
895 m_staMac->NotifyEmlsrModeChanged(m_emlsrLinks);
896 // Enforce the limit on the max channel width supported by aux PHYs
897 ApplyMaxChannelWidthAndModClassOnAuxPhys();
898
899 NotifyEmlsrModeChanged();
900}
901
902void
903EmlsrManager::ApplyMaxChannelWidthAndModClassOnAuxPhys()
904{
905 NS_LOG_FUNCTION(this);
906 auto currMainPhyLinkId = m_staMac->GetLinkForPhy(m_mainPhyId);
907 NS_ASSERT(currMainPhyLinkId);
908
909 for (const auto linkId : m_staMac->GetLinkIds())
910 {
911 auto auxPhy = m_staMac->GetWifiPhy(linkId);
912 auto channel = GetChannelForAuxPhy(linkId);
913
914 if (linkId == currMainPhyLinkId || !m_staMac->IsEmlsrLink(linkId) ||
915 auxPhy->GetOperatingChannel() == channel)
916 {
917 continue;
918 }
919
920 auxPhy->SetMaxModulationClassSupported(m_auxPhyMaxModClass);
921
922 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << channel
923 << " to operate on link " << +linkId);
924 // We cannot simply set the new channel, because otherwise the MAC will disable
925 // the setup link. We need to inform the MAC (via the Channel Access Manager) that
926 // this channel switch must not have such a consequence. We already have a method
927 // for doing so, i.e., inform the MAC that the PHY is switching channel to operate
928 // on the "same" link.
929 auto cam = m_staMac->GetChannelAccessManager(linkId);
930 cam->NotifySwitchingEmlsrLink(auxPhy, channel, linkId);
931
932 auxPhy->SetOperatingChannel(channel);
933
934 // the way the ChannelAccessManager handles EMLSR link switch implies that a PHY listener
935 // is removed when the channel switch starts and another one is attached when the channel
936 // switch ends. In the meantime, no PHY is connected to the ChannelAccessManager. Thus,
937 // reset all backoffs (so that access timeout is also cancelled) when the channel switch
938 // starts and request channel access (if needed) when the channel switch ends.
939 cam->ResetAllBackoffs();
940 Simulator::Schedule(auxPhy->GetChannelSwitchDelay(), [=, this]() {
941 for (const auto& [acIndex, ac] : wifiAcList)
942 {
943 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
944 linkId,
945 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
946 Txop::CHECK_MEDIUM_BUSY);
947 }
948 });
949 }
950}
951
952void
953EmlsrManager::ComputeOperatingChannels()
954{
955 NS_LOG_FUNCTION(this);
956
957 m_mainPhyChannels.clear();
958 m_auxPhyChannels.clear();
959
960 auto linkIds = m_staMac->GetSetupLinkIds();
961
962 for (auto linkId : linkIds)
963 {
964 const auto& channel = m_staMac->GetWifiPhy(linkId)->GetOperatingChannel();
965 m_mainPhyChannels.emplace(linkId, channel);
966
967 auto mainPhyChWidth = channel.GetWidth();
968 auto auxPhyMaxWidth =
969 std::min(m_auxPhyMaxWidth, GetMaximumChannelWidth(m_auxPhyMaxModClass));
970 if (auxPhyMaxWidth >= mainPhyChWidth)
971 {
972 // same channel can be used by aux PHYs
973 m_auxPhyChannels.emplace(linkId, channel);
974 continue;
975 }
976 // aux PHYs will operate on a primary subchannel
977 auto freq = channel.GetPrimaryChannelCenterFrequency(auxPhyMaxWidth);
978 auto chIt = WifiPhyOperatingChannel::FindFirst(0,
979 freq,
980 auxPhyMaxWidth,
982 channel.GetPhyBand());
983 NS_ASSERT_MSG(chIt != WifiPhyOperatingChannel::m_frequencyChannels.end(),
984 "Primary" << auxPhyMaxWidth << " channel not found");
985 m_auxPhyChannels.emplace(linkId, chIt);
986 // find the P20 index for the channel used by the aux PHYs
987 auto p20Index = channel.GetPrimaryChannelIndex(20);
988 while (mainPhyChWidth > auxPhyMaxWidth)
989 {
990 mainPhyChWidth /= 2;
991 p20Index /= 2;
992 }
993 m_auxPhyChannels[linkId].SetPrimary20Index(p20Index);
994 }
995}
996
998EmlsrManager::GetChannelForMainPhy(uint8_t linkId) const
999{
1000 auto it = m_mainPhyChannels.find(linkId);
1001 NS_ASSERT_MSG(it != m_mainPhyChannels.end(),
1002 "Channel for main PHY on link ID " << +linkId << " not found");
1003 return it->second;
1004}
1005
1007EmlsrManager::GetChannelForAuxPhy(uint8_t linkId) const
1008{
1009 auto it = m_auxPhyChannels.find(linkId);
1010 NS_ASSERT_MSG(it != m_auxPhyChannels.end(),
1011 "Channel for aux PHY on link ID " << +linkId << " not found");
1012 return it->second;
1013}
1014
1015} // 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:322
bool TraceDisconnectWithoutContext(std::string name, const CallbackBase &cb)
Disconnect from a TraceSource a Callback previously connected without a context.
Definition: object-base.cc:352
A base class which provides memory management and object aggregation.
Definition: object.h:89
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:444
bool IsInitialized() const
Check if the object has been initialized.
Definition: object.cc:251
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
void UnblockTxOnLink(std::set< uint8_t > linkIds, WifiQueueBlockedReason reason)
Unblock transmissions on the given links for the given reason.
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:1406
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:932
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:878
Mac48Address GetBssid(uint8_t linkId) const
Definition: wifi-mac.cc:492
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:436
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:947
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1185
Ptr< EhtConfiguration > GetEhtConfiguration() const
Definition: wifi-mac.cc:1786
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:453
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:988
const std::set< uint8_t > & GetLinkIds() const
Definition: wifi-mac.cc:953
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:884
Ptr< WifiPhy > GetPhy() const
Time GetChannelSwitchDelay() const
Definition: wifi-phy.cc:712
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition: wifi-phy.cc:450
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:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
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:1343
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
WifiMacDropReason
The reason why an MPDU was dropped.
Definition: wifi-mac.h:80
@ STA
Definition: wifi-mac.h:68
@ 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
@ TX
The PHY layer is sending a packet.
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:706
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:189
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
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition: log.h:106
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.