A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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 WIFI_FEM_NS_LOG_APPEND_CONTEXT
35
36namespace ns3
37{
38
39/// aRxPHYStartDelay value to use when waiting for a new frame in the context of EMLSR operations
40/// (Sec. 35.3.17 of 802.11be D3.1)
41static constexpr uint8_t RX_PHY_START_DELAY_USEC = 20;
42
43/**
44 * Additional time (exceeding 20 us) to wait for a PHY-RXSTART.indication when the PHY is
45 * decoding a PHY header.
46 *
47 * Values for aRxPHYStartDelay:
48 * - OFDM : 20 us (for 20 MHz) [Table 17-21 of 802.11-2020]
49 * - ERP-OFDM : 20 us [Table 18-5 of 802.11-2020]
50 * - HT : 28 us (HT-mixed), 24 us (HT-greenfield) [Table 19-25 of 802.11-2020]
51 * - VHT : 36 + 4 * max N_VHT-LTF + 4 = 72 us [Table 21-28 of 802.11-2020]
52 * - HE : 32 us (for HE SU and HE TB PPDUs)
53 * 32 + 4 * N_HE-SIG-B us (for HE MU PPDUs) [Table 27-54 of 802.11ax-2021]
54 * - EHT : 32 us (for EHT TB PPDUs)
55 * 32 + 4 * N_EHT-SIG us (for EHT MU PPDUs) [Table 36-70 of 802.11be D3.2]
56 */
57static constexpr uint8_t WAIT_FOR_RXSTART_DELAY_USEC = 52;
58
59NS_LOG_COMPONENT_DEFINE("EhtFrameExchangeManager");
60
62
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
83void
85{
86 NS_LOG_FUNCTION(this);
89}
90
91void
93{
94 NS_LOG_FUNCTION(this << txVector << psduDuration.As(Time::MS));
95
96 HeFrameExchangeManager::RxStartIndication(txVector, psduDuration);
98}
99
100void
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());
133 NS_ASSERT(address);
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
159bool
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)
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
175bool
177{
178 NS_LOG_FUNCTION(this << edca << allowedWidth);
179
180 if (m_apMac)
181 {
182 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
183 {
184 if (linkId == m_linkId)
185 {
186 continue;
187 }
188
189 // EMLSR clients involved in a DL or UL TXOP on another link
190 std::set<Mac48Address> emlsrClients;
191
192 // check if an EMLSR client is the holder of an UL TXOP on the other link
193 if (auto ehtFem =
194 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
195 ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
196 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(
197 ehtFem->m_txopHolder.value()))
198 {
199 emlsrClients.insert(ehtFem->m_txopHolder.value());
200 }
201
202 // check if EMLSR clients are involved in a DL TXOP on another link
203 for (const auto& address : m_protectedStas)
204 {
205 if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(address))
206 {
207 emlsrClients.insert(address);
208 }
209 }
210
211 for (const auto& address : emlsrClients)
212 {
213 auto mldAddress =
214 m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(address);
215 NS_ASSERT_MSG(mldAddress, "MLD address not found for " << address);
216
217 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(*mldAddress))
218 {
219 // EMLSR client did not enable EMLSR mode on this link, we can transmit to it
220 continue;
221 }
222
223 // check that this link is blocked as expected
224 WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddress, 0);
225 auto mask =
226 m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, m_linkId);
227 NS_ASSERT_MSG(mask,
228 "No mask for client " << *mldAddress << " on link " << +m_linkId);
229 if (!mask->test(
230 static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
231 {
232 NS_ASSERT_MSG(false,
233 "Transmissions to " << *mldAddress << " on link " << +m_linkId
234 << " are not blocked");
235 // in case asserts are disabled, block transmissions on the other links because
236 // this is what we need
238 *mldAddress,
239 {m_linkId});
240 }
241 }
242 }
243 }
244
245 std::optional<Time> timeToCtsEnd;
246
248 {
249 // Cannot start a transmission on a link blocked because another EMLSR link is being used
251 {
252 NS_LOG_DEBUG("StartTransmission called while another EMLSR link is being used");
254 return false;
255 }
256
257 auto emlsrManager = m_staMac->GetEmlsrManager();
258
259 if (auto elapsed = emlsrManager->GetElapsedMediumSyncDelayTimer(m_linkId);
260 elapsed && emlsrManager->MediumSyncDelayNTxopsExceeded(m_linkId))
261 {
262 NS_LOG_DEBUG("No new TXOP attempts allowed while MediumSyncDelay is running");
263 // request channel access if needed when the MediumSyncDelay timer expires; in the
264 // meantime no queued packet can be transmitted
266 emlsrManager->GetMediumSyncDuration() - *elapsed,
268 edca,
269 m_linkId,
270 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT, // queued frames cannot be transmitted until
271 // MSD expires
272 Txop::DONT_CHECK_MEDIUM_BUSY); // generate backoff regardless of medium busy
274 return false;
275 }
276
277 if (!m_phy)
278 {
279 NS_LOG_DEBUG("No PHY is currently operating on EMLSR link " << +m_linkId);
281 return false;
282 }
283
284 if (auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
285 mainPhy != m_phy)
286 {
287 // an aux PHY is operating on this link
288 if (!emlsrManager->GetAuxPhyTxCapable())
289 {
290 NS_LOG_DEBUG("Aux PHY is not capable of transmitting a PPDU");
292 return false;
293 }
294
295 if (mainPhy->IsStateRx())
296 {
298 "Main PHY is receiving a PPDU (may be, e.g., an ICF or a Beacon); do not "
299 "transmit to avoid dropping that PPDU due to the main PHY switching to this "
300 "link to take over the TXOP");
301 // Note that we do not prevent a (main or aux) PHY from starting a TXOP when
302 // an(other) aux PHY is receiving a PPDU. The reason is that if the aux PHY is
303 // receiving a Beacon frame, the aux PHY will not be affected by the start of
304 // a TXOP; if the aux PHY is receiving an ICF, the ICF will be dropped by
305 // ReceiveMpdu because another EMLSR link is being used.
307 return false;
308 }
309
310 const auto rtsTxVector =
311 GetWifiRemoteStationManager()->GetRtsTxVector(m_bssid, allowedWidth);
312 const auto rtsTxTime =
314 const auto ctsTxVector =
315 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, rtsTxVector.GetMode());
316 const auto ctsTxTime =
318
319 // the main PHY shall terminate the channel switch at the end of CTS reception;
320 // the time remaining to the end of CTS reception includes two propagation delays
321 timeToCtsEnd = rtsTxTime + m_phy->GetSifs() + ctsTxTime +
323
324 auto switchingTime = mainPhy->GetChannelSwitchDelay();
325
326 if (mainPhy->IsStateSwitching())
327 {
328 // the main PHY is switching (to another link), hence the remaining time to the
329 // end of the current channel switch needs to be added up
330 switchingTime += mainPhy->GetDelayUntilIdle();
331 }
332
333 if (switchingTime > timeToCtsEnd)
334 {
335 // switching takes longer than RTS/CTS exchange, do not transmit anything to
336 // avoid that the main PHY is requested to switch while already switching
337 NS_LOG_DEBUG("Main PHY will still be switching channel when RTS/CTS ends, thus it "
338 "will not be able to take over this TXOP");
340 return false;
341 }
342 }
343 }
344
345 auto started = HeFrameExchangeManager::StartTransmission(edca, allowedWidth);
346
347 if (started && m_staMac && m_staMac->IsEmlsrLink(m_linkId))
348 {
349 // notify the EMLSR Manager of the UL TXOP start on an EMLSR link
351 m_staMac->GetEmlsrManager()->NotifyUlTxopStart(m_linkId, timeToCtsEnd);
352 }
353
354 if (started)
355 {
356 // we are starting a new TXOP, hence consider the previous ongoing TXOP as terminated
358 }
359
360 return started;
361}
362
363void
365{
366 NS_LOG_FUNCTION(this << psdu << txVector);
367
368 // EHT-SIG, the equivalent of HE-SIG-B, is present in EHT SU transmissions, too
369 if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU)
370 {
371 auto phy = StaticCast<EhtPhy>(m_phy->GetPhyEntity(WIFI_MOD_CLASS_EHT));
372 auto sigBMode = phy->GetSigBMode(txVector);
373 txVector.SetSigBMode(sigBMode);
374 }
375
376 auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
377
379 UpdateTxopEndOnTxStart(txDuration, psdu->GetDuration());
380
381 if (m_apMac)
382 {
383 // check if the EMLSR clients shall switch back to listening operation at the end of this
384 // PPDU
385 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
386 {
387 auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
388
389 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
390 GetEmlsrSwitchToListening(psdu, aid, *clientIt))
391 {
392 EmlsrSwitchToListening(*clientIt, txDuration);
393 // this client is no longer involved in the current TXOP
394 clientIt = m_protectedStas.erase(clientIt);
395 }
396 else
397 {
398 clientIt++;
399 }
400 }
401 }
402}
403
404void
406{
407 NS_LOG_FUNCTION(this << psduMap << txVector);
408
409 auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
410
412 UpdateTxopEndOnTxStart(txDuration, psduMap.begin()->second->GetDuration());
413
414 if (m_apMac)
415 {
416 // check if the EMLSR clients shall switch back to listening operation at the end of this
417 // PPDU
418 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
419 {
420 auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
421
422 if (auto psduMapIt = psduMap.find(aid);
423 GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
424 (psduMapIt == psduMap.cend() ||
425 GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
426 {
427 EmlsrSwitchToListening(*clientIt, txDuration);
428 // this client is no longer involved in the current TXOP
429 clientIt = m_protectedStas.erase(clientIt);
430 }
431 else
432 {
433 clientIt++;
434 }
435 }
436 }
437}
438
439void
441{
442 NS_LOG_FUNCTION(this);
444 {
445 // the CTS may have been missed because another EMLSR link is being used; do not reset NAV
446 return;
447 }
449}
450
451void
453{
454 NS_LOG_FUNCTION(this);
456 {
457 // the CTS may have been missed because another EMLSR link is being used; do not reset NAV
458 return;
459 }
461}
462
463void
465{
466 NS_LOG_FUNCTION(this << address << delay.As(Time::US));
467
468 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
469 NS_ASSERT_MSG(mldAddress, "MLD address not found for " << address);
470 NS_ASSERT_MSG(m_apMac, "This function shall only be called by AP MLDs");
471
472 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
473 {
474 if (auto ehtFem =
475 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
476 ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
477 m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(*ehtFem->m_txopHolder) ==
478 mldAddress)
479 {
480 // this EMLSR client is the holder of an UL TXOP, do not unblock links
481 return;
482 }
483 }
484
485 // this EMLSR client switches back to listening operation a transition delay
486 // after the given delay
487 auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
488 NS_ASSERT(emlCapabilities);
489
490 std::set<uint8_t> linkIds;
491 for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
492 {
493 if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
494 {
495 linkIds.insert(linkId);
496 }
497 }
498
499 auto blockLinks = [=, this]() {
500 // the reason for blocking the other EMLSR links has changed now
502 *mldAddress,
503 linkIds);
504
505 // block DL transmissions on this link until transition delay elapses
507 *mldAddress,
508 linkIds);
509 };
510
511 delay.IsZero() ? blockLinks() : static_cast<void>(Simulator::Schedule(delay, blockLinks));
512
513 // unblock all EMLSR links when the transition delay elapses
514 auto unblockLinks = [=, this]() {
516 *mldAddress,
517 linkIds);
518 };
519
521 emlCapabilities->get().emlsrTransitionDelay);
522
523 endDelay.IsZero() ? unblockLinks()
524 : static_cast<void>(m_transDelayTimer[*mldAddress] =
525 Simulator::Schedule(endDelay, unblockLinks));
526}
527
528void
530{
531 NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
532
533 // TODO Shall we assert that there is no ongoing frame exchange sequence? Or is it possible
534 // that there is an ongoing frame exchange sequence (in such a case, we need to force a
535 // timeout, just like it is done in case of a normal channel switch
536
537 NS_ABORT_MSG_IF(!m_staMac, "This method can only be called on a STA");
538
539 // if we receive the notification from a PHY that is not connected to us, it means that
540 // we have been already connected to another PHY operating on this link, hence we do not
541 // have to reset the connected PHY. Similarly, we do not have to reset the connected PHY if
542 // the link does not change (this occurs when changing the channel width of aux PHYs upon
543 // enabling the EMLSR mode).
544 if (phy == m_phy && linkId != m_linkId)
545 {
546 ResetPhy();
547 }
548 m_staMac->NotifySwitchingEmlsrLink(phy, linkId, delay);
549}
550
551void
553{
554 NS_LOG_FUNCTION(this << dest << frame);
555
556 WifiMacHeader hdr;
558 hdr.SetAddr1(dest);
559 hdr.SetAddr2(m_self);
560 hdr.SetAddr3(m_bssid);
561 hdr.SetDsNotTo();
562 hdr.SetDsNotFrom();
563
564 // get the sequence number for the TWT Setup management frame
565 const auto sequence = m_txMiddle->GetNextSequenceNumberFor(&hdr);
566 hdr.SetSequenceNumber(sequence);
567
568 WifiActionHeader actionHdr;
572
573 auto packet = Create<Packet>();
574 packet->AddHeader(frame);
575 packet->AddHeader(actionHdr);
576
577 // Use AC_VO to send management frame addressed to a QoS STA (Sec. 10.2.3.2 of 802.11-2020)
578 m_mac->GetQosTxop(AC_VO)->Queue(Create<WifiMpdu>(packet, hdr));
579}
580
581std::optional<double>
583{
584 auto optRssi = HeFrameExchangeManager::GetMostRecentRssi(address);
585
586 if (optRssi)
587 {
588 return optRssi;
589 }
590
591 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
592
593 if (!mldAddress)
594 {
595 // not an MLD, nothing else can be done
596 return std::nullopt;
597 }
598
599 for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
600 {
601 std::optional<Mac48Address> linkAddress;
602 if (linkId != m_linkId &&
603 (linkAddress = m_mac->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(
604 *mldAddress)) &&
605 (optRssi = m_mac->GetWifiRemoteStationManager(linkId)->GetMostRecentRssi(*linkAddress)))
606 {
607 return optRssi;
608 }
609 }
610
611 return std::nullopt;
612}
613
614void
616{
617 NS_LOG_FUNCTION(this << &txParams);
618
619 uint8_t maxPaddingDelay = 0;
620
621 // block transmissions on the other EMLSR links of the EMLSR clients
622 for (const auto& address : m_sentRtsTo)
623 {
624 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
625 {
626 continue;
627 }
628
629 auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
630 NS_ASSERT(emlCapabilities);
631 maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->get().emlsrPaddingDelay);
632
633 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
634 NS_ASSERT(mldAddress);
635
636 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
637 {
638 if (linkId != m_linkId &&
639 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
640 {
642 *mldAddress,
643 {linkId});
644 }
645 }
646 }
647
648 // add padding (if needed)
649 if (maxPaddingDelay > 0)
650 {
651 NS_ASSERT(txParams.m_protection &&
652 txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
653 auto protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
654 NS_ASSERT(protection->muRts.IsMuRts());
655
656 // see formula (35-1) in Sec. 35.5.2.2.3 of 802.11be D3.0
657 auto rate = protection->muRtsTxVector.GetMode().GetDataRate(protection->muRtsTxVector);
658 std::size_t nDbps = rate / 1e6 * 4; // see Table 17-4 of 802.11-2020
659 protection->muRts.SetPaddingSize((1 << (maxPaddingDelay + 2)) * nDbps / 8);
660 }
661
663}
664
665void
667 const CtrlTriggerHeader& trigger,
668 double muRtsSnr)
669{
670 NS_LOG_FUNCTION(this << muRtsHdr << trigger << muRtsSnr);
671
673 if (auto emlsrManager = m_staMac->GetEmlsrManager())
674 {
675 auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
676
677 // an aux PHY that is not TX capable may get a TXOP, release the channel and request
678 // the main PHY to switch channel. Shortly afterwards, the AP MLD may send an ICF, thus
679 // when the main PHY is scheduled to send the CTS, the main PHY may be switching channel
680 // or may be operating on another link
681 if (mainPhy->IsStateSwitching() || m_mac->GetLinkForPhy(mainPhy) != m_linkId)
682 {
683 NS_LOG_DEBUG("Main PHY is switching or operating on another link, abort sending CTS");
684 return;
685 }
686 }
687 HeFrameExchangeManager::SendCtsAfterMuRts(muRtsHdr, trigger, muRtsSnr);
688}
689
690void
692{
693 NS_LOG_FUNCTION(this << *muRts << txVector);
694
695 // we blocked transmissions on the other EMLSR links for the EMLSR clients we sent the ICF to.
696 // Given that no client responded, we can unblock transmissions for a client if there is no
697 // ongoing UL TXOP held by that client
698 for (const auto& address : m_sentRtsTo)
699 {
700 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
701 {
702 continue;
703 }
704
705 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
706 NS_ASSERT(mldAddress);
707
709 m_mac->GetMldAddress(*m_txopHolder) == mldAddress)
710 {
711 continue;
712 }
713
714 std::set<uint8_t> linkIds;
715 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
716 {
717 if (linkId != m_linkId &&
718 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
719 {
720 linkIds.insert(linkId);
721 }
722 }
724 *mldAddress,
725 linkIds);
726 }
727
729}
730
731void
733 WifiMode rtsTxMode,
734 double rtsSnr)
735{
736 NS_LOG_FUNCTION(this << rtsHdr << rtsTxMode << rtsSnr);
737
738 if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(rtsHdr.GetAddr2()))
739 {
740 // we are going to send a CTS to an EMLSR client, transmissions to such EMLSR client
741 // must be blocked on the other EMLSR links
742
743 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(rtsHdr.GetAddr2());
744 NS_ASSERT_MSG(mldAddress, "MLD address not found for " << rtsHdr.GetAddr2());
745
746 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
747 {
748 if (linkId != m_linkId &&
749 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
750 {
751 // check that other links are blocked as expected
752 WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddress, 0);
753 auto mask =
754 m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
755 NS_ASSERT_MSG(mask, "No mask for client " << *mldAddress << " on link " << +linkId);
756 if (!mask->test(
757 static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
758 {
759 NS_ASSERT_MSG(false,
760 "Transmissions to " << *mldAddress << " on link " << +linkId
761 << " are not blocked");
762 // in case asserts are disabled, block transmissions on the other links because
763 // this is what we need
765 *mldAddress,
766 {linkId});
767 }
768 }
769 }
770 }
771
772 HeFrameExchangeManager::SendCtsAfterRts(rtsHdr, rtsTxMode, rtsSnr);
773}
774
775bool
777 uint16_t aid,
778 const Mac48Address& address) const
779{
780 NS_LOG_FUNCTION(this << psdu << aid << address);
781
782 // Sec. 35.3.17 of 802.11be D3.0:
783 // The non-AP MLD shall be switched back to the listening operation on the EMLSR links after
784 // the EMLSR transition delay time if [...] the non-AP STA affiliated with the non-AP MLD
785 // does not detect [...] any of the following frames:
786 // - an individually addressed frame with the RA equal to the MAC address of the non-AP STA
787 // affiliated with the non-AP MLD
788 if (psdu->GetAddr1() == address)
789 {
790 return false;
791 }
792
793 // - a Trigger frame that has one of the User Info fields addressed to the non-AP STA
794 // affiliated with the non-AP MLD
795 for (const auto& mpdu : *PeekPointer(psdu))
796 {
797 if (mpdu->GetHeader().IsTrigger())
798 {
799 CtrlTriggerHeader trigger;
800 mpdu->GetPacket()->PeekHeader(trigger);
801 if (trigger.FindUserInfoWithAid(aid) != trigger.end())
802 {
803 return false;
804 }
805 }
806 }
807
808 // - a CTS-to-self frame with the RA equal to the MAC address of the AP affiliated with
809 // the AP MLD
810 if (psdu->GetHeader(0).IsCts())
811 {
812 if (m_apMac && psdu->GetAddr1() == m_self)
813 {
814 return false;
815 }
816 if (m_staMac && psdu->GetAddr1() == m_bssid)
817 {
818 return false;
819 }
820 }
821
822 // - a Multi-STA BlockAck frame that has one of the Per AID TID Info fields addressed to
823 // the non-AP STA affiliated with the non-AP MLD
824 if (psdu->GetHeader(0).IsBlockAck())
825 {
826 CtrlBAckResponseHeader blockAck;
827 psdu->GetPayload(0)->PeekHeader(blockAck);
828 if (blockAck.IsMultiSta() && !blockAck.FindPerAidTidInfoWithAid(aid).empty())
829 {
830 return false;
831 }
832 }
833
834 // - a NDP Announcement frame that has one of the STA Info fields addressed to the non-AP
835 // STA affiliated with the non-AP MLD and a sounding NDP
836 // TODO NDP Announcement frame not supported yet
837
838 return true;
839}
840
841void
843{
844 NS_LOG_FUNCTION(this);
845
847 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
848 {
849 NS_LOG_DEBUG("Reset the counter of TXOP attempts allowed while "
850 "MediumSyncDelay is running");
851 m_staMac->GetEmlsrManager()->ResetMediumSyncDelayNTxops(m_linkId);
852 }
853
855}
856
857void
859{
860 NS_LOG_FUNCTION(this);
861
863 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
864 {
865 NS_LOG_DEBUG("Decrement the remaining number of TXOP attempts allowed while "
866 "MediumSyncDelay is running");
867 m_staMac->GetEmlsrManager()->DecrementMediumSyncDelayNTxops(m_linkId);
868 }
869
871}
872
873void
875{
876 NS_LOG_FUNCTION(this << txop);
877
878 if (m_apMac)
879 {
880 // the channel has been released; all EMLSR clients are switching back to
881 // listening operation
882 for (const auto& address : m_protectedStas)
883 {
884 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
885 {
886 EmlsrSwitchToListening(address, Seconds(0));
887 }
888 }
889 }
891 {
892 // Notify the UL TXOP end to the EMLSR Manager
893 auto edca = DynamicCast<QosTxop>(txop);
894 NS_ASSERT(edca);
895 auto txopStart = edca->GetTxopStartTime(m_linkId);
896
898 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId,
899 (!txopStart || *txopStart == Simulator::Now()),
901 }
902
904}
905
906void
908{
909 NS_LOG_FUNCTION(this << psdu << txVector);
910
911 // In addition, the timer resets to zero when any of the following events occur:
912 // — The STA receives an MPDU
913 // (Sec. 35.3.16.8.1 of 802.11be D3.1)
915 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
916 {
917 m_staMac->GetEmlsrManager()->CancelMediumSyncDelayTimer(m_linkId);
918 }
919
920 if (m_apMac)
921 {
922 // we iterate over protected STAs to consider only the case when the AP is the TXOP holder.
923 // The AP received a PSDU from a non-AP STA; given that the AP is the TXOP holder, this
924 // PSDU has been likely solicited by the AP. In most of the cases, we identify which EMLSR
925 // clients are no longer involved in the TXOP when the AP transmits the frame soliciting
926 // response(s) from client(s). This is not the case, for example, for the acknowledgment
927 // in SU format of a DL MU PPDU, where all the EMLSR clients (but one) switch to listening
928 // operation after the immediate response (if any) by one of the EMLSR clients.
929 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
930 {
931 // TB PPDUs are received by the AP at distinct times, so it is difficult to take a
932 // decision based on one of them. However, clients transmitting TB PPDUs are identified
933 // by the soliciting Trigger Frame, thus we have already identified (when sending the
934 // Trigger Frame) which EMLSR clients have switched to listening operation.
935 // If the PSDU is not carried in a TB PPDU, we can determine whether this EMLSR client
936 // is switching to listening operation by checking whether the AP is expecting a
937 // response from it.
938 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) && !txVector.IsUlMu() &&
939 !m_txTimer.GetStasExpectedToRespond().contains(*clientIt))
940 {
941 EmlsrSwitchToListening(*clientIt, Seconds(0));
942 // this client is no longer involved in the current TXOP
943 clientIt = m_protectedStas.erase(clientIt);
944 }
945 else
946 {
947 clientIt++;
948 }
949 }
950 }
951
953}
954
955void
957{
958 NS_LOG_FUNCTION(this << psdu << txVector);
959
961
962 if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
963 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
964 {
966 {
967 // an EMLSR client has started an UL TXOP. Start the ongoingTxopEnd timer so that
968 // the next call to UpdateTxopEndOnRxEnd does its job
971 }
972
973 UpdateTxopEndOnRxEnd(psdu->GetDuration());
974 }
975
977 {
979 {
980 // we are no longer involved in the TXOP and switching to listening mode
982 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
983 }
984 else
985 {
986 UpdateTxopEndOnRxEnd(psdu->GetDuration());
987 }
988 }
989}
990
991bool
993 const WifiTxVector& txVector)
994{
995 NS_LOG_FUNCTION(this);
996
997 auto sender = hdr.GetAddr2();
998
1000 {
1001 NS_LOG_DEBUG("A TXOP is already ongoing");
1002 return false;
1003 }
1004
1005 if (auto holder = FindTxopHolder(hdr, txVector); holder != sender)
1006 {
1007 NS_LOG_DEBUG("Sender (" << sender << ") differs from the TXOP holder ("
1008 << (holder ? Address(*holder) : Address()) << ")");
1009 return false;
1010 }
1011
1012 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(sender))
1013 {
1014 NS_LOG_DEBUG("Sender (" << sender << ") is not an EMLSR client");
1015 return false;
1016 }
1017
1018 NS_LOG_DEBUG("EMLSR client " << sender << " is starting a TXOP");
1019
1020 // Block transmissions for this EMLSR client on other links
1021 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(sender);
1022 NS_ASSERT(mldAddress);
1023
1024 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
1025 {
1026 if (linkId != m_linkId &&
1027 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
1028 {
1030 *mldAddress,
1031 {linkId});
1032 }
1033 }
1034
1035 // Make sure that transmissions for this EMLSR client are not blocked on this link
1036 // (the AP MLD may have sent an ICF on another link right before receiving this MPDU,
1037 // thus transmissions on this link may have been blocked)
1039 *mldAddress,
1040 {m_linkId});
1041
1042 // Stop the transition delay timer for this EMLSR client, if any is running
1043 if (auto it = m_transDelayTimer.find(*mldAddress);
1044 it != m_transDelayTimer.end() && it->second.IsPending())
1045 {
1046 it->second.PeekEventImpl()->Invoke();
1047 it->second.Cancel();
1048 }
1049
1050 return true;
1051}
1052
1053void
1055 RxSignalInfo rxSignalInfo,
1056 const WifiTxVector& txVector,
1057 bool inAmpdu)
1058{
1059 // The received MPDU is either broadcast or addressed to this station
1060 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1061
1062 const auto& hdr = mpdu->GetHeader();
1063
1064 if (m_apMac)
1065 {
1066 // if the AP MLD received an MPDU from an EMLSR client that is starting an UL TXOP,
1067 // block transmissions to the EMLSR client on other links
1068 CheckEmlsrClientStartingTxop(hdr, txVector);
1069 }
1070
1071 bool icfReceived = false;
1072
1073 if (hdr.IsTrigger())
1074 {
1075 if (!m_staMac)
1076 {
1077 return; // Trigger Frames are only processed by STAs
1078 }
1079
1080 CtrlTriggerHeader trigger;
1081 mpdu->GetPacket()->PeekHeader(trigger);
1082
1083 if (hdr.GetAddr1() != m_self &&
1084 (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
1085 hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with
1086 || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end()))
1087 {
1088 return; // not addressed to us
1089 }
1090
1091 if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId))
1092 {
1093 // this is an initial Control frame
1094 if (UsingOtherEmlsrLink())
1095 {
1096 // we received an ICF on a link that is blocked because another EMLSR link is
1097 // being used. This is likely because transmission on the other EMLSR link
1098 // started before the reception of the ICF ended. We drop this ICF and let the
1099 // UL TXOP continue.
1100 NS_LOG_DEBUG("Drop ICF because another EMLSR link is being used");
1101 return;
1102 }
1103
1104 /**
1105 * It might happen that, while the aux PHY is receiving an ICF, the main PHY is
1106 * completing a TXOP on another link or is returning to the primary link after a TXOP
1107 * is completed on another link. In order to respond to the ICF, it is necessary that
1108 * the main PHY has enough time to switch and be ready to operate on this link by the
1109 * end of the ICF padding.
1110 *
1111 * TXOP end
1112 * │
1113 * ┌───┐ another
1114 * AP MLD │ACK│ link
1115 * ───────────┬─────────┬┴───┴───────────────────────────────────────
1116 * EMLSR │ QoS │ │ main PHY
1117 * client │ Data │ │
1118 * └─────────┘ │
1119 * ┌─────┬───┐ this
1120 * AP MLD │ ICF │pad│ link
1121 * ────────────────────┴─────┴───┴───────────────────────────────────
1122 * aux PHY
1123 */
1124
1125 auto emlsrManager = m_staMac->GetEmlsrManager();
1126 NS_ASSERT(emlsrManager);
1127
1128 if (auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
1129 mainPhy != m_phy)
1130 {
1131 const auto delay = mainPhy->GetChannelSwitchDelay();
1132
1133 if (mainPhy->GetState()->GetLastTime({WifiPhyState::TX,
1134 // WifiPhyState::RX, comment out for now
1135 WifiPhyState::SWITCHING,
1136 WifiPhyState::SLEEP}) >
1137 Simulator::Now() - delay)
1138 {
1139 NS_LOG_DEBUG("Drop ICF due to not enough time for the main PHY to switch link");
1140 return;
1141 }
1142 }
1143
1144 emlsrManager->NotifyIcfReceived(m_linkId);
1145 icfReceived = true;
1146
1147 // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
1148 // SIFS (we are expected to reply by sending a CTS frame)
1150 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
1153 this,
1154 hdr.GetAddr2());
1155 }
1156 }
1157
1158 // We impose that an aux PHY is only able to receive an ICF, a CTS or a management frame
1159 // (we are interested in receiving mainly Beacon frames). Note that other frames are still
1160 // post-processed, e.g., used to set the NAV and the TXOP holder.
1161 // The motivation is that, e.g., an AP MLD may send an ICF to EMLSR clients A and B;
1162 // A responds while B does not; the AP MLD sends a DL MU PPDU to both clients followed
1163 // by an MU-BAR to solicit a BlockAck from both clients. If an aux PHY of client B is
1164 // operating on this link, the MU-BAR will be received and a TB PPDU response sent
1165 // through the aux PHY.
1167 m_mac->GetLinkForPhy(m_staMac->GetEmlsrManager()->GetMainPhyId()) != m_linkId &&
1168 !icfReceived && !mpdu->GetHeader().IsCts() && !mpdu->GetHeader().IsMgt())
1169 {
1170 NS_LOG_DEBUG("Dropping " << *mpdu << " received by an aux PHY on link " << +m_linkId);
1171 return;
1172 }
1173
1174 HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1175}
1176
1177void
1178EhtFrameExchangeManager::TxopEnd(const std::optional<Mac48Address>& txopHolder)
1179{
1180 NS_LOG_FUNCTION(this << txopHolder.has_value());
1181
1183 {
1184 // we may get here because the PHY has not issued the PHY-RXSTART.indication before
1185 // the expiration of the timer started to detect new received frames, but the PHY is
1186 // currently decoding the PHY header of a PPDU, so let's wait some more time to check
1187 // if we receive a PHY-RXSTART.indication when the PHY is done decoding the PHY header
1188 NS_LOG_DEBUG("PHY is decoding the PHY header of PPDU, postpone TXOP end");
1191 this,
1192 txopHolder);
1193 return;
1194 }
1195
1197 {
1198 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
1199 }
1200 else if (m_apMac && txopHolder && GetWifiRemoteStationManager()->GetEmlsrEnabled(*txopHolder))
1201 {
1202 // EMLSR client terminated its TXOP and is back to listening operation
1203 EmlsrSwitchToListening(*txopHolder, Seconds(0));
1204 }
1205}
1206
1207void
1209{
1210 NS_LOG_FUNCTION(this << txDuration.As(Time::MS) << durationId.As(Time::US));
1211
1213 {
1214 // nothing to do
1215 return;
1216 }
1217
1219 Time delay;
1220
1221 if (m_txTimer.IsRunning())
1222 {
1223 // the TX timer is running, hence we are expecting a response. Postpone the TXOP end
1224 // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
1225 // the response)
1226 delay = m_txTimer.GetDelayLeft();
1227 }
1228 else if (durationId <= m_phy->GetSifs())
1229 {
1230 // the TX timer is not running, hence no response is expected, and the Duration/ID value
1231 // is less than or equal to a SIFS; the TXOP will end after this transmission
1232 NS_LOG_DEBUG("Assume TXOP will end based on Duration/ID value");
1233 delay = txDuration;
1234 }
1235 else
1236 {
1237 // the TX Timer is not running, hence no response is expected (e.g., we are
1238 // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
1239 // after the end of this PPDU, hence we need to postpone the TXOP end in order to
1240 // get the PHY-RXSTART.indication
1241 delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1243 }
1244
1245 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1248}
1249
1250void
1252{
1253 NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
1254
1255 if (!m_ongoingTxopEnd.IsPending() || !psduDuration.IsStrictlyPositive())
1256 {
1257 // nothing to do
1258 return;
1259 }
1260
1261 // postpone the TXOP end until after the reception of the PSDU is completed
1263
1264 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
1267 this,
1268 m_txopHolder);
1269}
1270
1271void
1273{
1274 NS_LOG_FUNCTION(this << durationId.As(Time::US));
1275
1277 {
1278 // nothing to do
1279 return;
1280 }
1281
1283
1284 // if the Duration/ID of the received frame is less than a SIFS, the TXOP
1285 // is terminated
1286 if (durationId <= m_phy->GetSifs())
1287 {
1288 NS_LOG_DEBUG("Assume TXOP ended based on Duration/ID value");
1290 return;
1291 }
1292
1293 // we may send a response after a SIFS or we may receive another frame after a SIFS.
1294 // Postpone the TXOP end by considering the latter (which takes longer)
1296 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1299}
1300
1301} // namespace ns3
a polymophic address class
Definition: address.h:101
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 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 SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr) override
Send CTS after receiving an MU-RTS.
void UpdateTxopEndOnRxEnd(Time durationId)
Update the TXOP end timer when a frame reception ends.
bool CheckEmlsrClientStartingTxop(const WifiMacHeader &hdr, const WifiTxVector &txVector)
Check if the frame received (or being received) is sent by an EMLSR client to start an UL TXOP.
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 SendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiMode rtsTxMode, double rtsSnr) override
Send CTS after receiving RTS.
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 TxopEnd(const std::optional< Mac48Address > &txopHolder)
Take actions when a TXOP (of which we are not the holder) ends.
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 IsPending() 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
virtual void TransmissionFailed()
Take necessary actions upon a transmission failure.
WifiTxTimer m_txTimer
the timer set upon frame transmission
virtual void SendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiMode rtsTxMode, double rtsSnr)
Send CTS after receiving RTS.
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
virtual void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual bool StartTransmission(Ptr< Txop > dcf, uint16_t allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
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
std::optional< Mac48Address > FindTxopHolder(const WifiMacHeader &hdr, const WifiTxVector &txVector) override
Determine the holder of the TXOP, if possible, based on the received frame.
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.
virtual void SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr)
Send CTS after receiving an MU-RTS.
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.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
std::optional< Mac48Address > m_txopHolder
MAC address of the TXOP holder.
virtual Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
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
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
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
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:703
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition: txop.h:424
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:623
static constexpr bool DONT_CHECK_MEDIUM_BUSY
generation of backoff is independent of the busy/idle state of the medium
Definition: txop.h:428
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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.
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.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
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.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition: wifi-mac.cc:981
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1774
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:670
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:1072
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:1558
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:1512
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:483
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:1113
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:1045
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:593
represent a single transmission mode
Definition: wifi-mode.h:51
Ptr< WifiPhy > GetPhy() const
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:825
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:813
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1539
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1053
bool IsReceivingPhyHeader() const
Definition: wifi-phy.cc:1954
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:744
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:1343
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1355
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
@ 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
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:454
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:105
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:113
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