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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#include "emlsr-manager.h"
10
11#include "eht-configuration.h"
13
14#include "ns3/abort.h"
15#include "ns3/assert.h"
16#include "ns3/attribute-container.h"
17#include "ns3/log.h"
18#include "ns3/mgt-action-headers.h"
19#include "ns3/wifi-mpdu.h"
20#include "ns3/wifi-net-device.h"
21#include "ns3/wifi-phy-state-helper.h"
22
23#include <iterator>
24#include <sstream>
25
26namespace ns3
27{
28
29NS_LOG_COMPONENT_DEFINE("EmlsrManager");
30
31NS_OBJECT_ENSURE_REGISTERED(EmlsrManager);
32
33TypeId
35{
36 static TypeId tid =
37 TypeId("ns3::EmlsrManager")
39 .SetGroupName("Wifi")
40 .AddAttribute("EmlsrPaddingDelay",
41 "The EMLSR Paddind Delay (not used by AP MLDs). "
42 "Possible values are 0 us, 32 us, 64 us, 128 us or 256 us.",
46 .AddAttribute("EmlsrTransitionDelay",
47 "The EMLSR Transition Delay (not used by AP MLDs). "
48 "Possible values are 0 us, 16 us, 32 us, 64 us, 128 us or 256 us.",
52 .AddAttribute(
53 "MainPhyId",
54 "The ID of the main PHY (position in the vector of PHYs held by "
55 "WifiNetDevice). This attribute cannot be set after construction.",
56 TypeId::ATTR_GET | TypeId::ATTR_CONSTRUCT, // prevent setting after construction
60 .AddAttribute("AuxPhyChannelWidth",
61 "The maximum channel width (MHz) supported by Aux PHYs. Note that the "
62 "maximum channel width is capped to the maximum channel width supported "
63 "by the configured maximum modulation class supported.",
65 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
66 UintegerValue(20),
69 .AddAttribute("AuxPhyMaxModClass",
70 "The maximum modulation class supported by Aux PHYs. Use "
71 "WIFI_MOD_CLASS_OFDM for non-HT.",
73 TypeId::ATTR_CONSTRUCT, // prevent setting after construction
77 "HR-DSSS",
79 "ERP-OFDM",
81 "OFDM",
83 "HT",
85 "VHT",
87 "HE",
89 "EHT"))
90 .AddAttribute("AuxPhyTxCapable",
91 "Whether Aux PHYs are capable of transmitting PPDUs.",
92 BooleanValue(true),
96 .AddAttribute("InDeviceInterference",
97 "Whether in-device interference is such that a PHY cannot decode "
98 "anything and cannot decrease the backoff counter when another PHY "
99 "of the same device is transmitting.",
100 BooleanValue(false),
104 .AddAttribute(
105 "EmlsrLinkSet",
106 "IDs of the links on which EMLSR mode will be enabled. An empty set "
107 "indicates to disable EMLSR.",
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
137
138void
140{
141 NS_LOG_FUNCTION(this);
142 m_staMac->TraceDisconnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
143 m_staMac->TraceDisconnectWithoutContext("DroppedMpdu",
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");
163 NS_ABORT_MSG_IF(m_staMac->GetTypeOfStation() != STA,
164 "EmlsrManager can only be installed on non-AP MLDs");
165
166 m_staMac->TraceConnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
167 m_staMac->TraceConnectWithoutContext("DroppedMpdu",
169 DoSetWifiMac(mac);
170}
171
172void
177
178void
180{
181 NS_LOG_FUNCTION(this << mainPhyId);
182 NS_ABORT_MSG_IF(IsInitialized(), "Cannot be called once this object has been initialized");
183 m_mainPhyId = mainPhyId;
184}
185
186uint8_t
188{
189 return m_mainPhyId;
190}
191
192void
194{
195 m_resetCamState = enable;
196}
197
198bool
203
204void
206{
207 m_auxPhyTxCapable = capable;
208}
209
210bool
215
216void
221
222bool
227
228const std::set<uint8_t>&
230{
231 return m_emlsrLinks;
232}
233
236{
237 return m_staMac;
238}
239
241EmlsrManager::GetEhtFem(uint8_t linkId) const
242{
243 return StaticCast<EhtFrameExchangeManager>(m_staMac->GetFrameExchangeManager(linkId));
244}
245
246std::optional<Time>
248{
249 if (const auto statusIt = m_mediumSyncDelayStatus.find(linkId);
250 statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsPending())
251 {
252 return m_mediumSyncDuration - Simulator::GetDelayLeft(statusIt->second.timer);
253 }
254 return std::nullopt;
255}
256
257void
263
264std::optional<Time>
269
270void
272{
273 NS_LOG_FUNCTION(this << duration.As(Time::US));
274 m_mediumSyncDuration = duration;
275}
276
277Time
282
283void
285{
286 NS_LOG_FUNCTION(this << threshold);
287 m_msdOfdmEdThreshold = threshold;
288}
289
290int8_t
295
296void
297EmlsrManager::SetMediumSyncMaxNTxops(std::optional<uint8_t> nTxops)
298{
299 NS_LOG_FUNCTION(this << nTxops.has_value());
300 m_msdMaxNTxops = nTxops;
301}
302
303std::optional<uint8_t>
308
309void
310EmlsrManager::SetEmlsrLinks(const std::set<uint8_t>& linkIds)
311{
312 std::stringstream ss;
313 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
314 {
315 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
316 }
317 NS_LOG_FUNCTION(this << ss.str());
318 NS_ABORT_MSG_IF(linkIds.size() == 1, "Cannot enable EMLSR mode on a single link");
319
320 if (linkIds != m_emlsrLinks)
321 {
322 m_nextEmlsrLinks = linkIds;
323 }
324
325 if (GetStaMac() && GetStaMac()->IsAssociated() && GetTransitionTimeout() && m_nextEmlsrLinks)
326 {
327 // Request to enable EMLSR mode on the given links, provided that they have been setup
328 SendEmlOmn();
329 }
330}
331
332void
334{
335 NS_LOG_FUNCTION(this << *mpdu << linkId);
336
337 const auto& hdr = mpdu->GetHeader();
338
339 DoNotifyMgtFrameReceived(mpdu, linkId);
340
341 if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
342 {
343 // we just completed ML setup with an AP MLD that supports EMLSR
345
346 if (m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
347 {
348 // a non-empty set of EMLSR links have been configured, hence enable EMLSR mode
349 // on those links
350 SendEmlOmn();
351 }
352 }
353
354 if (hdr.IsAction() && hdr.GetAddr2() == m_staMac->GetBssid(linkId))
355 {
356 // this is an action frame sent by an AP of the AP MLD we are associated with
357 auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
358 if (category == WifiActionHeader::PROTECTED_EHT &&
359 action.protectedEhtAction ==
361 {
363 {
364 // no need to wait until the expiration of the transition timeout
367 }
368 }
369 }
370}
371
372void
374{
375 NS_LOG_FUNCTION(this << linkId);
376
377 NS_ASSERT(m_staMac->IsEmlsrLink(linkId));
378
379 // block transmissions and suspend medium access on all other EMLSR links
380 for (auto id : m_staMac->GetLinkIds())
381 {
382 if (id != linkId && m_staMac->IsEmlsrLink(id))
383 {
385 }
386 }
387
388 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
389 auto auxPhy = m_staMac->GetWifiPhy(linkId);
390
391 if (m_staMac->GetWifiPhy(linkId) != mainPhy)
392 {
393 // an aux PHY received the ICF
394 SwitchMainPhy(linkId,
395 true, // channel switch should occur instantaneously
398
399 // aux PHY received the ICF but main PHY will send the response
400 auto uid = auxPhy->GetPreviouslyRxPpduUid();
401 mainPhy->SetPreviouslyRxPpduUid(uid);
402 }
403
404 DoNotifyIcfReceived(linkId);
405}
406
407std::pair<bool, Time>
409{
410 auto phy = m_staMac->GetWifiPhy(linkId);
411 NS_ASSERT_MSG(phy, "No PHY operating on link " << +linkId);
412
413 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
414
415 // check possible reasons to give up the TXOP that apply to both main PHY and aux PHYs
416 if (const auto [startTxop, delay] = DoGetDelayUntilAccessRequest(linkId); !startTxop)
417 {
418 return {false, delay};
419 }
420
421 if (phy == mainPhy)
422 {
423 // no more constraints to check if medium was gained by main PHY
424 return {true, Time{0}};
425 }
426
427 // an aux PHY is operating on the given link; call the appropriate method depending on
428 // whether the aux PHY is TX capable or not
430 {
432 // if the aux PHY is not TX capable, we don't have to request channel access: if the main
433 // PHY switches link, the UL TXOP will be started; if the main PHY does not switch, it is
434 // because it is going to start an UL TXOP on another link and this link will be restarted
435 // at the end of that UL TXOP when this link will be unblocked
436 NS_LOG_DEBUG("Aux PHY is not capable of transmitting a PPDU");
437 return {false, Time{0}};
438 }
439
441}
442
443void
445{
446 NS_LOG_FUNCTION(this << linkId);
447
448 if (!m_staMac->IsEmlsrLink(linkId))
449 {
450 NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
451 return;
452 }
453
454 // block transmissions and suspend medium access on all other EMLSR links
455 for (auto id : m_staMac->GetLinkIds())
456 {
457 if (id != linkId && m_staMac->IsEmlsrLink(id))
458 {
460 }
461 }
462
463 DoNotifyUlTxopStart(linkId);
464}
465
466void
467EmlsrManager::NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted, bool ongoingDlTxop)
468{
469 NS_LOG_FUNCTION(this << linkId << ulTxopNotStarted << ongoingDlTxop);
470
471 if (!m_staMac->IsEmlsrLink(linkId))
472 {
473 NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
474 return;
475 }
476
477 // If the main PHY has been scheduled to switch to this link, cancel the channel switch.
478 // This happens, e.g., when an aux PHY sent an RTS to start an UL TXOP but it did not
479 // receive a CTS response.
480 if (auto it = m_ulMainPhySwitch.find(linkId); it != m_ulMainPhySwitch.end())
481 {
482 if (it->second.IsPending())
483 {
484 NS_LOG_DEBUG("Cancelling main PHY channel switch event on link " << +linkId);
485 it->second.Cancel();
486 }
487 m_ulMainPhySwitch.erase(it);
488 }
489
490 // Unblock the other EMLSR links and start the MediumSyncDelay timer, provided that the TXOP
491 // included the transmission of at least a frame and there is no ongoing DL TXOP on this link.
492 // Indeed, the UL TXOP may have ended because the transmission of a frame failed and the
493 // corresponding TX timeout (leading to this call) may have occurred after the reception on
494 // this link of an ICF starting a DL TXOP. If the EMLSR Manager unblocked the other EMLSR
495 // links, another TXOP could be started on another EMLSR link (possibly leading to a crash)
496 // while the DL TXOP on this link is ongoing.
497 if (ongoingDlTxop)
498 {
499 NS_LOG_DEBUG("DL TXOP ongoing");
500 return;
501 }
502 if (ulTxopNotStarted)
503 {
504 NS_LOG_DEBUG("TXOP did not even start");
505 return;
506 }
507
508 DoNotifyTxopEnd(linkId);
509
510 Simulator::ScheduleNow([=, this]() {
511 // unblock transmissions and resume medium access on other EMLSR links
512 std::set<uint8_t> linkIds;
513 for (auto id : m_staMac->GetLinkIds())
514 {
515 if ((id != linkId) && m_staMac->IsEmlsrLink(id))
516 {
517 linkIds.insert(id);
518 }
519 }
521
523 });
524}
525
526void
528{
529 NS_LOG_FUNCTION(this << phy << linkId);
530
531 // if a MediumSyncDelay timer is running for the link on which the main PHY is going to
532 // operate, set the CCA ED threshold to the MediumSyncDelay OFDM ED threshold
533 if (auto statusIt = m_mediumSyncDelayStatus.find(linkId);
534 statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsPending())
535 {
536 NS_LOG_DEBUG("Setting CCA ED threshold of PHY " << phy << " to " << +m_msdOfdmEdThreshold
537 << " on link " << +linkId);
538
539 // store the current CCA ED threshold in the m_prevCcaEdThreshold map, if not present
540 m_prevCcaEdThreshold.try_emplace(phy, phy->GetCcaEdThreshold());
541
542 phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
543 }
544 // otherwise, restore the previous value for the CCA ED threshold (if any)
545 else if (auto threshIt = m_prevCcaEdThreshold.find(phy);
546 threshIt != m_prevCcaEdThreshold.cend())
547 {
548 NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
549 << " on link " << +linkId);
550 phy->SetCcaEdThreshold(threshIt->second);
551 m_prevCcaEdThreshold.erase(threshIt);
552 }
553}
554
555void
557 bool noSwitchDelay,
558 bool resetBackoff,
559 bool requestAccess)
560{
561 NS_LOG_FUNCTION(this << linkId << noSwitchDelay << resetBackoff << requestAccess);
562
563 auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
564
565 NS_ASSERT_MSG(mainPhy != m_staMac->GetWifiPhy(linkId),
566 "Main PHY is already operating on link " << +linkId);
567
568 // find the link on which the main PHY is operating
569 auto currMainPhyLinkId = m_staMac->GetLinkForPhy(mainPhy);
570
571 NS_ASSERT_MSG(currMainPhyLinkId.has_value() || mainPhy->IsStateSwitching(),
572 "If the main PHY is not operating on a link, it must be switching");
573
574 const auto newMainPhyChannel = GetChannelForMainPhy(linkId);
575
576 NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel
577 << " to operate on link " << +linkId);
578
579 // if the main PHY is operating on a link, notify the channel access manager of the upcoming
580 // channel switch
581 if (currMainPhyLinkId.has_value())
582 {
583 m_staMac->GetChannelAccessManager(*currMainPhyLinkId)
584 ->NotifySwitchingEmlsrLink(mainPhy, newMainPhyChannel, linkId);
585 }
586
587 // this assert also ensures that the actual channel switch is not delayed
588 NS_ASSERT_MSG(!mainPhy->GetState()->IsStateTx(),
589 "We should not ask the main PHY to switch channel while transmitting");
590
591 // request the main PHY to switch channel
592 const auto delay = mainPhy->GetChannelSwitchDelay();
593 const auto pifs = mainPhy->GetSifs() + mainPhy->GetSlot();
594 NS_ASSERT_MSG(noSwitchDelay || delay <= std::max(m_lastAdvTransitionDelay, pifs),
595 "Channel switch delay ("
596 << delay.As(Time::US)
597 << ") should be shorter than the maximum between the Transition delay ("
598 << m_lastAdvTransitionDelay.As(Time::US) << ") and a PIFS ("
599 << pifs.As(Time::US) << ")");
600 if (noSwitchDelay)
601 {
602 mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
603 }
604 mainPhy->SetOperatingChannel(newMainPhyChannel);
605 // restore previous channel switch delay
606 if (noSwitchDelay)
607 {
608 mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(delay));
609 }
610 // re-enable short time slot, if needed
611 if (m_staMac->GetWifiRemoteStationManager(linkId)->GetShortSlotTimeEnabled())
612 {
613 mainPhy->SetSlot(MicroSeconds(9));
614 }
615
616 const auto timeToSwitchEnd = noSwitchDelay ? Seconds(0) : delay;
617
618 // if the main PHY is not operating on any link (because it was switching), it is not connected
619 // to a channel access manager, hence we must notify the MAC of the new link switch
620 if (!currMainPhyLinkId.has_value())
621 {
622 m_staMac->NotifySwitchingEmlsrLink(mainPhy, linkId, timeToSwitchEnd);
623 }
624
625 if (resetBackoff && currMainPhyLinkId.has_value())
626 {
627 // reset the backoffs on the link left by the main PHY
628 m_staMac->GetChannelAccessManager(*currMainPhyLinkId)->ResetAllBackoffs();
629 }
630
631 if (requestAccess)
632 {
633 // schedule channel access request on the new link when switch is completed
634 Simulator::Schedule(timeToSwitchEnd, [=, this]() {
635 for (const auto& [acIndex, ac] : wifiAcList)
636 {
637 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
638 linkId,
641 }
642 });
643 }
644
645 SetCcaEdThresholdOnLinkSwitch(mainPhy, linkId);
646 NotifyMainPhySwitch(currMainPhyLinkId, linkId, timeToSwitchEnd);
647}
648
649void
650EmlsrManager::SwitchAuxPhy(Ptr<WifiPhy> auxPhy, uint8_t currLinkId, uint8_t nextLinkId)
651{
652 NS_LOG_FUNCTION(this << auxPhy << currLinkId << nextLinkId);
653
654 auto newAuxPhyChannel = GetChannelForAuxPhy(nextLinkId);
655
656 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << newAuxPhyChannel
657 << " to operate on link " << +nextLinkId);
658
659 GetStaMac()
660 ->GetChannelAccessManager(currLinkId)
661 ->NotifySwitchingEmlsrLink(auxPhy, newAuxPhyChannel, nextLinkId);
662
663 auxPhy->SetOperatingChannel(newAuxPhyChannel);
664 // re-enable short time slot, if needed
665 if (m_staMac->GetWifiRemoteStationManager(nextLinkId)->GetShortSlotTimeEnabled())
666 {
667 auxPhy->SetSlot(MicroSeconds(9));
668 }
669
670 // schedule channel access request on the new link when switch is completed
671 Simulator::Schedule(auxPhy->GetChannelSwitchDelay(), [=, this]() {
672 for (const auto& [acIndex, ac] : wifiAcList)
673 {
674 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
675 nextLinkId,
676 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
677 Txop::CHECK_MEDIUM_BUSY);
678 }
679 });
680
681 SetCcaEdThresholdOnLinkSwitch(auxPhy, nextLinkId);
682}
683
684void
685EmlsrManager::StartMediumSyncDelayTimer(uint8_t linkId)
686{
687 NS_LOG_FUNCTION(this << linkId);
688
689 // iterate over all the other EMLSR links
690 for (auto id : m_staMac->GetLinkIds())
691 {
692 if (id != linkId && m_staMac->IsEmlsrLink(id))
693 {
694 const auto [it, inserted] = m_mediumSyncDelayStatus.try_emplace(id);
695
696 // reset the max number of TXOP attempts
697 it->second.msdNTxopsLeft = m_msdMaxNTxops;
698
699 // there are cases in which no PHY is operating on a link; e.g., the main PHY starts
700 // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS
701 // is not received and the UL TXOP ends before the main PHY channel switch is
702 // completed. The MSD timer is started on the link left "uncovered" by the main PHY
703 if (auto phy = m_staMac->GetWifiPhy(id); phy && !it->second.timer.IsPending())
704 {
705 NS_LOG_DEBUG("Setting CCA ED threshold on link "
706 << +id << " to " << +m_msdOfdmEdThreshold << " PHY " << phy);
707 m_prevCcaEdThreshold[phy] = phy->GetCcaEdThreshold();
708 phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
709 }
710
711 // (re)start the timer
712 it->second.timer.Cancel();
713 it->second.timer = Simulator::Schedule(m_mediumSyncDuration,
714 &EmlsrManager::MediumSyncDelayTimerExpired,
715 this,
716 id);
717 }
718 }
719}
720
721void
722EmlsrManager::CancelMediumSyncDelayTimer(uint8_t linkId)
723{
724 NS_LOG_FUNCTION(this << linkId);
725
726 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
727
728 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
729
730 timerIt->second.timer.Cancel();
731 MediumSyncDelayTimerExpired(linkId);
732}
733
734void
735EmlsrManager::MediumSyncDelayTimerExpired(uint8_t linkId)
736{
737 NS_LOG_FUNCTION(this << linkId);
738
739 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
740
741 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && !timerIt->second.timer.IsPending());
742
743 // reset the MSD OFDM ED threshold
744 auto phy = m_staMac->GetWifiPhy(linkId);
745
746 if (!phy)
747 {
748 // no PHY is operating on this link. This may happen when a MediumSyncDelay timer expires
749 // on the link left "uncovered" by the main PHY that is operating on another link (and the
750 // aux PHY of that link did not switch). In this case, do nothing, since the CCA ED
751 // threshold on the main PHY will be restored once the main PHY switches back to its link
752 return;
753 }
754
755 auto threshIt = m_prevCcaEdThreshold.find(phy);
756 NS_ASSERT_MSG(threshIt != m_prevCcaEdThreshold.cend(),
757 "No value to restore for CCA ED threshold on PHY " << phy);
758 NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
759 << " on link " << +linkId);
760 phy->SetCcaEdThreshold(threshIt->second);
761 m_prevCcaEdThreshold.erase(threshIt);
762}
763
764void
765EmlsrManager::DecrementMediumSyncDelayNTxops(uint8_t linkId)
766{
767 NS_LOG_FUNCTION(this << linkId);
768
769 const auto timerIt = m_mediumSyncDelayStatus.find(linkId);
770
771 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
772 NS_ASSERT(timerIt->second.msdNTxopsLeft != 0);
773
774 if (timerIt->second.msdNTxopsLeft)
775 {
776 --timerIt->second.msdNTxopsLeft.value();
777 }
778}
779
780void
781EmlsrManager::ResetMediumSyncDelayNTxops(uint8_t linkId)
782{
783 NS_LOG_FUNCTION(this << linkId);
784
785 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
786
787 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
788 timerIt->second.msdNTxopsLeft.reset();
789}
790
791bool
792EmlsrManager::MediumSyncDelayNTxopsExceeded(uint8_t linkId)
793{
794 NS_LOG_FUNCTION(this << linkId);
795
796 auto timerIt = m_mediumSyncDelayStatus.find(linkId);
797
798 NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
799 return timerIt->second.msdNTxopsLeft == 0;
800}
801
803EmlsrManager::GetEmlOmn()
804{
805 MgtEmlOmn frame;
806
807 // Add the EMLSR Parameter Update field if needed
808 if (m_lastAdvPaddingDelay != m_emlsrPaddingDelay ||
809 m_lastAdvTransitionDelay != m_emlsrTransitionDelay)
810 {
811 m_lastAdvPaddingDelay = m_emlsrPaddingDelay;
812 m_lastAdvTransitionDelay = m_emlsrTransitionDelay;
815 frame.m_emlsrParamUpdate->paddingDelay =
816 CommonInfoBasicMle::EncodeEmlsrPaddingDelay(m_lastAdvPaddingDelay);
817 frame.m_emlsrParamUpdate->transitionDelay =
818 CommonInfoBasicMle::EncodeEmlsrTransitionDelay(m_lastAdvTransitionDelay);
819 }
820
821 // We must verify that the links included in the given EMLSR link set (if any) have been setup.
822 auto setupLinkIds = m_staMac->GetSetupLinkIds();
823
824 for (auto emlsrLinkIt = m_nextEmlsrLinks->begin(); emlsrLinkIt != m_nextEmlsrLinks->end();)
825 {
826 if (auto setupLinkIt = setupLinkIds.find(*emlsrLinkIt); setupLinkIt != setupLinkIds.cend())
827 {
828 setupLinkIds.erase(setupLinkIt);
829 frame.SetLinkIdInBitmap(*emlsrLinkIt);
830 emlsrLinkIt++;
831 }
832 else
833 {
834 NS_LOG_DEBUG("Link ID " << +(*emlsrLinkIt) << " has not been setup");
835 emlsrLinkIt = m_nextEmlsrLinks->erase(emlsrLinkIt);
836 }
837 }
838
839 // EMLSR Mode is enabled if and only if the set of EMLSR links is not empty
840 frame.m_emlControl.emlsrMode = m_nextEmlsrLinks->empty() ? 0 : 1;
841
842 return frame;
843}
844
845void
846EmlsrManager::SendEmlOmn()
847{
848 NS_LOG_FUNCTION(this);
849
850 NS_ABORT_MSG_IF(!m_emlsrTransitionTimeout,
851 "AP did not advertise a Transition Timeout, cannot send EML notification");
852 NS_ASSERT_MSG(m_nextEmlsrLinks, "Need to set EMLSR links before calling this method");
853
854 // TODO if this is a single radio non-AP MLD and not all setup links are in the EMLSR link
855 // set, we have to put setup links that are not included in the given EMLSR link set (i.e.,
856 // those remaining in setupLinkIds, if m_nextEmlsrLinks is not empty) in the sleep mode:
857 // For the EMLSR mode enabled in a single radio non-AP MLD, the STA(s) affiliated with
858 // the non-AP MLD that operates on the enabled link(s) that corresponds to the bit
859 // position(s) of the EMLSR Link Bitmap subfield set to 0 shall be in doze state if a
860 // non-AP STA affiliated with the non-AP MLD that operates on one of the EMLSR links is
861 // in awake state. (Sec. 35.3.17 of 802.11be D3.0)
862
863 auto frame = GetEmlOmn();
864 auto linkId = GetLinkToSendEmlOmn();
865 GetEhtFem(linkId)->SendEmlOmn(m_staMac->GetBssid(linkId), frame);
866}
867
868void
869EmlsrManager::TxOk(Ptr<const WifiMpdu> mpdu)
870{
871 NS_LOG_FUNCTION(this << *mpdu);
872
873 const auto& hdr = mpdu->GetHeader();
874
875 if (hdr.IsAssocReq())
876 {
877 // store padding delay and transition delay advertised in AssocReq
878 MgtAssocRequestHeader assocReq;
879 mpdu->GetPacket()->PeekHeader(assocReq);
880 auto& mle = assocReq.Get<MultiLinkElement>();
881 NS_ASSERT_MSG(mle, "AssocReq should contain a Multi-Link Element");
882 m_lastAdvPaddingDelay = mle->GetEmlsrPaddingDelay();
883 m_lastAdvTransitionDelay = mle->GetEmlsrTransitionDelay();
884 }
885
886 if (hdr.IsMgt() && hdr.IsAction())
887 {
888 if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
889 category == WifiActionHeader::PROTECTED_EHT &&
890 action.protectedEhtAction ==
891 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
892 {
893 // the EML Operating Mode Notification frame that we sent has been acknowledged.
894 // Start the transition timeout to wait until the request can be made effective
895 NS_ASSERT_MSG(m_emlsrTransitionTimeout, "No transition timeout received from AP");
896 m_transitionTimeoutEvent = Simulator::Schedule(*m_emlsrTransitionTimeout,
897 &EmlsrManager::ChangeEmlsrMode,
898 this);
899 }
900 }
901}
902
903void
904EmlsrManager::TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu)
905{
906 NS_LOG_FUNCTION(this << reason << *mpdu);
907
908 const auto& hdr = mpdu->GetHeader();
909
910 if (hdr.IsMgt() && hdr.IsAction())
911 {
912 auto pkt = mpdu->GetPacket()->Copy();
913 if (auto [category, action] = WifiActionHeader::Remove(pkt);
914 category == WifiActionHeader::PROTECTED_EHT &&
915 action.protectedEhtAction ==
916 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
917 {
918 // the EML Operating Mode Notification frame has been dropped. Ask the subclass
919 // whether the frame needs to be resent
920 auto linkId = ResendNotification(mpdu);
921 if (linkId)
922 {
923 MgtEmlOmn frame;
924 pkt->RemoveHeader(frame);
925 GetEhtFem(*linkId)->SendEmlOmn(m_staMac->GetBssid(*linkId), frame);
926 }
927 else
928 {
929 m_nextEmlsrLinks.reset();
930 }
931 }
932 }
933}
934
935void
936EmlsrManager::ChangeEmlsrMode()
937{
938 NS_LOG_FUNCTION(this);
939
940 // After the successful transmission of the EML Operating Mode Notification frame by the
941 // non-AP STA affiliated with the non-AP MLD, the non-AP MLD shall operate in the EMLSR mode
942 // and the other non-AP STAs operating on the corresponding EMLSR links shall transition to
943 // active mode after the transition delay indicated in the Transition Timeout subfield in the
944 // EML Capabilities subfield of the Basic Multi-Link element or immediately after receiving an
945 // EML Operating Mode Notification frame from one of the APs operating on the EMLSR links and
946 // affiliated with the AP MLD. (Sec. 35.3.17 of 802.11be D3.0)
947 NS_ASSERT_MSG(m_nextEmlsrLinks, "No set of EMLSR links stored");
948 m_emlsrLinks.swap(*m_nextEmlsrLinks);
949 m_nextEmlsrLinks.reset();
950
951 // Make other non-AP STAs operating on the corresponding EMLSR links transition to
952 // active mode or passive mode (depending on whether EMLSR mode has been enabled or disabled)
953 m_staMac->NotifyEmlsrModeChanged(m_emlsrLinks);
954 // Enforce the limit on the max channel width supported by aux PHYs
955 ApplyMaxChannelWidthAndModClassOnAuxPhys();
956
957 NotifyEmlsrModeChanged();
958}
959
960void
961EmlsrManager::ApplyMaxChannelWidthAndModClassOnAuxPhys()
962{
963 NS_LOG_FUNCTION(this);
964 auto currMainPhyLinkId = m_staMac->GetLinkForPhy(m_mainPhyId);
965 NS_ASSERT(currMainPhyLinkId);
966
967 for (const auto linkId : m_staMac->GetLinkIds())
968 {
969 auto auxPhy = m_staMac->GetWifiPhy(linkId);
970 auto channel = GetChannelForAuxPhy(linkId);
971
972 if (linkId == currMainPhyLinkId || !m_staMac->IsEmlsrLink(linkId) ||
973 auxPhy->GetOperatingChannel() == channel)
974 {
975 continue;
976 }
977
978 auxPhy->SetMaxModulationClassSupported(m_auxPhyMaxModClass);
979
980 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") is about to switch to " << channel
981 << " to operate on link " << +linkId);
982 // We cannot simply set the new channel, because otherwise the MAC will disable
983 // the setup link. We need to inform the MAC (via the Channel Access Manager) that
984 // this channel switch must not have such a consequence. We already have a method
985 // for doing so, i.e., inform the MAC that the PHY is switching channel to operate
986 // on the "same" link.
987 auto cam = m_staMac->GetChannelAccessManager(linkId);
988 cam->NotifySwitchingEmlsrLink(auxPhy, channel, linkId);
989
990 auxPhy->SetOperatingChannel(channel);
991
992 // the way the ChannelAccessManager handles EMLSR link switch implies that a PHY listener
993 // is removed when the channel switch starts and another one is attached when the channel
994 // switch ends. In the meantime, no PHY is connected to the ChannelAccessManager. Thus,
995 // reset all backoffs (so that access timeout is also cancelled) when the channel switch
996 // starts and request channel access (if needed) when the channel switch ends.
997 cam->ResetAllBackoffs();
998 Simulator::Schedule(auxPhy->GetChannelSwitchDelay(), [=, this]() {
999 for (const auto& [acIndex, ac] : wifiAcList)
1000 {
1001 m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
1002 linkId,
1003 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
1004 Txop::CHECK_MEDIUM_BUSY);
1005 }
1006 });
1007 }
1008}
1009
1010void
1011EmlsrManager::ComputeOperatingChannels()
1012{
1013 NS_LOG_FUNCTION(this);
1014
1015 m_mainPhyChannels.clear();
1016 m_auxPhyChannels.clear();
1017
1018 auto linkIds = m_staMac->GetSetupLinkIds();
1019
1020 for (auto linkId : linkIds)
1021 {
1022 const auto& channel = m_staMac->GetWifiPhy(linkId)->GetOperatingChannel();
1023 m_mainPhyChannels.emplace(linkId, channel);
1024
1025 auto mainPhyChWidth = channel.GetWidth();
1026 auto auxPhyMaxWidth =
1027 std::min(m_auxPhyMaxWidth, GetMaximumChannelWidth(m_auxPhyMaxModClass));
1028 if (auxPhyMaxWidth >= mainPhyChWidth)
1029 {
1030 // same channel can be used by aux PHYs
1031 m_auxPhyChannels.emplace(linkId, channel);
1032 continue;
1033 }
1034 // aux PHYs will operate on a primary subchannel
1035 auto freq = channel.GetPrimaryChannelCenterFrequency(auxPhyMaxWidth);
1036 auto chIt = WifiPhyOperatingChannel::FindFirst(0,
1037 freq,
1038 auxPhyMaxWidth,
1040 channel.GetPhyBand());
1041 NS_ASSERT_MSG(chIt != WifiPhyOperatingChannel::m_frequencyChannels.end(),
1042 "Primary" << auxPhyMaxWidth << " channel not found");
1043 m_auxPhyChannels.emplace(linkId, chIt);
1044 // find the P20 index for the channel used by the aux PHYs
1045 auto p20Index = channel.GetPrimaryChannelIndex(20);
1046 while (mainPhyChWidth > auxPhyMaxWidth)
1047 {
1048 mainPhyChWidth /= 2;
1049 p20Index /= 2;
1050 }
1051 m_auxPhyChannels[linkId].SetPrimary20Index(p20Index);
1052 }
1053}
1054
1056EmlsrManager::GetChannelForMainPhy(uint8_t linkId) const
1057{
1058 auto it = m_mainPhyChannels.find(linkId);
1059 NS_ASSERT_MSG(it != m_mainPhyChannels.end(),
1060 "Channel for main PHY on link ID " << +linkId << " not found");
1061 return it->second;
1062}
1063
1065EmlsrManager::GetChannelForAuxPhy(uint8_t linkId) const
1066{
1067 auto it = m_auxPhyChannels.find(linkId);
1068 NS_ASSERT_MSG(it != m_auxPhyChannels.end(),
1069 "Channel for aux PHY on link ID " << +linkId << " not found");
1070 return it->second;
1071}
1072
1073} // namespace ns3
A container for one type of attribute.
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.
virtual void NotifyMainPhySwitch(std::optional< uint8_t > currLinkId, uint8_t nextLinkId, Time duration)=0
Notify subclass that the main PHY is switching channel to operate on another link.
bool m_auxPhyTxCapable
whether Aux PHYs are capable of transmitting PPDUs
std::optional< Time > GetTransitionTimeout() const
std::pair< bool, Time > GetDelayUntilAccessRequest(uint8_t linkId, AcIndex aci)
Notify that an UL TXOP is gained on the given link by the given AC.
virtual std::pair< bool, Time > DoGetDelayUntilAccessRequest(uint8_t linkId)=0
Subclasses have to provide an implementation for this method, that is called by the base class when t...
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 NotifyUlTxopStart(uint8_t linkId)
Notify the start of an UL TXOP on the given link.
void TxOk(Ptr< const WifiMpdu > mpdu)
Notify the acknowledgment of the given MPDU.
void NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted=false, bool ongoingDlTxop=false)
Notify the end of a TXOP on the given link.
std::map< uint8_t, EventId > m_ulMainPhySwitch
link ID-indexed map of timers started when an aux PHY gains an UL TXOP and schedules a channel switch...
bool m_inDeviceInterference
whether in-device interference is such that a PHY cannot decode anything and cannot decrease the back...
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 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)
virtual std::pair< bool, Time > GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId)=0
Subclasses have to provide an implementation for this method, that is called by the base class when t...
virtual void SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex aci)=0
Subclasses have to provide an implementation for this method, that is called by the base class when t...
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.
bool GetInDeviceInterference() const
MHz_u m_auxPhyMaxWidth
max channel width supported by aux PHYs
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...
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.
void SwitchAuxPhy(Ptr< WifiPhy > auxPhy, uint8_t currLinkId, uint8_t nextLinkId)
Switch channel on the Aux PHY operating on the given current link so that it operates on the given ne...
std::map< Ptr< WifiPhy >, dBm_u > m_prevCcaEdThreshold
the CCA sensitivity threshold to restore once the MediumSyncDelay timer expires or the PHY moves to a...
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.
virtual void DoSetWifiMac(Ptr< StaWifiMac > mac)
Allow subclasses to take actions when the MAC is set.
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 SetCcaEdThresholdOnLinkSwitch(Ptr< WifiPhy > phy, uint8_t linkId)
Set the CCA ED threshold (if needed) on the given PHY that is switching channel to operate on the giv...
void SetMainPhyId(uint8_t mainPhyId)
Set the ID of main PHY (position in the vector of PHYs held by WifiNetDevice).
const WifiPhyOperatingChannel & GetChannelForMainPhy(uint8_t linkId) const
~EmlsrManager() override
void SetMediumSyncDuration(Time duration)
Set the duration of the MediumSyncDelay timer.
static constexpr bool RESET_BACKOFF
reset backoff on main PHY switch
Time m_lastAdvTransitionDelay
last advertised transition delay
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.
virtual void DoNotifyIcfReceived(uint8_t linkId)=0
Notify the subclass of the reception of an initial Control frame on the given link.
void SetInDeviceInterference(bool enable)
Set the member variable indicating whether in-device interference is such that a PHY cannot decode an...
const WifiPhyOperatingChannel & GetChannelForAuxPhy(uint8_t linkId) const
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:52
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
EventImpl * PeekEventImpl() const
Definition event-id.cc:78
void Invoke()
Called by the simulation engine to notify the event that it is time to execute.
Definition event-impl.cc:36
Implement the header for management frames of type association request.
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.
A base class which provides memory management and object aggregation.
Definition object.h:78
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
bool IsInitialized() const
Check if the object has been initialized.
Definition object.cc:240
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ US
microsecond
Definition nstime.h:107
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition txop.h:390
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
Definition txop.h:392
a unique identifier for an interface.
Definition type-id.h:48
@ ATTR_GET
The attribute can be read.
Definition type-id.h:53
@ ATTR_CONSTRUCT
The attribute can be written at construction-time.
Definition type-id.h:55
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
static std::pair< CategoryValue, ActionValue > Peek(Ptr< const Packet > pkt)
Peek an Action header from the given packet.
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:55
#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:75
Ptr< AttributeChecker > MakeAttributeContainerChecker()
Make uninitialized AttributeContainerChecker using explicit types.
Ptr< const AttributeAccessor > MakeAttributeContainerAccessor(T1 a1)
Make AttributeContainerAccessor using explicit types.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:35
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
WifiMacDropReason
The reason why an MPDU was dropped.
Definition wifi-mac.h:70
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
@ STA
Definition wifi-mac.h:58
@ 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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
static constexpr uint8_t DEFAULT_MSD_MAX_N_TXOPS
default MediumSyncDelay max number of TXOP attempts
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1396
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:684
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
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:179
MHz_u GetMaximumChannelWidth(WifiModulationClass modulation)
Get the maximum channel width allowed for the given modulation class.
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:115
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:95
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
static constexpr uint16_t DEFAULT_MSD_DURATION_USEC
default MediumSyncDelay timer duration (max PPDU TX time rounded to a multiple of 32 us)
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition enum.h:221
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
ns3::Time timeout
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
EMLSR Parameter Update field.