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/sta-wifi-mac.h"
29#include "ns3/wifi-mac-queue.h"
30
31#undef NS_LOG_APPEND_CONTEXT
32#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
33
34namespace ns3
35{
36
39static constexpr uint8_t RX_PHY_START_DELAY_USEC = 48;
40
41NS_LOG_COMPONENT_DEFINE("EhtFrameExchangeManager");
42
44
47{
48 static TypeId tid = TypeId("ns3::EhtFrameExchangeManager")
50 .AddConstructor<EhtFrameExchangeManager>()
51 .SetGroupName("Wifi");
52 return tid;
53}
54
56{
57 NS_LOG_FUNCTION(this);
58}
59
61{
63}
64
65void
67{
68 NS_LOG_FUNCTION(this);
71}
72
73void
75{
76 NS_LOG_FUNCTION(this << txVector << psduDuration.As(Time::MS));
77
78 HeFrameExchangeManager::RxStartIndication(txVector, psduDuration);
80}
81
82void
84{
85 if (auto protectionManager = GetProtectionManager())
86 {
87 protectionManager->SetLinkId(linkId);
88 }
89 if (auto ackManager = GetAckManager())
90 {
91 ackManager->SetLinkId(linkId);
92 }
93 m_msduAggregator->SetLinkId(linkId);
94 m_mpduAggregator->SetLinkId(linkId);
96}
97
100{
101 NS_LOG_FUNCTION(this << *mpdu);
102
103 // alias needs only be created for non-broadcast QoS data frames exchanged between two MLDs
104 if (!mpdu->GetHeader().IsQosData() || m_mac->GetNLinks() == 1 ||
105 mpdu->GetHeader().GetAddr1().IsGroup() ||
106 !GetWifiRemoteStationManager()->GetMldAddress(mpdu->GetHeader().GetAddr1()))
107 {
109 }
110
111 mpdu = mpdu->CreateAlias(m_linkId);
112 auto& hdr = mpdu->GetHeader();
113 hdr.SetAddr2(GetAddress());
114 auto address = GetWifiRemoteStationManager()->GetAffiliatedStaAddress(hdr.GetAddr1());
115 NS_ASSERT(address);
116 hdr.SetAddr1(*address);
117 /*
118 * Set Address3 according to Table 9-30 of 802.11-2020 and Section 35.3.3 of
119 * 802.11be D2.0 ["the value of the Address 3 field and the Address 4 field (if present)
120 * in the MAC header of a data frame shall be set based on Table 9-30 (Address field
121 * contents) and the settings of the To DS and From DS bits, where the BSSID is the
122 * MAC address of the AP affiliated with the AP MLD corresponding to that link"].
123 */
124 if (hdr.IsQosAmsdu())
125 {
126 if (hdr.IsToDs() && !hdr.IsFromDs())
127 {
128 // from STA to AP: BSSID is in Address1
129 hdr.SetAddr3(hdr.GetAddr1());
130 }
131 else if (!hdr.IsToDs() && hdr.IsFromDs())
132 {
133 // from AP to STA: BSSID is in Address2
134 hdr.SetAddr3(hdr.GetAddr2());
135 }
136 }
137
138 return mpdu;
139}
140
141bool
143{
144 NS_LOG_FUNCTION(this << edca << allowedWidth);
145
146 auto started = HeFrameExchangeManager::StartTransmission(edca, allowedWidth);
147
148 if (started && m_staMac && m_staMac->IsEmlsrLink(m_linkId))
149 {
150 // notify the EMLSR Manager of the UL TXOP start on an EMLSR link
152 m_staMac->GetEmlsrManager()->NotifyUlTxopStart(m_linkId);
153 }
154
155 return started;
156}
157
158void
160{
161 NS_LOG_FUNCTION(this << psdu << txVector);
162
163 // EHT-SIG, the equivalent of HE-SIG-B, is present in EHT SU transmissions, too
164 if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU)
165 {
166 auto phy = StaticCast<EhtPhy>(m_phy->GetPhyEntity(WIFI_MOD_CLASS_EHT));
167 auto sigBMode = phy->GetSigBMode(txVector);
168 txVector.SetSigBMode(sigBMode);
169 }
170
171 auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
172
174 UpdateTxopEndOnTxStart(txDuration);
175
176 if (m_apMac)
177 {
178 // check if the EMLSR clients shall switch back to listening operation at the end of this
179 // PPDU
180 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
181 {
182 auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
183
184 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
185 GetEmlsrSwitchToListening(psdu, aid, *clientIt))
186 {
187 EmlsrSwitchToListening(*clientIt, txDuration);
188 // this client is no longer involved in the current TXOP
189 clientIt = m_protectedStas.erase(clientIt);
190 }
191 else
192 {
193 clientIt++;
194 }
195 }
196 }
197}
198
199void
201{
202 NS_LOG_FUNCTION(this << psduMap << txVector);
203
204 auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
205
207 UpdateTxopEndOnTxStart(txDuration);
208
209 if (m_apMac)
210 {
211 // check if the EMLSR clients shall switch back to listening operation at the end of this
212 // PPDU
213 for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
214 {
215 auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
216
217 if (auto psduMapIt = psduMap.find(aid);
218 GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
219 (psduMapIt == psduMap.cend() ||
220 GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
221 {
222 EmlsrSwitchToListening(*clientIt, txDuration);
223 // this client is no longer involved in the current TXOP
224 clientIt = m_protectedStas.erase(clientIt);
225 }
226 else
227 {
228 clientIt++;
229 }
230 }
231 }
232}
233
234void
236{
237 NS_LOG_FUNCTION(this << address << delay.As(Time::US));
238
239 // this EMLSR client switches back to listening operation a transition delay
240 // after the given delay
241 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
242 NS_ASSERT(mldAddress);
243 auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
244 NS_ASSERT(emlCapabilities);
245
246 for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
247 {
248 if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
249 {
250 Simulator::Schedule(delay, [=]() {
251 if (linkId != m_linkId)
252 {
253 // the reason for blocking the other EMLSR links has changed now
255 *mldAddress,
256 {linkId});
257 }
258
259 // block DL transmissions on this link until transition delay elapses
261 *mldAddress,
262 {linkId});
263 });
264
265 // unblock all EMLSR links when the transition delay elapses
267 emlCapabilities->get().emlsrTransitionDelay),
268 [=]() {
269 m_mac->UnblockUnicastTxOnLinks(
270 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
271 *mldAddress,
272 {linkId});
273 });
274 }
275 }
276}
277
278void
279EhtFrameExchangeManager::NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy, uint8_t linkId, Time delay)
280{
281 NS_LOG_FUNCTION(this << phy << linkId << delay.As(Time::US));
282
283 // TODO Shall we assert that there is no ongoing frame exchange sequence? Or is it possible
284 // that there is an ongoing frame exchange sequence (in such a case, we need to force a
285 // timeout, just like it is done in case of a normal channel switch
286
287 NS_ABORT_MSG_IF(!m_staMac, "This method can only be called on a STA");
288
289 // if we receive the notification from a PHY that is not connected to us, it means that
290 // we have been already connected to another PHY operating on this link, hence we do not
291 // have to reset the connected PHY
292 if (phy == m_phy)
293 {
294 ResetPhy();
295 }
296 m_staMac->NotifySwitchingEmlsrLink(phy, linkId);
297}
298
299void
300EhtFrameExchangeManager::SendEmlOmn(const Mac48Address& dest, const MgtEmlOmn& frame)
301{
302 NS_LOG_FUNCTION(this << dest << frame);
303
304 WifiMacHeader hdr;
306 hdr.SetAddr1(dest);
307 hdr.SetAddr2(m_self);
308 hdr.SetAddr3(m_bssid);
309 hdr.SetDsNotTo();
310 hdr.SetDsNotFrom();
311
312 // get the sequence number for the TWT Setup management frame
313 const auto sequence = m_txMiddle->GetNextSequenceNumberFor(&hdr);
314 hdr.SetSequenceNumber(sequence);
315
316 WifiActionHeader actionHdr;
318 action.protectedEhtAction = WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION;
319 actionHdr.SetAction(WifiActionHeader::PROTECTED_EHT, action);
320
321 auto packet = Create<Packet>();
322 packet->AddHeader(frame);
323 packet->AddHeader(actionHdr);
324
325 // Use AC_VO to send management frame addressed to a QoS STA (Sec. 10.2.3.2 of 802.11-2020)
326 m_mac->GetQosTxop(AC_VO)->Queue(Create<WifiMpdu>(packet, hdr));
327}
328
329std::optional<double>
330EhtFrameExchangeManager::GetMostRecentRssi(const Mac48Address& address) const
331{
332 auto optRssi = HeFrameExchangeManager::GetMostRecentRssi(address);
333
334 if (optRssi)
335 {
336 return optRssi;
337 }
338
339 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
340
341 if (!mldAddress)
342 {
343 // not an MLD, nothing else can be done
344 return std::nullopt;
345 }
346
347 for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
348 {
349 std::optional<Mac48Address> linkAddress;
350 if (linkId != m_linkId &&
351 (linkAddress = m_mac->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(
352 *mldAddress)) &&
353 (optRssi = m_mac->GetWifiRemoteStationManager(linkId)->GetMostRecentRssi(*linkAddress)))
354 {
355 return optRssi;
356 }
357 }
358
359 return std::nullopt;
360}
361
362void
363EhtFrameExchangeManager::SendMuRts(const WifiTxParameters& txParams)
364{
365 NS_LOG_FUNCTION(this << &txParams);
366
367 uint8_t maxPaddingDelay = 0;
368
369 // block transmissions on the other EMLSR links of the EMLSR clients
370 for (const auto& address : m_sentRtsTo)
371 {
372 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
373 {
374 continue;
375 }
376
377 auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
378 NS_ASSERT(emlCapabilities);
379 maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->get().emlsrPaddingDelay);
380
381 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
382 NS_ASSERT(mldAddress);
383
384 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
385 {
386 if (linkId != m_linkId &&
387 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
388 {
389 m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
390 *mldAddress,
391 {linkId});
392 }
393 }
394 }
395
396 // add padding (if needed)
397 if (maxPaddingDelay > 0)
398 {
399 NS_ASSERT(txParams.m_protection &&
400 txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
401 auto protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
402 NS_ASSERT(protection->muRts.IsMuRts());
403
404 // see formula (35-1) in Sec. 35.5.2.2.3 of 802.11be D3.0
405 auto rate = protection->muRtsTxVector.GetMode().GetDataRate(protection->muRtsTxVector);
406 std::size_t nDbps = rate / 1e6 * 4; // see Table 17-4 of 802.11-2020
407 protection->muRts.SetPaddingSize((1 << (maxPaddingDelay + 2)) * nDbps / 8);
408 }
409
410 HeFrameExchangeManager::SendMuRts(txParams);
411}
412
413bool
414EhtFrameExchangeManager::GetEmlsrSwitchToListening(Ptr<const WifiPsdu> psdu,
415 uint16_t aid,
416 const Mac48Address& address) const
417{
418 NS_LOG_FUNCTION(this << psdu << aid << address);
419
420 // Sec. 35.3.17 of 802.11be D3.0:
421 // The non-AP MLD shall be switched back to the listening operation on the EMLSR links after
422 // the EMLSR transition delay time if [...] the non-AP STA affiliated with the non-AP MLD
423 // does not detect [...] any of the following frames:
424 // - an individually addressed frame with the RA equal to the MAC address of the non-AP STA
425 // affiliated with the non-AP MLD
426 if (psdu->GetAddr1() == address)
427 {
428 return false;
429 }
430
431 // - a Trigger frame that has one of the User Info fields addressed to the non-AP STA
432 // affiliated with the non-AP MLD
433 for (const auto& mpdu : *PeekPointer(psdu))
434 {
435 if (mpdu->GetHeader().IsTrigger())
436 {
437 CtrlTriggerHeader trigger;
438 mpdu->GetPacket()->PeekHeader(trigger);
439 if (trigger.FindUserInfoWithAid(aid) != trigger.end())
440 {
441 return false;
442 }
443 }
444 }
445
446 // - a CTS-to-self frame with the RA equal to the MAC address of the AP affiliated with
447 // the AP MLD
448 if (psdu->GetHeader(0).IsCts())
449 {
450 if (m_apMac && psdu->GetAddr1() == m_self)
451 {
452 return false;
453 }
454 if (m_staMac && psdu->GetAddr1() == m_bssid)
455 {
456 return false;
457 }
458 }
459
460 // - a Multi-STA BlockAck frame that has one of the Per AID TID Info fields addressed to
461 // the non-AP STA affiliated with the non-AP MLD
462 if (psdu->GetHeader(0).IsBlockAck())
463 {
464 CtrlBAckResponseHeader blockAck;
465 psdu->GetPayload(0)->PeekHeader(blockAck);
466 if (blockAck.IsMultiSta() && !blockAck.FindPerAidTidInfoWithAid(aid).empty())
467 {
468 return false;
469 }
470 }
471
472 // - a NDP Announcement frame that has one of the STA Info fields addressed to the non-AP
473 // STA affiliated with the non-AP MLD and a sounding NDP
474 // TODO NDP Announcement frame not supported yet
475
476 return true;
477}
478
479void
480EhtFrameExchangeManager::TransmissionFailed()
481{
482 NS_LOG_FUNCTION(this);
483
484 for (const auto& address : m_txTimer.GetStasExpectedToRespond())
485 {
486 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
487 {
488 // This EMLSR client did not respond to a frame sent by the AP. Specs say:
489 // The AP affiliated with the AP MLD should transmit before the TXNAV timer expires
490 // another initial Control frame addressed to the non-AP STA affiliated with the
491 // non-AP MLD if the AP intends to continue the frame exchanges with the STA and did
492 // not receive the response frame from this STA for the most recently transmitted
493 // frame that requires an immediate response after a SIFS
494 // (Sec. 35.3.17 of 802.11be D3.1)
495 // We let the AP continue the TXOP. TransmissionSucceeded() removes this client from
496 // protected stations, hence next transmission to this client in this TXOP will be
497 // protected by ICF
498 NS_LOG_DEBUG("EMLSR client " << address << " did not respond, continue TXOP");
499 TransmissionSucceeded();
500 return;
501 }
502 }
503
504 HeFrameExchangeManager::TransmissionFailed();
505}
506
507void
508EhtFrameExchangeManager::NotifyChannelReleased(Ptr<Txop> txop)
509{
510 NS_LOG_FUNCTION(this << txop);
511
512 if (m_apMac)
513 {
514 // the channel has been released; all EMLSR clients will switch back to listening
515 // operation after a timeout interval of aSIFSTime + aSlotTime + aRxPHYStartDelay
516 auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
517 for (const auto& address : m_protectedStas)
518 {
519 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
520 {
521 EmlsrSwitchToListening(address, delay);
522 }
523 }
524 }
525 else if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
526 {
527 // notify the EMLSR Manager of the UL TXOP end
528 NS_ASSERT(m_staMac->GetEmlsrManager());
529 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
530 }
531
532 HeFrameExchangeManager::NotifyChannelReleased(txop);
533}
534
535void
536EhtFrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
537{
538 NS_LOG_FUNCTION(this << psdu << txVector);
539
540 HeFrameExchangeManager::PostProcessFrame(psdu, txVector);
541
542 if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
543 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
544 {
545 if (!m_ongoingTxopEnd.IsRunning())
546 {
547 // an EMLSR client has started an UL TXOP. We may send a response after a SIFS or
548 // we may receive another frame after a SIFS. Postpone the TXOP end by considering
549 // the latter (which takes longer)
550 auto delay =
551 m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
552 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
553 m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
554
555 // block transmissions on other links
556 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(psdu->GetAddr2());
557 NS_ASSERT(mldAddress);
558
559 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
560 {
561 if (linkId != m_linkId &&
562 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
563 {
564 m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
565 *mldAddress,
566 {linkId});
567 }
568 }
569 }
570 else
571 {
572 UpdateTxopEndOnRxEnd();
573 }
574 }
575
576 if (m_staMac && m_ongoingTxopEnd.IsRunning())
577 {
578 if (GetEmlsrSwitchToListening(psdu, m_staMac->GetAssociationId(), m_self))
579 {
580 // we are no longer involved in the TXOP and switching to listening mode
581 m_ongoingTxopEnd.Cancel();
582 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
583 }
584 else
585 {
586 UpdateTxopEndOnRxEnd();
587 }
588 }
589}
590
591void
592EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
593 RxSignalInfo rxSignalInfo,
594 const WifiTxVector& txVector,
595 bool inAmpdu)
596{
597 // The received MPDU is either broadcast or addressed to this station
598 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
599
600 const auto& hdr = mpdu->GetHeader();
601
602 if (hdr.IsTrigger())
603 {
604 if (!m_staMac)
605 {
606 return; // Trigger Frames are only processed by STAs
607 }
608
609 CtrlTriggerHeader trigger;
610 mpdu->GetPacket()->PeekHeader(trigger);
611
612 if (hdr.GetAddr1() != m_self &&
613 (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
614 hdr.GetAddr2() != m_bssid // not sent by the AP this STA is associated with
615 || trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) == trigger.end()))
616 {
617 return; // not addressed to us
618 }
619
620 if (trigger.IsMuRts() && m_staMac->IsEmlsrLink(m_linkId))
621 {
622 // this is an initial Control frame
623 auto apAddress = GetWifiRemoteStationManager()->GetMldAddress(m_bssid);
624 NS_ASSERT_MSG(apAddress, "MLD address not found for BSSID " << m_bssid);
625 // when EMLSR links are blocked, all TIDs are blocked (we test TID 0 here)
627 if (auto mask =
628 m_staMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, m_linkId);
629 mask && mask->test(static_cast<std::size_t>(
630 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
631 {
632 // we received an ICF on a link that is blocked because another EMLSR link is
633 // being used. This is likely because transmission on the other EMLSR link
634 // started before the reception of the ICF ended. We drop this ICF and let the
635 // UL TXOP continue.
636 NS_LOG_DEBUG("Drop ICF because another EMLSR link is being used");
637 return;
638 }
639
640 NS_ASSERT(m_staMac->GetEmlsrManager());
641 Simulator::ScheduleNow(&EmlsrManager::NotifyIcfReceived,
642 m_staMac->GetEmlsrManager(),
643 m_linkId);
644 // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
645 // SIFS (we are expected to reply by sending a CTS frame)
646 m_ongoingTxopEnd.Cancel();
647 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
648 m_ongoingTxopEnd = Simulator::Schedule(m_phy->GetSifs() + NanoSeconds(1),
649 &EhtFrameExchangeManager::TxopEnd,
650 this);
651 }
652 }
653
654 HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
655}
656
657void
658EhtFrameExchangeManager::TxopEnd()
659{
660 NS_LOG_FUNCTION(this);
661
662 if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
663 {
664 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
665 }
666 else if (m_apMac && m_txopHolder &&
667 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
668 {
669 // EMLSR client terminated its TXOP and is back to listening operation
670 EmlsrSwitchToListening(*m_txopHolder, Seconds(0));
671 }
672}
673
674void
675EhtFrameExchangeManager::UpdateTxopEndOnTxStart(Time txDuration)
676{
677 NS_LOG_FUNCTION(this << txDuration.As(Time::MS));
678
679 if (!m_ongoingTxopEnd.IsRunning())
680 {
681 // nothing to do
682 return;
683 }
684
685 m_ongoingTxopEnd.Cancel();
686 Time delay;
687
688 if (m_txTimer.IsRunning())
689 {
690 // the TX timer is running, hence we are expecting a response. Postpone the TXOP end
691 // to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
692 // the response)
693 delay = m_txTimer.GetDelayLeft();
694 }
695 else
696 {
697 // the TX Timer is not running, hence no response is expected (e.g., we are
698 // transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
699 // after the end of this PPDU, hence we need to postpone the TXOP end in order to
700 // get the PHY-RXSTART.indication
701 delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
703 }
704
705 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
706 m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
707}
708
709void
710EhtFrameExchangeManager::UpdateTxopEndOnRxStartIndication(Time psduDuration)
711{
712 NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
713
714 if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
715 {
716 // nothing to do
717 return;
718 }
719
720 // postpone the TXOP end until after the reception of the PSDU is completed
721 m_ongoingTxopEnd.Cancel();
722
723 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
724 m_ongoingTxopEnd =
725 Simulator::Schedule(psduDuration + NanoSeconds(1), &EhtFrameExchangeManager::TxopEnd, this);
726}
727
728void
729EhtFrameExchangeManager::UpdateTxopEndOnRxEnd()
730{
731 NS_LOG_FUNCTION(this);
732
733 if (!m_ongoingTxopEnd.IsRunning())
734 {
735 // nothing to do
736 return;
737 }
738
739 m_ongoingTxopEnd.Cancel();
740
741 // we may send a response after a SIFS or we may receive another frame after a SIFS.
742 // Postpone the TXOP end by considering the latter (which takes longer)
743 auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
744 NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
745 m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
746}
747
748} // 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 ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector) override
Forward a map of PSDUs down to the PHY layer.
void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector) override
Forward a PSDU down to the PHY layer.
Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const override
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
void UpdateTxopEndOnTxStart(Time txDuration)
Update the TXOP end timer when starting a frame transmission.
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.
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 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 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
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
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.
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 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.
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
virtual void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector)
Forward a map of PSDUs down to the PHY layer.
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.
Definition: mgt-headers.h:1113
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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:558
Ptr< EmlsrManager > GetEmlsrManager() const
bool IsEmlsrLink(uint8_t linkId) const
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:350
@ US
microsecond
Definition: nstime.h:118
@ MS
millisecond
Definition: nstime.h:117
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:930
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
Definition: mgt-headers.h:539
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
Definition: mgt-headers.cc:601
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.
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:935
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:1430
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:1389
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:908
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1496
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1005
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:713
bool GetEmlsrEnabled(const Mac48Address &address) const
uint16_t GetAssociationId(Mac48Address remoteAddress) const
Get the AID of a remote station.
std::optional< Mac48Address > GetAffiliatedStaAddress(const Mac48Address &mldAddress) const
Get the address of the remote station operating on this link and affiliated with the MLD having the g...
std::optional< std::reference_wrapper< CommonInfoBasicMle::EmlCapabilities > > GetStationEmlCapabilities(const Mac48Address &from)
std::optional< Mac48Address > GetMldAddress(const Mac48Address &address) const
Get the address of the MLD the given station is affiliated with, if any.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiPreamble GetPreambleType() 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:1349
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1361
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1325
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ AC_BE
Best Effort.
Definition: qos-utils.h:74
@ AC_VO
Voice.
Definition: qos-utils.h:80
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:484
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
static constexpr uint8_t RX_PHY_START_DELAY_USEC
generic value for aRxPHYStartDelay PHY characteristic (used when we do not know the preamble type of ...
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 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
Definition: mgt-headers.h:723