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 std::optional<Time> timeToCtsEnd;
181
183 {
184 // Cannot start a transmission on a link blocked because another EMLSR link is being used
186 {
187 NS_LOG_DEBUG("StartTransmission called while another EMLSR link is being used");
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
209 return false;
210 }
211
212 if (!m_phy)
213 {
214 NS_LOG_DEBUG("No PHY is currently operating on EMLSR link " << +m_linkId);
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");
227 return false;
228 }
229
230 if (mainPhy->IsStateRx())
231 {
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.
242 return false;
243 }
244
245 const auto rtsTxVector =
246 GetWifiRemoteStationManager()->GetRtsTxVector(m_bssid, allowedWidth);
247 const auto rtsTxTime =
249 const auto ctsTxVector =
250 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, rtsTxVector.GetMode());
251 const auto ctsTxTime =
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");
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
292void
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
333void
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
368void
370{
371 NS_LOG_FUNCTION(this);
373 {
374 // the CTS may have been missed because another EMLSR link is being used; do not reset NAV
375 return;
376 }
378}
379
380void
382{
383 NS_LOG_FUNCTION(this);
385 {
386 // the CTS may have been missed because another EMLSR link is being used; do not reset NAV
387 return;
388 }
390}
391
392void
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
435 emlCapabilities->get().emlsrTransitionDelay);
436
437 endDelay.IsZero() ? unblockLinks()
438 : static_cast<void>(m_transDelayTimer[*mldAddress] =
439 Simulator::Schedule(endDelay, unblockLinks));
440}
441
442void
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
465void
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
495std::optional<double>
497{
498 auto optRssi = HeFrameExchangeManager::GetMostRecentRssi(address);
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
528void
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
579void
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 std::set<uint8_t> linkIds;
604 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
605 {
606 if (linkId != m_linkId &&
607 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
608 {
609 linkIds.insert(linkId);
610 }
611 }
613 *mldAddress,
614 linkIds);
615 }
616
618}
619
620bool
622 uint16_t aid,
623 const Mac48Address& address) const
624{
625 NS_LOG_FUNCTION(this << psdu << aid << address);
626
627 // Sec. 35.3.17 of 802.11be D3.0:
628 // The non-AP MLD shall be switched back to the listening operation on the EMLSR links after
629 // the EMLSR transition delay time if [...] the non-AP STA affiliated with the non-AP MLD
630 // does not detect [...] any of the following frames:
631 // - an individually addressed frame with the RA equal to the MAC address of the non-AP STA
632 // affiliated with the non-AP MLD
633 if (psdu->GetAddr1() == address)
634 {
635 return false;
636 }
637
638 // - a Trigger frame that has one of the User Info fields addressed to the non-AP STA
639 // affiliated with the non-AP MLD
640 for (const auto& mpdu : *PeekPointer(psdu))
641 {
642 if (mpdu->GetHeader().IsTrigger())
643 {
644 CtrlTriggerHeader trigger;
645 mpdu->GetPacket()->PeekHeader(trigger);
646 if (trigger.FindUserInfoWithAid(aid) != trigger.end())
647 {
648 return false;
649 }
650 }
651 }
652
653 // - a CTS-to-self frame with the RA equal to the MAC address of the AP affiliated with
654 // the AP MLD
655 if (psdu->GetHeader(0).IsCts())
656 {
657 if (m_apMac && psdu->GetAddr1() == m_self)
658 {
659 return false;
660 }
661 if (m_staMac && psdu->GetAddr1() == m_bssid)
662 {
663 return false;
664 }
665 }
666
667 // - a Multi-STA BlockAck frame that has one of the Per AID TID Info fields addressed to
668 // the non-AP STA affiliated with the non-AP MLD
669 if (psdu->GetHeader(0).IsBlockAck())
670 {
671 CtrlBAckResponseHeader blockAck;
672 psdu->GetPayload(0)->PeekHeader(blockAck);
673 if (blockAck.IsMultiSta() && !blockAck.FindPerAidTidInfoWithAid(aid).empty())
674 {
675 return false;
676 }
677 }
678
679 // - a NDP Announcement frame that has one of the STA Info fields addressed to the non-AP
680 // STA affiliated with the non-AP MLD and a sounding NDP
681 // TODO NDP Announcement frame not supported yet
682
683 return true;
684}
685
686void
688{
689 NS_LOG_FUNCTION(this);
690
692 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
693 {
694 NS_LOG_DEBUG("Reset the counter of TXOP attempts allowed while "
695 "MediumSyncDelay is running");
696 m_staMac->GetEmlsrManager()->ResetMediumSyncDelayNTxops(m_linkId);
697 }
698
700}
701
702void
704{
705 NS_LOG_FUNCTION(this);
706
708 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
709 {
710 NS_LOG_DEBUG("Decrement the remaining number of TXOP attempts allowed while "
711 "MediumSyncDelay is running");
712 m_staMac->GetEmlsrManager()->DecrementMediumSyncDelayNTxops(m_linkId);
713 }
714
716}
717
718void
720{
721 NS_LOG_FUNCTION(this << txop);
722
723 if (m_apMac)
724 {
725 // the channel has been released; all EMLSR clients are switching back to
726 // listening operation
727 for (const auto& address : m_protectedStas)
728 {
729 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
730 {
731 EmlsrSwitchToListening(address, Seconds(0));
732 }
733 }
734 }
736 {
737 // notify the EMLSR Manager of the UL TXOP end, if the TXOP included the transmission of
738 // at least a frame
740 auto edca = DynamicCast<QosTxop>(txop);
741 NS_ASSERT(edca);
742 if (auto txopStart = edca->GetTxopStartTime(m_linkId);
743 txopStart && Simulator::Now() > *txopStart)
744 {
745 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
746 }
747 }
748
750}
751
752void
754{
755 NS_LOG_FUNCTION(this << psdu << txVector);
756
757 // In addition, the timer resets to zero when any of the following events occur:
758 // — The STA receives an MPDU
759 // (Sec. 35.3.16.8.1 of 802.11be D3.1)
761 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
762 {
763 m_staMac->GetEmlsrManager()->CancelMediumSyncDelayTimer(m_linkId);
764 }
765
766 if (m_apMac)
767 {
768 // we iterate over protected STAs to consider only the case when the AP is the TXOP holder.
769 // The AP received a PSDU from a non-AP STA; given that the AP is the TXOP holder, this
770 // PSDU has been likely solicited by the AP. In most of the cases, we identify which EMLSR
771 // clients are no longer involved in the TXOP when the AP transmits the frame soliciting
772 // response(s) from client(s). This is not the case, for example, for the acknowledgment
773 // in SU format of a DL MU PPDU, where all the EMLSR clients (but one) switch to listening
774 // operation after the immediate response (if any) by one of the EMLSR clients.
775 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
776 {
777 // TB PPDUs are received by the AP at distinct times, so it is difficult to take a
778 // decision based on one of them. However, clients transmitting TB PPDUs are identified
779 // by the soliciting Trigger Frame, thus we have already identified (when sending the
780 // Trigger Frame) which EMLSR clients have switched to listening operation.
781 // If the PSDU is not carried in a TB PPDU, we can determine whether this EMLSR client
782 // is switching to listening operation by checking whether the AP is expecting a
783 // response from it.
784 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) && !txVector.IsUlMu() &&
785 !m_txTimer.GetStasExpectedToRespond().contains(*clientIt))
786 {
787 EmlsrSwitchToListening(*clientIt, Seconds(0));
788 // this client is no longer involved in the current TXOP
789 clientIt = m_protectedStas.erase(clientIt);
790 }
791 else
792 {
793 clientIt++;
794 }
795 }
796 }
797
799}
800
801void
803{
804 NS_LOG_FUNCTION(this << psdu << txVector);
805
807
808 if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
809 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
810 {
812 {
813 // an EMLSR client has started an UL TXOP. We may send a response after a SIFS or
814 // we may receive another frame after a SIFS. Postpone the TXOP end by considering
815 // the latter (which takes longer)
816 auto delay =
818 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
820 }
821 else
822 {
823 UpdateTxopEndOnRxEnd(psdu->GetDuration());
824 }
825 }
826
828 {
830 {
831 // we are no longer involved in the TXOP and switching to listening mode
833 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
834 }
835 else
836 {
837 UpdateTxopEndOnRxEnd(psdu->GetDuration());
838 }
839 }
840}
841
842void
844 RxSignalInfo rxSignalInfo,
845 const WifiTxVector& txVector,
846 bool inAmpdu)
847{
848 // The received MPDU is either broadcast or addressed to this station
849 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
850
851 const auto& hdr = mpdu->GetHeader();
852
853 if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr2()))
854 {
855 // the AP MLD received an MPDU from an EMLSR client, which is now involved in an UL TXOP,
856 // hence block transmissions for this EMLSR client on other links
857 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(hdr.GetAddr2());
858 NS_ASSERT(mldAddress);
859
860 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
861 {
862 if (linkId != m_linkId &&
863 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
864 {
866 *mldAddress,
867 {linkId});
868 }
869 }
870
871 // Make sure that transmissions for this EMLSR client are not blocked on this link
872 // (the AP MLD may have sent an ICF on another link right before receiving this MPDU,
873 // thus transmissions on this link may have been blocked)
875 *mldAddress,
876 {m_linkId});
877
878 // Stop the transition delay timer for this EMLSR client, if any is running
879 if (auto it = m_transDelayTimer.find(*mldAddress);
880 it != m_transDelayTimer.end() && it->second.IsRunning())
881 {
882 it->second.PeekEventImpl()->Invoke();
883 it->second.Cancel();
884 }
885 }
886
887 bool icfReceived = false;
888
889 if (hdr.IsTrigger())
890 {
891 if (!m_staMac)
892 {
893 return; // Trigger Frames are only processed by STAs
894 }
895
896 CtrlTriggerHeader trigger;
897 mpdu->GetPacket()->PeekHeader(trigger);
898
899 if (hdr.GetAddr1() != m_self &&
900 (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
901 hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with
902 || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end()))
903 {
904 return; // not addressed to us
905 }
906
907 if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId))
908 {
909 // this is an initial Control frame
911 {
912 // we received an ICF on a link that is blocked because another EMLSR link is
913 // being used. This is likely because transmission on the other EMLSR link
914 // started before the reception of the ICF ended. We drop this ICF and let the
915 // UL TXOP continue.
916 NS_LOG_DEBUG("Drop ICF because another EMLSR link is being used");
917 return;
918 }
919
920 /**
921 * It might happen that the AP MLD has not yet received a data frame being transmitted
922 * by us on another link and starts sending an ICF on this link. The transmission of
923 * the ICF might be long enough to terminate after the subsequent acknowledgment, which
924 * terminates the TXOP on the other link. Consequently, no TXOP is ongoing when the
925 * reception of the ICF ends, hence the ICF is not dropped and a DL TXOP can start on
926 * this link. However, even if the aux PHY is able to receive the ICF, we need to allow
927 * enough time for the main PHY to switch to this link. Therefore, we assume that the
928 * ICF is successfully received (by an aux PHY) if the TXOP on the other link ended
929 * before the padding of the ICF. In order to determine when the TXOP ended, we can
930 * determine when the medium sync delay timer started on this link.
931 *
932 * TXOP end
933 * │
934 * ┌───┐ another
935 * AP MLD │ACK│ link
936 * ───────────┬─────────┬┴───┴───────────────────────────────────────
937 * EMLSR │ QoS │ │ main PHY
938 * client │ Data │ │
939 * └─────────┘ │
940 * │- medium sync delay timer -│
941 * ┌─────┬───┐ this
942 * AP MLD │ ICF │pad│ link
943 * ────────────────────┴─────┴───┴───────────────────────────────────
944 * aux PHY
945 */
946
947 if (auto elapsed =
948 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
949 {
950 TimeValue padding;
951 m_staMac->GetEmlsrManager()->GetAttribute("EmlsrPaddingDelay", padding);
952
953 if (*elapsed < padding.Get())
954 {
955 NS_LOG_DEBUG("Drop ICF due to not enough time for the main PHY to switch link");
956 return;
957 }
958 }
959
961 m_staMac->GetEmlsrManager()->NotifyIcfReceived(m_linkId);
962 icfReceived = true;
963
964 // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
965 // SIFS (we are expected to reply by sending a CTS frame)
967 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
970 this);
971 }
972 }
973
974 // We impose that an aux PHY is only able to receive an ICF, a CTS or a management frame
975 // (we are interested in receiving mainly Beacon frames). Note that other frames are still
976 // post-processed, e.g., used to set the NAV and the TXOP holder.
977 // The motivation is that, e.g., an AP MLD may send an ICF to EMLSR clients A and B;
978 // A responds while B does not; the AP MLD sends a DL MU PPDU to both clients followed
979 // by an MU-BAR to solicit a BlockAck from both clients. If an aux PHY of client B is
980 // operating on this link, the MU-BAR will be received and a TB PPDU response sent
981 // through the aux PHY.
983 m_mac->GetLinkForPhy(m_staMac->GetEmlsrManager()->GetMainPhyId()) != m_linkId &&
984 !icfReceived && !mpdu->GetHeader().IsCts() && !mpdu->GetHeader().IsMgt())
985 {
986 NS_LOG_DEBUG("Dropping " << *mpdu << " received by an aux PHY on link " << +m_linkId);
987 return;
988 }
989
990 HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
991}
992
993void
995{
996 NS_LOG_FUNCTION(this);
997
999 {
1000 // we may get here because the PHY has not issued the PHY-RXSTART.indication before
1001 // the expiration of the timer started to detect new received frames, but the PHY is
1002 // currently decoding the PHY header of a PPDU, so let's wait some more time to check
1003 // if we receive a PHY-RXSTART.indication when the PHY is done decoding the PHY header
1004 NS_LOG_DEBUG("PHY is decoding the PHY header of PPDU, postpone TXOP end");
1007 this);
1008 return;
1009 }
1010
1012 {
1013 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
1014 }
1015 else if (m_apMac && m_txopHolder &&
1016 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
1017 {
1018 // EMLSR client terminated its TXOP and is back to listening operation
1020 }
1021}
1022
1023void
1025{
1026 NS_LOG_FUNCTION(this << txDuration.As(Time::MS) << durationId.As(Time::US));
1027
1029 {
1030 // nothing to do
1031 return;
1032 }
1033
1035 Time delay;
1036
1037 if (m_txTimer.IsRunning())
1038 {
1039 // the TX timer is running, hence we are expecting a response. Postpone the TXOP end
1040 // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
1041 // the response)
1042 delay = m_txTimer.GetDelayLeft();
1043 }
1044 else if (durationId <= m_phy->GetSifs())
1045 {
1046 // the TX timer is not running, hence no response is expected, and the Duration/ID value
1047 // is less than or equal to a SIFS; the TXOP will end after this transmission
1048 NS_LOG_DEBUG("Assume TXOP will end based on Duration/ID value");
1049 delay = txDuration;
1050 }
1051 else
1052 {
1053 // the TX Timer is not running, hence no response is expected (e.g., we are
1054 // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
1055 // after the end of this PPDU, hence we need to postpone the TXOP end in order to
1056 // get the PHY-RXSTART.indication
1057 delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1059 }
1060
1061 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1063}
1064
1065void
1067{
1068 NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
1069
1070 if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
1071 {
1072 // nothing to do
1073 return;
1074 }
1075
1076 // postpone the TXOP end until after the reception of the PSDU is completed
1078
1079 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
1082}
1083
1084void
1086{
1087 NS_LOG_FUNCTION(this << durationId.As(Time::US));
1088
1090 {
1091 // nothing to do
1092 return;
1093 }
1094
1096
1097 // if the Duration/ID of the received frame is less than a SIFS, the TXOP
1098 // is terminated
1099 if (durationId <= m_phy->GetSifs())
1100 {
1101 NS_LOG_DEBUG("Assume TXOP ended based on Duration/ID value");
1102 TxopEnd();
1103 return;
1104 }
1105
1106 // we may send a response after a SIFS or we may receive another frame after a SIFS.
1107 // Postpone the TXOP end by considering the latter (which takes longer)
1109 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1111}
1112
1113} // namespace ns3
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
virtual void TransmissionFailed()
Take necessary actions upon a transmission failure.
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
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
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.
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
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
AttributeValue implementation for Time.
Definition: nstime.h:1406
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:602
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:522
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.
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:1663
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:590
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:947
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:1447
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:1401
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:453
std::optional< uint8_t > GetLinkForPhy(Ptr< const WifiPhy > phy) const
Get the ID of the link (if any) on which the given PHY is operating.
Definition: wifi-mac.cc:988
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:920
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:513
Ptr< WifiPhy > GetPhy() const
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:815
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:803
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1529
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1043
bool IsReceivingPhyHeader() const
Definition: wifi-phy.cc:1923
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:734
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: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
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