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
41static constexpr uint8_t RX_PHY_START_DELAY_USEC = 20;
42
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 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
604 {
605 if (linkId != m_linkId &&
606 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
607 {
609 *mldAddress,
610 {linkId});
611 }
612 }
613 }
614
616}
617
618bool
620 uint16_t aid,
621 const Mac48Address& address) const
622{
623 NS_LOG_FUNCTION(this << psdu << aid << address);
624
625 // Sec. 35.3.17 of 802.11be D3.0:
626 // The non-AP MLD shall be switched back to the listening operation on the EMLSR links after
627 // the EMLSR transition delay time if [...] the non-AP STA affiliated with the non-AP MLD
628 // does not detect [...] any of the following frames:
629 // - an individually addressed frame with the RA equal to the MAC address of the non-AP STA
630 // affiliated with the non-AP MLD
631 if (psdu->GetAddr1() == address)
632 {
633 return false;
634 }
635
636 // - a Trigger frame that has one of the User Info fields addressed to the non-AP STA
637 // affiliated with the non-AP MLD
638 for (const auto& mpdu : *PeekPointer(psdu))
639 {
640 if (mpdu->GetHeader().IsTrigger())
641 {
642 CtrlTriggerHeader trigger;
643 mpdu->GetPacket()->PeekHeader(trigger);
644 if (trigger.FindUserInfoWithAid(aid) != trigger.end())
645 {
646 return false;
647 }
648 }
649 }
650
651 // - a CTS-to-self frame with the RA equal to the MAC address of the AP affiliated with
652 // the AP MLD
653 if (psdu->GetHeader(0).IsCts())
654 {
655 if (m_apMac && psdu->GetAddr1() == m_self)
656 {
657 return false;
658 }
659 if (m_staMac && psdu->GetAddr1() == m_bssid)
660 {
661 return false;
662 }
663 }
664
665 // - a Multi-STA BlockAck frame that has one of the Per AID TID Info fields addressed to
666 // the non-AP STA affiliated with the non-AP MLD
667 if (psdu->GetHeader(0).IsBlockAck())
668 {
669 CtrlBAckResponseHeader blockAck;
670 psdu->GetPayload(0)->PeekHeader(blockAck);
671 if (blockAck.IsMultiSta() && !blockAck.FindPerAidTidInfoWithAid(aid).empty())
672 {
673 return false;
674 }
675 }
676
677 // - a NDP Announcement frame that has one of the STA Info fields addressed to the non-AP
678 // STA affiliated with the non-AP MLD and a sounding NDP
679 // TODO NDP Announcement frame not supported yet
680
681 return true;
682}
683
684void
686{
687 NS_LOG_FUNCTION(this);
688
690 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
691 {
692 NS_LOG_DEBUG("Reset the counter of TXOP attempts allowed while "
693 "MediumSyncDelay is running");
694 m_staMac->GetEmlsrManager()->ResetMediumSyncDelayNTxops(m_linkId);
695 }
696
698}
699
700void
702{
703 NS_LOG_FUNCTION(this);
704
706 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
707 {
708 NS_LOG_DEBUG("Decrement the remaining number of TXOP attempts allowed while "
709 "MediumSyncDelay is running");
710 m_staMac->GetEmlsrManager()->DecrementMediumSyncDelayNTxops(m_linkId);
711 }
712
714}
715
716void
718{
719 NS_LOG_FUNCTION(this << txop);
720
721 if (m_apMac)
722 {
723 // the channel has been released; all EMLSR clients are switching back to
724 // listening operation
725 for (const auto& address : m_protectedStas)
726 {
727 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
728 {
729 EmlsrSwitchToListening(address, Seconds(0));
730 }
731 }
732 }
734 {
735 // notify the EMLSR Manager of the UL TXOP end, if the TXOP included the transmission of
736 // at least a frame
738 auto edca = DynamicCast<QosTxop>(txop);
739 NS_ASSERT(edca);
740 if (auto txopStart = edca->GetTxopStartTime(m_linkId);
741 txopStart && Simulator::Now() > *txopStart)
742 {
743 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
744 }
745 }
746
748}
749
750void
752{
753 NS_LOG_FUNCTION(this << psdu << txVector);
754
755 // In addition, the timer resets to zero when any of the following events occur:
756 // — The STA receives an MPDU
757 // (Sec. 35.3.16.8.1 of 802.11be D3.1)
759 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
760 {
761 m_staMac->GetEmlsrManager()->CancelMediumSyncDelayTimer(m_linkId);
762 }
763
764 if (m_apMac)
765 {
766 // we iterate over protected STAs to consider only the case when the AP is the TXOP holder.
767 // The AP received a PSDU from a non-AP STA; given that the AP is the TXOP holder, this
768 // PSDU has been likely solicited by the AP. In most of the cases, we identify which EMLSR
769 // clients are no longer involved in the TXOP when the AP transmits the frame soliciting
770 // response(s) from client(s). This is not the case, for example, for the acknowledgment
771 // in SU format of a DL MU PPDU, where all the EMLSR clients (but one) switch to listening
772 // operation after the immediate response (if any) by one of the EMLSR clients.
773 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
774 {
775 // TB PPDUs are received by the AP at distinct times, so it is difficult to take a
776 // decision based on one of them. However, clients transmitting TB PPDUs are identified
777 // by the soliciting Trigger Frame, thus we have already identified (when sending the
778 // Trigger Frame) which EMLSR clients have switched to listening operation.
779 // If the PSDU is not carried in a TB PPDU, we can determine whether this EMLSR client
780 // is switching to listening operation by checking whether the AP is expecting a
781 // response from it.
782 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) && !txVector.IsUlMu() &&
783 m_txTimer.GetStasExpectedToRespond().count(*clientIt) == 0)
784 {
785 EmlsrSwitchToListening(*clientIt, Seconds(0));
786 // this client is no longer involved in the current TXOP
787 clientIt = m_protectedStas.erase(clientIt);
788 }
789 else
790 {
791 clientIt++;
792 }
793 }
794 }
795
797}
798
799void
801{
802 NS_LOG_FUNCTION(this << psdu << txVector);
803
805
806 if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
807 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
808 {
810 {
811 // an EMLSR client has started an UL TXOP. We may send a response after a SIFS or
812 // we may receive another frame after a SIFS. Postpone the TXOP end by considering
813 // the latter (which takes longer)
814 auto delay =
816 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
818 }
819 else
820 {
821 UpdateTxopEndOnRxEnd(psdu->GetDuration());
822 }
823 }
824
826 {
828 {
829 // we are no longer involved in the TXOP and switching to listening mode
831 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
832 }
833 else
834 {
835 UpdateTxopEndOnRxEnd(psdu->GetDuration());
836 }
837 }
838}
839
840void
842 RxSignalInfo rxSignalInfo,
843 const WifiTxVector& txVector,
844 bool inAmpdu)
845{
846 // The received MPDU is either broadcast or addressed to this station
847 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
848
849 const auto& hdr = mpdu->GetHeader();
850
851 if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr2()))
852 {
853 // the AP MLD received an MPDU from an EMLSR client, which is now involved in an UL TXOP,
854 // hence block transmissions for this EMLSR client on other links
855 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(hdr.GetAddr2());
856 NS_ASSERT(mldAddress);
857
858 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
859 {
860 if (linkId != m_linkId &&
861 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
862 {
864 *mldAddress,
865 {linkId});
866 }
867 }
868
869 // Make sure that transmissions for this EMLSR client are not blocked on this link
870 // (the AP MLD may have sent an ICF on another link right before receiving this MPDU,
871 // thus transmissions on this link may have been blocked)
873 *mldAddress,
874 {m_linkId});
875
876 // Stop the transition delay timer for this EMLSR client, if any is running
877 if (auto it = m_transDelayTimer.find(*mldAddress);
878 it != m_transDelayTimer.end() && it->second.IsRunning())
879 {
880 it->second.PeekEventImpl()->Invoke();
881 it->second.Cancel();
882 }
883 }
884
885 bool icfReceived = false;
886
887 if (hdr.IsTrigger())
888 {
889 if (!m_staMac)
890 {
891 return; // Trigger Frames are only processed by STAs
892 }
893
894 CtrlTriggerHeader trigger;
895 mpdu->GetPacket()->PeekHeader(trigger);
896
897 if (hdr.GetAddr1() != m_self &&
898 (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
899 hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with
900 || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end()))
901 {
902 return; // not addressed to us
903 }
904
905 if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId))
906 {
907 // this is an initial Control frame
909 {
910 // we received an ICF on a link that is blocked because another EMLSR link is
911 // being used. This is likely because transmission on the other EMLSR link
912 // started before the reception of the ICF ended. We drop this ICF and let the
913 // UL TXOP continue.
914 NS_LOG_DEBUG("Drop ICF because another EMLSR link is being used");
915 return;
916 }
917
945 if (auto elapsed =
946 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
947 {
948 TimeValue padding;
949 m_staMac->GetEmlsrManager()->GetAttribute("EmlsrPaddingDelay", padding);
950
951 if (*elapsed < padding.Get())
952 {
953 NS_LOG_DEBUG("Drop ICF due to not enough time for the main PHY to switch link");
954 return;
955 }
956 }
957
959 m_staMac->GetEmlsrManager()->NotifyIcfReceived(m_linkId);
960 icfReceived = true;
961
962 // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
963 // SIFS (we are expected to reply by sending a CTS frame)
965 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
968 this);
969 }
970 }
971
972 // We impose that an aux PHY is only able to receive an ICF, a CTS or a management frame
973 // (we are interested in receiving mainly Beacon frames). Note that other frames are still
974 // post-processed, e.g., used to set the NAV and the TXOP holder.
975 // The motivation is that, e.g., an AP MLD may send an ICF to EMLSR clients A and B;
976 // A responds while B does not; the AP MLD sends a DL MU PPDU to both clients followed
977 // by an MU-BAR to solicit a BlockAck from both clients. If an aux PHY of client B is
978 // operating on this link, the MU-BAR will be received and a TB PPDU response sent
979 // through the aux PHY.
981 m_mac->GetLinkForPhy(m_staMac->GetEmlsrManager()->GetMainPhyId()) != m_linkId &&
982 !icfReceived && !mpdu->GetHeader().IsCts() && !mpdu->GetHeader().IsMgt())
983 {
984 NS_LOG_DEBUG("Dropping " << *mpdu << " received by an aux PHY on link " << +m_linkId);
985 return;
986 }
987
988 HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
989}
990
991void
993{
994 NS_LOG_FUNCTION(this);
995
997 {
998 // we may get here because the PHY has not issued the PHY-RXSTART.indication before
999 // the expiration of the timer started to detect new received frames, but the PHY is
1000 // currently decoding the PHY header of a PPDU, so let's wait some more time to check
1001 // if we receive a PHY-RXSTART.indication when the PHY is done decoding the PHY header
1002 NS_LOG_DEBUG("PHY is decoding the PHY header of PPDU, postpone TXOP end");
1005 this);
1006 return;
1007 }
1008
1010 {
1011 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
1012 }
1013 else if (m_apMac && m_txopHolder &&
1014 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
1015 {
1016 // EMLSR client terminated its TXOP and is back to listening operation
1018 }
1019}
1020
1021void
1023{
1024 NS_LOG_FUNCTION(this << txDuration.As(Time::MS) << durationId.As(Time::US));
1025
1027 {
1028 // nothing to do
1029 return;
1030 }
1031
1033 Time delay;
1034
1035 if (m_txTimer.IsRunning())
1036 {
1037 // the TX timer is running, hence we are expecting a response. Postpone the TXOP end
1038 // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
1039 // the response)
1040 delay = m_txTimer.GetDelayLeft();
1041 }
1042 else if (durationId <= m_phy->GetSifs())
1043 {
1044 // the TX timer is not running, hence no response is expected, and the Duration/ID value
1045 // is less than or equal to a SIFS; the TXOP will end after this transmission
1046 NS_LOG_DEBUG("Assume TXOP will end based on Duration/ID value");
1047 delay = txDuration;
1048 }
1049 else
1050 {
1051 // the TX Timer is not running, hence no response is expected (e.g., we are
1052 // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
1053 // after the end of this PPDU, hence we need to postpone the TXOP end in order to
1054 // get the PHY-RXSTART.indication
1055 delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1057 }
1058
1059 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1061}
1062
1063void
1065{
1066 NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
1067
1068 if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
1069 {
1070 // nothing to do
1071 return;
1072 }
1073
1074 // postpone the TXOP end until after the reception of the PSDU is completed
1076
1077 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
1080}
1081
1082void
1084{
1085 NS_LOG_FUNCTION(this << durationId.As(Time::US));
1086
1088 {
1089 // nothing to do
1090 return;
1091 }
1092
1094
1095 // if the Duration/ID of the received frame is less than a SIFS, the TXOP
1096 // is terminated
1097 if (durationId <= m_phy->GetSifs())
1098 {
1099 NS_LOG_DEBUG("Assume TXOP ended based on Duration/ID value");
1100 TxopEnd();
1101 return;
1102 }
1103
1104 // we may send a response after a SIFS or we may receive another frame after a SIFS.
1105 // Postpone the TXOP end by considering the latter (which takes longer)
1107 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1109}
1110
1111} // namespace ns3
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:1413
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:568
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
Definition: txop.h:423
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:519
static constexpr bool DONT_CHECK_MEDIUM_BUSY
generation of backoff is independent of the busy/idle state of the medium
Definition: txop.h:427
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:1632
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
Definition: wifi-mac.cc:576
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:933
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Definition: wifi-mac.cc:1428
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Definition: wifi-mac.cc:1387
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-mac.cc:439
std::optional< uint8_t > GetLinkForPhy(Ptr< const WifiPhy > phy) const
Get the ID of the link (if any) on which the given PHY is operating.
Definition: wifi-mac.cc:974
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:906
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
Ptr< WifiPhy > GetPhy() const
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:811
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:799
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1525
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1039
bool IsReceivingPhyHeader() const
Definition: wifi-phy.cc:1909
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:730
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
bool IsRunning() const
Return true if the timer is running.
const std::set< Mac48Address > & GetStasExpectedToRespond() const
Time GetDelayLeft() const
Get the remaining time until the timer will expire.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiPreamble GetPreambleType() const
bool IsUlMu() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
Declaration of ns3::EhtPhy class.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:449
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