A Discrete-Event Network Simulator
API
eht-frame-exchange-manager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022 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 
21 
22 #include "eht-phy.h"
23 #include "emlsr-manager.h"
24 
25 #include "ns3/abort.h"
26 #include "ns3/ap-wifi-mac.h"
27 #include "ns3/log.h"
28 #include "ns3/mgt-action-headers.h"
29 #include "ns3/sta-wifi-mac.h"
30 #include "ns3/wifi-mac-queue.h"
31 #include "ns3/wifi-net-device.h"
32 
33 #undef NS_LOG_APPEND_CONTEXT
34 #define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
35 
36 namespace ns3
37 {
38 
41 static constexpr uint8_t RX_PHY_START_DELAY_USEC = 20;
42 
57 static constexpr uint8_t WAIT_FOR_RXSTART_DELAY_USEC = 52;
58 
59 NS_LOG_COMPONENT_DEFINE("EhtFrameExchangeManager");
60 
62 
63 TypeId
65 {
66  static TypeId tid = TypeId("ns3::EhtFrameExchangeManager")
68  .AddConstructor<EhtFrameExchangeManager>()
69  .SetGroupName("Wifi");
70  return tid;
71 }
72 
74 {
75  NS_LOG_FUNCTION(this);
76 }
77 
79 {
81 }
82 
83 void
85 {
86  NS_LOG_FUNCTION(this);
89 }
90 
91 void
93 {
94  NS_LOG_FUNCTION(this << txVector << psduDuration.As(Time::MS));
95 
96  HeFrameExchangeManager::RxStartIndication(txVector, psduDuration);
98 }
99 
100 void
102 {
103  if (auto protectionManager = GetProtectionManager())
104  {
105  protectionManager->SetLinkId(linkId);
106  }
107  if (auto ackManager = GetAckManager())
108  {
109  ackManager->SetLinkId(linkId);
110  }
111  m_msduAggregator->SetLinkId(linkId);
112  m_mpduAggregator->SetLinkId(linkId);
114 }
115 
118 {
119  NS_LOG_FUNCTION(this << *mpdu);
120 
121  // alias needs only be created for non-broadcast QoS data frames exchanged between two MLDs
122  if (!mpdu->GetHeader().IsQosData() || m_mac->GetNLinks() == 1 ||
123  mpdu->GetHeader().GetAddr1().IsGroup() ||
124  !GetWifiRemoteStationManager()->GetMldAddress(mpdu->GetHeader().GetAddr1()))
125  {
127  }
128 
129  mpdu = mpdu->CreateAlias(m_linkId);
130  auto& hdr = mpdu->GetHeader();
131  hdr.SetAddr2(GetAddress());
132  auto address = GetWifiRemoteStationManager()->GetAffiliatedStaAddress(hdr.GetAddr1());
134  hdr.SetAddr1(*address);
135  /*
136  * Set Address3 according to Table 9-30 of 802.11-2020 and Section 35.3.3 of
137  * 802.11be D2.0 ["the value of the Address 3 field and the Address 4 field (if present)
138  * in the MAC header of a data frame shall be set based on Table 9-30 (Address field
139  * contents) and the settings of the To DS and From DS bits, where the BSSID is the
140  * MAC address of the AP affiliated with the AP MLD corresponding to that link"].
141  */
142  if (hdr.IsQosAmsdu())
143  {
144  if (hdr.IsToDs() && !hdr.IsFromDs())
145  {
146  // from STA to AP: BSSID is in Address1
147  hdr.SetAddr3(hdr.GetAddr1());
148  }
149  else if (!hdr.IsToDs() && hdr.IsFromDs())
150  {
151  // from AP to STA: BSSID is in Address2
152  hdr.SetAddr3(hdr.GetAddr2());
153  }
154  }
155 
156  return mpdu;
157 }
158 
159 bool
161 {
163  {
164  return false;
165  }
166  auto apAddress = GetWifiRemoteStationManager()->GetMldAddress(m_bssid);
167  NS_ASSERT_MSG(apAddress, "MLD address not found for BSSID " << m_bssid);
168  // when EMLSR links are blocked, all TIDs are blocked (we test TID 0 here)
169  WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *apAddress, 0);
170  auto mask = m_staMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, m_linkId);
171  NS_ASSERT_MSG(mask, "No mask for AP " << *apAddress << " on link " << m_linkId);
172  return mask->test(static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK));
173 }
174 
175 bool
177 {
178  NS_LOG_FUNCTION(this << edca << allowedWidth);
179 
180  std::optional<Time> timeToCtsEnd;
181 
183  {
184  // Cannot start a transmission on a link blocked because another EMLSR link is being used
185  if (UsingOtherEmlsrLink())
186  {
187  NS_LOG_DEBUG("StartTransmission called while another EMLSR link is being used");
188  NotifyChannelReleased(edca);
189  return false;
190  }
191 
192  auto emlsrManager = m_staMac->GetEmlsrManager();
193 
194  if (auto elapsed = emlsrManager->GetElapsedMediumSyncDelayTimer(m_linkId);
195  elapsed && emlsrManager->MediumSyncDelayNTxopsExceeded(m_linkId))
196  {
197  NS_LOG_DEBUG("No new TXOP attempts allowed while MediumSyncDelay is running");
198  // request channel access if needed when the MediumSyncDelay timer expires; in the
199  // meantime no queued packet can be transmitted
201  emlsrManager->GetMediumSyncDuration() - *elapsed,
203  edca,
204  m_linkId,
205  Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT, // queued frames cannot be transmitted until
206  // MSD expires
207  Txop::DONT_CHECK_MEDIUM_BUSY); // generate backoff regardless of medium busy
208  NotifyChannelReleased(edca);
209  return false;
210  }
211 
212  if (!m_phy)
213  {
214  NS_LOG_DEBUG("No PHY is currently operating on EMLSR link " << +m_linkId);
215  NotifyChannelReleased(edca);
216  return false;
217  }
218 
219  if (auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
220  mainPhy != m_phy)
221  {
222  // an aux PHY is operating on this link
223  if (!emlsrManager->GetAuxPhyTxCapable())
224  {
225  NS_LOG_DEBUG("Aux PHY is not capable of transmitting a PPDU");
226  NotifyChannelReleased(edca);
227  return false;
228  }
229 
230  if (mainPhy->IsStateRx())
231  {
232  NS_LOG_DEBUG(
233  "Main PHY is receiving a PPDU (may be, e.g., an ICF or a Beacon); do not "
234  "transmit to avoid dropping that PPDU due to the main PHY switching to this "
235  "link to take over the TXOP");
236  // Note that we do not prevent a (main or aux) PHY from starting a TXOP when
237  // an(other) aux PHY is receiving a PPDU. The reason is that if the aux PHY is
238  // receiving a Beacon frame, the aux PHY will not be affected by the start of
239  // a TXOP; if the aux PHY is receiving an ICF, the ICF will be dropped by
240  // ReceiveMpdu because another EMLSR link is being used.
241  NotifyChannelReleased(edca);
242  return false;
243  }
244 
245  const auto rtsTxVector =
246  GetWifiRemoteStationManager()->GetRtsTxVector(m_bssid, allowedWidth);
247  const auto rtsTxTime =
248  m_phy->CalculateTxDuration(GetRtsSize(), rtsTxVector, m_phy->GetPhyBand());
249  const auto ctsTxVector =
250  GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, rtsTxVector.GetMode());
251  const auto ctsTxTime =
252  m_phy->CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand());
253 
254  // the main PHY shall terminate the channel switch at the end of CTS reception;
255  // the time remaining to the end of CTS reception includes two propagation delays
256  timeToCtsEnd = rtsTxTime + m_phy->GetSifs() + ctsTxTime +
258 
259  auto switchingTime = mainPhy->GetChannelSwitchDelay();
260 
261  if (mainPhy->IsStateSwitching())
262  {
263  // the main PHY is switching (to another link), hence the remaining time to the
264  // end of the current channel switch needs to be added up
265  switchingTime += mainPhy->GetDelayUntilIdle();
266  }
267 
268  if (switchingTime > timeToCtsEnd)
269  {
270  // switching takes longer than RTS/CTS exchange, do not transmit anything to
271  // avoid that the main PHY is requested to switch while already switching
272  NS_LOG_DEBUG("Main PHY will still be switching channel when RTS/CTS ends, thus it "
273  "will not be able to take over this TXOP");
274  NotifyChannelReleased(edca);
275  return false;
276  }
277  }
278  }
279 
280  auto started = HeFrameExchangeManager::StartTransmission(edca, allowedWidth);
281 
282  if (started && m_staMac && m_staMac->IsEmlsrLink(m_linkId))
283  {
284  // notify the EMLSR Manager of the UL TXOP start on an EMLSR link
286  m_staMac->GetEmlsrManager()->NotifyUlTxopStart(m_linkId, timeToCtsEnd);
287  }
288 
289  return started;
290 }
291 
292 void
294 {
295  NS_LOG_FUNCTION(this << psdu << txVector);
296 
297  // EHT-SIG, the equivalent of HE-SIG-B, is present in EHT SU transmissions, too
298  if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU)
299  {
300  auto phy = StaticCast<EhtPhy>(m_phy->GetPhyEntity(WIFI_MOD_CLASS_EHT));
301  auto sigBMode = phy->GetSigBMode(txVector);
302  txVector.SetSigBMode(sigBMode);
303  }
304 
305  auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
306 
308  UpdateTxopEndOnTxStart(txDuration, psdu->GetDuration());
309 
310  if (m_apMac)
311  {
312  // check if the EMLSR clients shall switch back to listening operation at the end of this
313  // PPDU
314  for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
315  {
316  auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
317 
318  if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
319  GetEmlsrSwitchToListening(psdu, aid, *clientIt))
320  {
321  EmlsrSwitchToListening(*clientIt, txDuration);
322  // this client is no longer involved in the current TXOP
323  clientIt = m_protectedStas.erase(clientIt);
324  }
325  else
326  {
327  clientIt++;
328  }
329  }
330  }
331 }
332 
333 void
335 {
336  NS_LOG_FUNCTION(this << psduMap << txVector);
337 
338  auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
339 
341  UpdateTxopEndOnTxStart(txDuration, psduMap.begin()->second->GetDuration());
342 
343  if (m_apMac)
344  {
345  // check if the EMLSR clients shall switch back to listening operation at the end of this
346  // PPDU
347  for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
348  {
349  auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
350 
351  if (auto psduMapIt = psduMap.find(aid);
352  GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
353  (psduMapIt == psduMap.cend() ||
354  GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
355  {
356  EmlsrSwitchToListening(*clientIt, txDuration);
357  // this client is no longer involved in the current TXOP
358  clientIt = m_protectedStas.erase(clientIt);
359  }
360  else
361  {
362  clientIt++;
363  }
364  }
365  }
366 }
367 
368 void
370 {
371  NS_LOG_FUNCTION(this);
372  if (UsingOtherEmlsrLink())
373  {
374  // the CTS may have been missed because another EMLSR link is being used; do not reset NAV
375  return;
376  }
378 }
379 
380 void
382 {
383  NS_LOG_FUNCTION(this);
384  if (UsingOtherEmlsrLink())
385  {
386  // the CTS may have been missed because another EMLSR link is being used; do not reset NAV
387  return;
388  }
390 }
391 
392 void
394 {
395  NS_LOG_FUNCTION(this << address << delay.As(Time::US));
396 
397  // this EMLSR client switches back to listening operation a transition delay
398  // after the given delay
399  auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
400  NS_ASSERT(mldAddress);
401  auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
402  NS_ASSERT(emlCapabilities);
403 
404  std::set<uint8_t> linkIds;
405  for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
406  {
407  if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
408  {
409  linkIds.insert(linkId);
410  }
411  }
412 
413  auto blockLinks = [=, this]() {
414  // the reason for blocking the other EMLSR links has changed now
416  *mldAddress,
417  linkIds);
418 
419  // block DL transmissions on this link until transition delay elapses
421  *mldAddress,
422  linkIds);
423  };
424 
425  delay.IsZero() ? blockLinks() : static_cast<void>(Simulator::Schedule(delay, blockLinks));
426 
427  // unblock all EMLSR links when the transition delay elapses
428  auto unblockLinks = [=, this]() {
430  *mldAddress,
431  linkIds);
432  };
433 
434  auto endDelay = delay + CommonInfoBasicMle::DecodeEmlsrTransitionDelay(
435  emlCapabilities->get().emlsrTransitionDelay);
436 
437  endDelay.IsZero() ? unblockLinks()
438  : static_cast<void>(m_transDelayTimer[*mldAddress] =
439  Simulator::Schedule(endDelay, unblockLinks));
440 }
441 
442 void
444 {
445  NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
446 
447  // TODO Shall we assert that there is no ongoing frame exchange sequence? Or is it possible
448  // that there is an ongoing frame exchange sequence (in such a case, we need to force a
449  // timeout, just like it is done in case of a normal channel switch
450 
451  NS_ABORT_MSG_IF(!m_staMac, "This method can only be called on a STA");
452 
453  // if we receive the notification from a PHY that is not connected to us, it means that
454  // we have been already connected to another PHY operating on this link, hence we do not
455  // have to reset the connected PHY. Similarly, we do not have to reset the connected PHY if
456  // the link does not change (this occurs when changing the channel width of aux PHYs upon
457  // enabling the EMLSR mode).
458  if (phy == m_phy && linkId != m_linkId)
459  {
460  ResetPhy();
461  }
462  m_staMac->NotifySwitchingEmlsrLink(phy, linkId, delay);
463 }
464 
465 void
467 {
468  NS_LOG_FUNCTION(this << dest << frame);
469 
470  WifiMacHeader hdr;
472  hdr.SetAddr1(dest);
473  hdr.SetAddr2(m_self);
474  hdr.SetAddr3(m_bssid);
475  hdr.SetDsNotTo();
476  hdr.SetDsNotFrom();
477 
478  // get the sequence number for the TWT Setup management frame
479  const auto sequence = m_txMiddle->GetNextSequenceNumberFor(&hdr);
480  hdr.SetSequenceNumber(sequence);
481 
482  WifiActionHeader actionHdr;
486 
487  auto packet = Create<Packet>();
488  packet->AddHeader(frame);
489  packet->AddHeader(actionHdr);
490 
491  // Use AC_VO to send management frame addressed to a QoS STA (Sec. 10.2.3.2 of 802.11-2020)
492  m_mac->GetQosTxop(AC_VO)->Queue(Create<WifiMpdu>(packet, hdr));
493 }
494 
495 std::optional<double>
497 {
499 
500  if (optRssi)
501  {
502  return optRssi;
503  }
504 
505  auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
506 
507  if (!mldAddress)
508  {
509  // not an MLD, nothing else can be done
510  return std::nullopt;
511  }
512 
513  for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
514  {
515  std::optional<Mac48Address> linkAddress;
516  if (linkId != m_linkId &&
517  (linkAddress = m_mac->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(
518  *mldAddress)) &&
519  (optRssi = m_mac->GetWifiRemoteStationManager(linkId)->GetMostRecentRssi(*linkAddress)))
520  {
521  return optRssi;
522  }
523  }
524 
525  return std::nullopt;
526 }
527 
528 void
530 {
531  NS_LOG_FUNCTION(this << &txParams);
532 
533  uint8_t maxPaddingDelay = 0;
534 
535  // block transmissions on the other EMLSR links of the EMLSR clients
536  for (const auto& address : m_sentRtsTo)
537  {
538  if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
539  {
540  continue;
541  }
542 
543  auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
544  NS_ASSERT(emlCapabilities);
545  maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->get().emlsrPaddingDelay);
546 
547  auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
548  NS_ASSERT(mldAddress);
549 
550  for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
551  {
552  if (linkId != m_linkId &&
553  m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
554  {
556  *mldAddress,
557  {linkId});
558  }
559  }
560  }
561 
562  // add padding (if needed)
563  if (maxPaddingDelay > 0)
564  {
565  NS_ASSERT(txParams.m_protection &&
566  txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
567  auto protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
568  NS_ASSERT(protection->muRts.IsMuRts());
569 
570  // see formula (35-1) in Sec. 35.5.2.2.3 of 802.11be D3.0
571  auto rate = protection->muRtsTxVector.GetMode().GetDataRate(protection->muRtsTxVector);
572  std::size_t nDbps = rate / 1e6 * 4; // see Table 17-4 of 802.11-2020
573  protection->muRts.SetPaddingSize((1 << (maxPaddingDelay + 2)) * nDbps / 8);
574  }
575 
577 }
578 
579 void
581 {
582  NS_LOG_FUNCTION(this << *muRts << txVector);
583 
584  // we blocked transmissions on the other EMLSR links for the EMLSR clients we sent the ICF to.
585  // Given that no client responded, we can unblock transmissions for a client if there is no
586  // ongoing UL TXOP held by that client
587  for (const auto& address : m_sentRtsTo)
588  {
589  if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
590  {
591  continue;
592  }
593 
594  auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
595  NS_ASSERT(mldAddress);
596 
598  m_mac->GetMldAddress(*m_txopHolder) == mldAddress)
599  {
600  continue;
601  }
602 
603  for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
604  {
605  if (linkId != m_linkId &&
606  m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
607  {
609  *mldAddress,
610  {linkId});
611  }
612  }
613  }
614 
616 }
617 
618 bool
620  uint16_t aid,
621  const Mac48Address& address) const
622 {
623  NS_LOG_FUNCTION(this << psdu << aid << address);
624 
625  // Sec. 35.3.17 of 802.11be D3.0:
626  // The non-AP MLD shall be switched back to the listening operation on the EMLSR links after
627  // the EMLSR transition delay time if [...] the non-AP STA affiliated with the non-AP MLD
628  // does not detect [...] any of the following frames:
629  // - an individually addressed frame with the RA equal to the MAC address of the non-AP STA
630  // affiliated with the non-AP MLD
631  if (psdu->GetAddr1() == address)
632  {
633  return false;
634  }
635 
636  // - a Trigger frame that has one of the User Info fields addressed to the non-AP STA
637  // affiliated with the non-AP MLD
638  for (const auto& mpdu : *PeekPointer(psdu))
639  {
640  if (mpdu->GetHeader().IsTrigger())
641  {
642  CtrlTriggerHeader trigger;
643  mpdu->GetPacket()->PeekHeader(trigger);
644  if (trigger.FindUserInfoWithAid(aid) != trigger.end())
645  {
646  return false;
647  }
648  }
649  }
650 
651  // - a CTS-to-self frame with the RA equal to the MAC address of the AP affiliated with
652  // the AP MLD
653  if (psdu->GetHeader(0).IsCts())
654  {
655  if (m_apMac && psdu->GetAddr1() == m_self)
656  {
657  return false;
658  }
659  if (m_staMac && psdu->GetAddr1() == m_bssid)
660  {
661  return false;
662  }
663  }
664 
665  // - a Multi-STA BlockAck frame that has one of the Per AID TID Info fields addressed to
666  // the non-AP STA affiliated with the non-AP MLD
667  if (psdu->GetHeader(0).IsBlockAck())
668  {
669  CtrlBAckResponseHeader blockAck;
670  psdu->GetPayload(0)->PeekHeader(blockAck);
671  if (blockAck.IsMultiSta() && !blockAck.FindPerAidTidInfoWithAid(aid).empty())
672  {
673  return false;
674  }
675  }
676 
677  // - a NDP Announcement frame that has one of the STA Info fields addressed to the non-AP
678  // STA affiliated with the non-AP MLD and a sounding NDP
679  // TODO NDP Announcement frame not supported yet
680 
681  return true;
682 }
683 
684 void
686 {
687  NS_LOG_FUNCTION(this);
688 
690  m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
691  {
692  NS_LOG_DEBUG("Reset the counter of TXOP attempts allowed while "
693  "MediumSyncDelay is running");
694  m_staMac->GetEmlsrManager()->ResetMediumSyncDelayNTxops(m_linkId);
695  }
696 
698 }
699 
700 void
702 {
703  NS_LOG_FUNCTION(this);
704 
706  m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
707  {
708  NS_LOG_DEBUG("Decrement the remaining number of TXOP attempts allowed while "
709  "MediumSyncDelay is running");
710  m_staMac->GetEmlsrManager()->DecrementMediumSyncDelayNTxops(m_linkId);
711  }
712 
714 }
715 
716 void
718 {
719  NS_LOG_FUNCTION(this << txop);
720 
721  if (m_apMac)
722  {
723  // the channel has been released; all EMLSR clients are switching back to
724  // listening operation
725  for (const auto& address : m_protectedStas)
726  {
727  if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
728  {
730  }
731  }
732  }
733  else if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
734  {
735  // notify the EMLSR Manager of the UL TXOP end, if the TXOP included the transmission of
736  // at least a frame
738  auto edca = DynamicCast<QosTxop>(txop);
739  NS_ASSERT(edca);
740  if (auto txopStart = edca->GetTxopStartTime(m_linkId);
741  txopStart && Simulator::Now() > *txopStart)
742  {
743  m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
744  }
745  }
746 
748 }
749 
750 void
752 {
753  NS_LOG_FUNCTION(this << psdu << txVector);
754 
755  // In addition, the timer resets to zero when any of the following events occur:
756  // — The STA receives an MPDU
757  // (Sec. 35.3.16.8.1 of 802.11be D3.1)
759  m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
760  {
761  m_staMac->GetEmlsrManager()->CancelMediumSyncDelayTimer(m_linkId);
762  }
763 
764  if (m_apMac)
765  {
766  // we iterate over protected STAs to consider only the case when the AP is the TXOP holder.
767  // The AP received a PSDU from a non-AP STA; given that the AP is the TXOP holder, this
768  // PSDU has been likely solicited by the AP. In most of the cases, we identify which EMLSR
769  // clients are no longer involved in the TXOP when the AP transmits the frame soliciting
770  // response(s) from client(s). This is not the case, for example, for the acknowledgment
771  // in SU format of a DL MU PPDU, where all the EMLSR clients (but one) switch to listening
772  // operation after the immediate response (if any) by one of the EMLSR clients.
773  for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
774  {
775  // TB PPDUs are received by the AP at distinct times, so it is difficult to take a
776  // decision based on one of them. However, clients transmitting TB PPDUs are identified
777  // by the soliciting Trigger Frame, thus we have already identified (when sending the
778  // Trigger Frame) which EMLSR clients have switched to listening operation.
779  // If the PSDU is not carried in a TB PPDU, we can determine whether this EMLSR client
780  // is switching to listening operation by checking whether the AP is expecting a
781  // response from it.
782  if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) && !txVector.IsUlMu() &&
783  m_txTimer.GetStasExpectedToRespond().count(*clientIt) == 0)
784  {
785  EmlsrSwitchToListening(*clientIt, Seconds(0));
786  // this client is no longer involved in the current TXOP
787  clientIt = m_protectedStas.erase(clientIt);
788  }
789  else
790  {
791  clientIt++;
792  }
793  }
794  }
795 
797 }
798 
799 void
801 {
802  NS_LOG_FUNCTION(this << psdu << txVector);
803 
805 
806  if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
807  GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
808  {
810  {
811  // an EMLSR client has started an UL TXOP. We may send a response after a SIFS or
812  // we may receive another frame after a SIFS. Postpone the TXOP end by considering
813  // the latter (which takes longer)
814  auto delay =
816  NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
818  }
819  else
820  {
822  }
823  }
824 
826  {
828  {
829  // we are no longer involved in the TXOP and switching to listening mode
831  m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
832  }
833  else
834  {
836  }
837  }
838 }
839 
840 void
842  RxSignalInfo rxSignalInfo,
843  const WifiTxVector& txVector,
844  bool inAmpdu)
845 {
846  // The received MPDU is either broadcast or addressed to this station
847  NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
848 
849  const auto& hdr = mpdu->GetHeader();
850 
851  if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr2()))
852  {
853  // the AP MLD received an MPDU from an EMLSR client, which is now involved in an UL TXOP,
854  // hence block transmissions for this EMLSR client on other links
855  auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(hdr.GetAddr2());
856  NS_ASSERT(mldAddress);
857 
858  for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
859  {
860  if (linkId != m_linkId &&
861  m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
862  {
864  *mldAddress,
865  {linkId});
866  }
867  }
868 
869  // Make sure that transmissions for this EMLSR client are not blocked on this link
870  // (the AP MLD may have sent an ICF on another link right before receiving this MPDU,
871  // thus transmissions on this link may have been blocked)
873  *mldAddress,
874  {m_linkId});
875 
876  // Stop the transition delay timer for this EMLSR client, if any is running
877  if (auto it = m_transDelayTimer.find(*mldAddress);
878  it != m_transDelayTimer.end() && it->second.IsRunning())
879  {
880  it->second.PeekEventImpl()->Invoke();
881  it->second.Cancel();
882  }
883  }
884 
885  bool icfReceived = false;
886 
887  if (hdr.IsTrigger())
888  {
889  if (!m_staMac)
890  {
891  return; // Trigger Frames are only processed by STAs
892  }
893 
894  CtrlTriggerHeader trigger;
895  mpdu->GetPacket()->PeekHeader(trigger);
896 
897  if (hdr.GetAddr1() != m_self &&
898  (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
899  hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with
900  || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end()))
901  {
902  return; // not addressed to us
903  }
904 
905  if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId))
906  {
907  // this is an initial Control frame
908  if (UsingOtherEmlsrLink())
909  {
910  // we received an ICF on a link that is blocked because another EMLSR link is
911  // being used. This is likely because transmission on the other EMLSR link
912  // started before the reception of the ICF ended. We drop this ICF and let the
913  // UL TXOP continue.
914  NS_LOG_DEBUG("Drop ICF because another EMLSR link is being used");
915  return;
916  }
917 
945  if (auto elapsed =
946  m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
947  {
948  TimeValue padding;
949  m_staMac->GetEmlsrManager()->GetAttribute("EmlsrPaddingDelay", padding);
950 
951  if (*elapsed < padding.Get())
952  {
953  NS_LOG_DEBUG("Drop ICF due to not enough time for the main PHY to switch link");
954  return;
955  }
956  }
957 
959  m_staMac->GetEmlsrManager()->NotifyIcfReceived(m_linkId);
960  icfReceived = true;
961 
962  // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
963  // SIFS (we are expected to reply by sending a CTS frame)
965  NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
968  this);
969  }
970  }
971 
972  // We impose that an aux PHY is only able to receive an ICF, a CTS or a management frame
973  // (we are interested in receiving mainly Beacon frames). Note that other frames are still
974  // post-processed, e.g., used to set the NAV and the TXOP holder.
975  // The motivation is that, e.g., an AP MLD may send an ICF to EMLSR clients A and B;
976  // A responds while B does not; the AP MLD sends a DL MU PPDU to both clients followed
977  // by an MU-BAR to solicit a BlockAck from both clients. If an aux PHY of client B is
978  // operating on this link, the MU-BAR will be received and a TB PPDU response sent
979  // through the aux PHY.
981  m_mac->GetLinkForPhy(m_staMac->GetEmlsrManager()->GetMainPhyId()) != m_linkId &&
982  !icfReceived && !mpdu->GetHeader().IsCts() && !mpdu->GetHeader().IsMgt())
983  {
984  NS_LOG_DEBUG("Dropping " << *mpdu << " received by an aux PHY on link " << +m_linkId);
985  return;
986  }
987 
988  HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
989 }
990 
991 void
993 {
994  NS_LOG_FUNCTION(this);
995 
997  {
998  // we may get here because the PHY has not issued the PHY-RXSTART.indication before
999  // the expiration of the timer started to detect new received frames, but the PHY is
1000  // currently decoding the PHY header of a PPDU, so let's wait some more time to check
1001  // if we receive a PHY-RXSTART.indication when the PHY is done decoding the PHY header
1002  NS_LOG_DEBUG("PHY is decoding the PHY header of PPDU, postpone TXOP end");
1005  this);
1006  return;
1007  }
1008 
1010  {
1011  m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
1012  }
1013  else if (m_apMac && m_txopHolder &&
1014  GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
1015  {
1016  // EMLSR client terminated its TXOP and is back to listening operation
1018  }
1019 }
1020 
1021 void
1023 {
1024  NS_LOG_FUNCTION(this << txDuration.As(Time::MS) << durationId.As(Time::US));
1025 
1026  if (!m_ongoingTxopEnd.IsRunning())
1027  {
1028  // nothing to do
1029  return;
1030  }
1031 
1033  Time delay;
1034 
1035  if (m_txTimer.IsRunning())
1036  {
1037  // the TX timer is running, hence we are expecting a response. Postpone the TXOP end
1038  // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
1039  // the response)
1040  delay = m_txTimer.GetDelayLeft();
1041  }
1042  else if (durationId <= m_phy->GetSifs())
1043  {
1044  // the TX timer is not running, hence no response is expected, and the Duration/ID value
1045  // is less than or equal to a SIFS; the TXOP will end after this transmission
1046  NS_LOG_DEBUG("Assume TXOP will end based on Duration/ID value");
1047  delay = txDuration;
1048  }
1049  else
1050  {
1051  // the TX Timer is not running, hence no response is expected (e.g., we are
1052  // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
1053  // after the end of this PPDU, hence we need to postpone the TXOP end in order to
1054  // get the PHY-RXSTART.indication
1055  delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1057  }
1058 
1059  NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1061 }
1062 
1063 void
1065 {
1066  NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
1067 
1068  if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
1069  {
1070  // nothing to do
1071  return;
1072  }
1073 
1074  // postpone the TXOP end until after the reception of the PSDU is completed
1076 
1077  NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
1080 }
1081 
1082 void
1084 {
1085  NS_LOG_FUNCTION(this << durationId.As(Time::US));
1086 
1087  if (!m_ongoingTxopEnd.IsRunning())
1088  {
1089  // nothing to do
1090  return;
1091  }
1092 
1094 
1095  // if the Duration/ID of the received frame is less than a SIFS, the TXOP
1096  // is terminated
1097  if (durationId <= m_phy->GetSifs())
1098  {
1099  NS_LOG_DEBUG("Assume TXOP ended based on Duration/ID value");
1100  TxopEnd();
1101  return;
1102  }
1103 
1104  // we may send a response after a SIFS or we may receive another frame after a SIFS.
1105  // Postpone the TXOP end by considering the latter (which takes longer)
1107  NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1109 }
1110 
1111 } // namespace ns3
#define max(a, b)
Definition: 80211b.c:42
Headers for BlockAck response.
Definition: ctrl-headers.h:203
std::vector< uint32_t > FindPerAidTidInfoWithAid(uint16_t aid) const
For Multi-STA Block Acks, get the indices of the Per AID TID Info subfields carrying the given AID in...
bool IsMultiSta() const
Check if the BlockAck frame variant is Multi-STA Block Ack.
Headers for Trigger frames.
Definition: ctrl-headers.h:942
ConstIterator end() const
Get a const iterator indicating past-the-last User Info field in the list.
bool IsMuRts() const
Check if this is a MU-RTS Trigger frame.
ConstIterator FindUserInfoWithAid(ConstIterator start, uint16_t aid12) const
Get a const iterator pointing to the first User Info field found (starting from the one pointed to by...
EhtFrameExchangeManager handles the frame exchange sequences for EHT stations.
void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector) override
Forward a map of PSDUs down to the PHY layer.
void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector) override
Forward a PSDU down to the PHY layer.
void TxopEnd()
Take actions when a TXOP (of which we are not the holder) ends.
void SendEmlOmn(const Mac48Address &dest, const MgtEmlOmn &frame)
Send an EML Operating Mode Notification frame to the given station.
Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const override
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
void TransmissionFailed() override
Take necessary actions upon a transmission failure.
void IntraBssNavResetTimeout() override
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
void SendMuRts(const WifiTxParameters &txParams) override
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
void UpdateTxopEndOnRxEnd(Time durationId)
Update the TXOP end timer when a frame reception ends.
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
bool GetEmlsrSwitchToListening(Ptr< const WifiPsdu > psdu, uint16_t aid, const Mac48Address &address) const
static TypeId GetTypeId()
Get the type ID.
void DoDispose() override
Destructor implementation.
bool StartTransmission(Ptr< Txop > edca, uint16_t allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
std::unordered_map< Mac48Address, EventId, WifiAddressHash > m_transDelayTimer
MLD address-indexed map of transition delay timers.
void NotifyChannelReleased(Ptr< Txop > txop) override
Notify the given Txop that channel has been released.
EventId m_ongoingTxopEnd
event indicating the possible end of the current TXOP (of which we are not the holder)
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void UpdateTxopEndOnTxStart(Time txDuration, Time durationId)
Update the TXOP end timer when starting a frame transmission.
void UpdateTxopEndOnRxStartIndication(Time psduDuration)
Update the TXOP end timer when receiving a PHY-RXSTART.indication.
void EmlsrSwitchToListening(const Mac48Address &address, const Time &delay)
This method is intended to be called when an AP MLD detects that an EMLSR client previously involved ...
void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector) override
Called when no CTS frame is received after an MU-RTS.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, uint8_t linkId, Time delay)
Notify that the given PHY will switch channel to operate on another EMLSR link after the given delay.
std::optional< double > GetMostRecentRssi(const Mac48Address &address) const override
Get the RSSI (in dBm) of the most recent packet received from the station having the given address.
void SetLinkId(uint8_t linkId) override
Set the ID of the link this Frame Exchange Manager is associated with.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
virtual void ResetPhy()
Remove WifiPhy associated with this FrameExchangeManager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
Mac48Address m_self
the MAC address of this device
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
Mac48Address GetAddress() const
Get the MAC address.
virtual void SetLinkId(uint8_t linkId)
Set the ID of the link this Frame Exchange Manager is associated with.
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
Ptr< WifiPhy > m_phy
the PHY layer on this station
Mac48Address m_bssid
BSSID address (Mac48Address)
HeFrameExchangeManager handles the frame exchange sequences for HE stations.
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
void DoDispose() override
Destructor implementation.
virtual void IntraBssNavResetTimeout()
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
virtual void SendMuRts(const WifiTxParameters &txParams)
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
virtual std::optional< double > GetMostRecentRssi(const Mac48Address &address) const
Get the RSSI (in dBm) of the most recent packet received from the station having the given address.
virtual void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector)
Called when no CTS frame is received after an MU-RTS.
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
virtual void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector)
Forward a map of PSDUs down to the PHY layer.
void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
Ptr< MpduAggregator > m_mpduAggregator
A-MPDU aggregator.
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
Ptr< MsduAggregator > m_msduAggregator
A-MSDU aggregator.
an EUI-48 address
Definition: mac48-address.h:46
Implement the header for Action frames of type EML Operating Mode Notification.
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
void TransmissionFailed() override
Take necessary actions upon a transmission failure.
std::optional< Mac48Address > m_txopHolder
MAC address of the TXOP holder.
bool StartTransmission(Ptr< Txop > edca, uint16_t allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
virtual Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
uint16_t GetAssociationId() const
Return the association ID.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, uint8_t linkId, Time delay)
Notify that the given PHY switched channel to operate on another EMLSR link.
Ptr< EmlsrManager > GetEmlsrManager() const
bool IsEmlsrLink(uint8_t linkId) const
bool IsAssociated() const
Return whether we are associated with an AP.
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
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
@ US
microsecond
Definition: nstime.h:118
@ MS
millisecond
Definition: nstime.h:117
@ S
second
Definition: nstime.h:116
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:315
Time Get() const
Definition: time.cc:530
void StartAccessAfterEvent(uint8_t linkId, bool hadFramesToTransmit, bool checkMediumBusy)
Request channel access on the given link after the occurrence of an event that possibly requires to g...
Definition: txop.cc:572
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition: txop.h:417
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:523
static constexpr bool DONT_CHECK_MEDIUM_BUSY
generation of backoff is independent of the busy/idle state of the medium
Definition: txop.h:421
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
Implements the IEEE 802.11 MAC header.
bool IsCts() const
Return true if the header is a CTS header.
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
bool IsBlockAck() const
Return true if the header is a BlockAck header.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1632
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:576
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:933
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Definition: wifi-mac.cc:1428
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Definition: wifi-mac.cc:1387
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
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:906
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
Ptr< WifiPhy > GetPhy() const
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:793
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:781
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1507
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1021
bool IsReceivingPhyHeader() const
Definition: wifi-phy.cc:1891
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:711
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:279
Time GetDuration() const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
Definition: wifi-psdu.cc:153
Mac48Address GetAddr2() const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:128
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Definition: wifi-psdu.cc:291
Mac48Address GetAddr1() const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:113
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
bool IsRunning() const
Return true if the timer is running.
const std::set< Mac48Address > & GetStasExpectedToRespond() const
Time GetDelayLeft() const
Get the remaining time until the timer will expire.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiPreamble GetPreambleType() const
bool IsUlMu() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
Declaration of ns3::EhtPhy class.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG_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 NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
address
Definition: first.py:47
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
static constexpr uint8_t WAIT_FOR_RXSTART_DELAY_USEC
Additional time (exceeding 20 us) to wait for a PHY-RXSTART.indication when the PHY is decoding a PHY...
static constexpr uint8_t RX_PHY_START_DELAY_USEC
aRxPHYStartDelay value to use when waiting for a new frame in the context of EMLSR operations (Sec.
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Definition: wifi-utils.cc:103
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
@ WIFI_MAC_MGT_ACTION
static constexpr uint8_t MAX_PROPAGATION_DELAY_USEC
maximum propagation delay
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
Definition: wifi-utils.cc:111
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:449
phy
Definition: third.py:89
static Time DecodeEmlsrTransitionDelay(uint8_t value)
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.
typedef for union of different ActionValues