A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
frame-exchange-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
10
11#include "ap-wifi-mac.h"
12#include "gcr-manager.h"
13#include "snr-tag.h"
14#include "sta-wifi-mac.h"
15#include "wifi-mac-queue.h"
16#include "wifi-mac-trailer.h"
17#include "wifi-utils.h"
18
19#include "ns3/abort.h"
20#include "ns3/log.h"
21
22#undef NS_LOG_APPEND_CONTEXT
23#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
24
25// Time (in nanoseconds) to be added to the PSDU duration to yield the duration
26// of the timer that is started when the PHY indicates the start of the reception
27// of a frame and we are waiting for a response.
28#define PSDU_DURATION_SAFEGUARD 400
29
30namespace ns3
31{
32
33NS_LOG_COMPONENT_DEFINE("FrameExchangeManager");
34
35NS_OBJECT_ENSURE_REGISTERED(FrameExchangeManager);
36
37TypeId
39{
40 static TypeId tid =
41 TypeId("ns3::FrameExchangeManager")
43 .AddConstructor<FrameExchangeManager>()
44 .SetGroupName("Wifi")
45 .AddAttribute("ProtectedIfResponded",
46 "Whether a station is assumed to be protected if replied to a frame "
47 "requiring acknowledgment. If a station is protected, subsequent "
48 "transmissions to the same station in the same TXOP are not "
49 "preceded by protection mechanisms.",
50 BooleanValue(true),
53 return tid;
54}
55
57 : m_navEnd(0),
58 m_txNav(0),
59 m_linkId(0),
60 m_allowedWidth{0},
61 m_promisc(false),
62 m_moreFragments(false)
63{
64 NS_LOG_FUNCTION(this);
65}
66
71
72void
86
87void
89{
90 NS_LOG_FUNCTION(this);
91 Reset();
92 m_fragmentedPacket = nullptr;
93 m_mac = nullptr;
94 m_apMac = nullptr;
95 m_staMac = nullptr;
96 m_txMiddle = nullptr;
97 m_rxMiddle = nullptr;
98 m_channelAccessManager = nullptr;
99 m_protectionManager = nullptr;
100 m_ackManager = nullptr;
101 ResetPhy();
103}
104
105void
107{
108 NS_LOG_FUNCTION(this << protectionManager);
109 m_protectionManager = protectionManager;
110}
111
117
118void
120{
121 NS_LOG_FUNCTION(this << ackManager);
122 m_ackManager = ackManager;
123}
124
130
131void
133{
134 NS_LOG_FUNCTION(this << +linkId);
135 m_linkId = linkId;
136}
137
138void
146
147void
149{
150 NS_LOG_FUNCTION(this << txMiddle);
151 m_txMiddle = txMiddle;
152}
153
154void
156{
157 NS_LOG_FUNCTION(this << rxMiddle);
158 m_rxMiddle = rxMiddle;
159}
160
161void
163{
164 NS_LOG_FUNCTION(this << channelAccessManager);
165 m_channelAccessManager = channelAccessManager;
166}
167
170{
171 return m_mac->GetWifiRemoteStationManager(m_linkId);
172}
173
174void
186
187void
189{
190 NS_LOG_FUNCTION(this);
191 if (m_phy)
192 {
194 "PhyRxPayloadBegin",
197 "PhyRxMacHeaderEnd",
199 if (m_phy->GetState())
200 {
204 const WifiTxVector&,
205 const std::vector<bool>&>());
207 }
208 m_phy = nullptr;
209 m_ongoingRxInfo.macHdr.reset();
211 }
212}
213
214void
216{
217 NS_LOG_FUNCTION(this << address);
218 // For APs, the BSSID is the MAC address. For STAs, the BSSID will be overwritten
219 // when receiving Beacon frames or Probe Response frames
220 SetBssid(address);
221 m_self = address;
222}
223
226{
227 return m_self;
228}
229
230void
232{
233 NS_LOG_FUNCTION(this << bssid);
234 m_bssid = bssid;
235}
236
239{
240 return m_bssid;
241}
242
243MHz_u
248
249void
251{
252 NS_LOG_FUNCTION(this << &callback);
253 m_droppedMpduCallback = callback;
254}
255
256void
258{
259 NS_LOG_FUNCTION(this << &callback);
260 m_ackedMpduCallback = callback;
261}
262
263void
268
269bool
271{
272 return m_promisc;
273}
274
275const WifiTxTimer&
280
281void
288
289void
291{
292 NS_LOG_FUNCTION(this << "PSDU reception started for " << psduDuration.As(Time::US)
293 << " (txVector: " << txVector << ")");
294
296 "The TX timer and the NAV reset event cannot be both running");
297
298 // No need to reschedule timeouts if PSDU duration is null. In this case,
299 // PHY-RXEND immediately follows PHY-RXSTART (e.g. when PPDU has been filtered)
300 // and CCA will take over
301 if (m_txTimer.IsRunning() && psduDuration.IsStrictlyPositive())
302 {
303 // we are waiting for a response and something arrived
304 NS_LOG_DEBUG("Rescheduling timeout event");
306 // PHY has switched to RX, so we can reset the ack timeout
307 m_channelAccessManager->NotifyAckTimeoutResetNow();
308 }
309
311 {
313 }
314
315 m_ongoingRxInfo = {std::nullopt, txVector, Simulator::Now() + psduDuration};
316}
317
318void
320 const WifiTxVector& txVector,
321 Time psduDuration)
322{
323 NS_LOG_FUNCTION(this << macHdr << txVector << psduDuration.As(Time::MS));
324 m_ongoingRxInfo = {macHdr, txVector, Simulator::Now() + psduDuration};
325 UpdateNav(macHdr, txVector, psduDuration);
326}
327
328std::optional<std::reference_wrapper<const FrameExchangeManager::OngoingRxInfo>>
330{
332 {
333 return m_ongoingRxInfo;
334 }
335 return std::nullopt;
336}
337
338std::optional<std::reference_wrapper<const WifiMacHeader>>
340{
341 if (auto info = GetOngoingRxInfo(); info.has_value() && info->get().macHdr.has_value())
342 {
343 return info->get().macHdr.value();
344 }
345 return std::nullopt;
346}
347
348bool
350{
351 NS_LOG_FUNCTION(this << dcf << allowedWidth);
352
354 if (m_txTimer.IsRunning())
355 {
357 }
358 m_dcf = dcf;
359 m_allowedWidth = allowedWidth;
360
361 Ptr<WifiMacQueue> queue = dcf->GetWifiMacQueue();
362
363 // Even though channel access is requested when the queue is not empty, at
364 // the time channel access is granted the lifetime of the packet might be
365 // expired and the queue might be empty.
366 queue->WipeAllExpiredMpdus();
367
368 Ptr<WifiMpdu> mpdu = queue->Peek(m_linkId);
369
370 if (!mpdu)
371 {
372 NS_LOG_DEBUG("Queue empty");
374 m_dcf = nullptr;
375 return false;
376 }
377
379
380 NS_ASSERT(mpdu->GetHeader().IsData() || mpdu->GetHeader().IsMgt());
381
382 // assign a sequence number if this is not a fragment nor a retransmission
383 if (!mpdu->IsFragment() && !mpdu->GetHeader().IsRetry())
384 {
385 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
386 mpdu->AssignSeqNo(sequence);
387 }
388
389 NS_LOG_DEBUG("MPDU payload size=" << mpdu->GetPacketSize()
390 << ", to=" << mpdu->GetHeader().GetAddr1()
391 << ", seq=" << mpdu->GetHeader().GetSequenceControl());
392
393 // check if the MSDU needs to be fragmented
394 mpdu = GetFirstFragmentIfNeeded(mpdu);
395
398 WifiTxParameters txParams;
399 txParams.m_txVector =
400 GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
401 txParams.AddMpdu(mpdu);
402 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
403 txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
404 txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
405
406 SendMpduWithProtection(mpdu, txParams);
407
408 return true;
409}
410
413{
414 NS_LOG_FUNCTION(this << *mpdu);
415
416 if (mpdu->IsFragment())
417 {
418 // a fragment cannot be further fragmented
420 }
421 else if (GetWifiRemoteStationManager()->NeedFragmentation(mpdu))
422 {
423 NS_LOG_DEBUG("Fragmenting the MSDU");
424 m_fragmentedPacket = mpdu->GetPacket()->Copy();
425 // create the first fragment
427 0,
428 GetWifiRemoteStationManager()->GetFragmentSize(mpdu, 0));
429 // enqueue the first fragment
430 Ptr<WifiMpdu> item = Create<WifiMpdu>(fragment, mpdu->GetHeader());
431 item->GetHeader().SetMoreFragments();
432 m_mac->GetTxopQueue(mpdu->GetQueueAc())->Replace(mpdu, item);
433 return item;
434 }
435 return mpdu;
436}
437
438void
440{
441 NS_LOG_FUNCTION(this << *mpdu << &txParams);
442
443 m_mpdu = mpdu;
444 m_txParams = std::move(txParams);
445
446 // If protection is required, the MPDU must be stored in some queue because
447 // it is not put back in a queue if the RTS/CTS exchange fails
449 m_mpdu->GetHeader().IsCtl() || m_mpdu->IsQueued());
450
451 // Make sure that the acknowledgment time has been computed, so that SendRts()
452 // and SendCtsToSelf() can reuse this value.
454
455 if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
456 {
458 }
459
460 // Set QoS Ack policy if this is a QoS data frame
462
463 if (m_mpdu->IsQueued())
464 {
465 m_mpdu->SetInFlight(m_linkId);
466 }
467
469}
470
471void
473{
474 NS_LOG_FUNCTION(this << &txParams);
475
476 switch (txParams.m_protection->method)
477 {
479 SendRts(txParams);
480 break;
482 SendCtsToSelf(txParams);
483 break;
486 break;
487 default:
488 NS_ABORT_MSG("Unknown protection type: " << txParams.m_protection.get());
489 }
490}
491
492void
508
509const std::set<Mac48Address>&
514
515void
517{
518 NS_LOG_FUNCTION(this);
519
522 m_phy->GetPhyBand());
523
525
527 {
528 if (m_mac->GetTypeOfStation() == AP && m_apMac->UseGcr(m_mpdu->GetHeader()))
529 {
530 if (m_apMac->GetGcrManager()->KeepGroupcastQueued(m_mpdu))
531 {
532 // keep the groupcast frame in the queue for future retransmission
533 Simulator::Schedule(txDuration + m_phy->GetSifs(), [=, this, mpdu = m_mpdu]() {
534 NS_LOG_DEBUG("Prepare groupcast MPDU for retry");
535 mpdu->ResetInFlight(m_linkId);
536 // restore addr1 to the group address instead of the concealment address
537 if (m_apMac->GetGcrManager()->UseConcealment(mpdu->GetHeader()))
538 {
539 mpdu->GetHeader().SetAddr1(mpdu->begin()->second.GetDestinationAddr());
540 }
541 mpdu->GetHeader().SetRetry();
542 });
543 }
544 else
545 {
546 if (m_apMac->GetGcrManager()->GetRetransmissionPolicy() ==
548 {
550 }
552 }
553 }
554 else if (!m_mpdu->GetHeader().IsQosData() ||
555 m_mpdu->GetHeader().GetQosAckPolicy() == WifiMacHeader::NO_ACK)
556 {
557 // No acknowledgment, hence dequeue the MPDU if it is stored in a queue
559 }
560
561 Simulator::Schedule(txDuration, [=, this]() {
563 m_mpdu = nullptr;
564 });
565 }
566 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
567 {
568 m_mpdu->GetHeader().SetDuration(
569 GetFrameDurationId(m_mpdu->GetHeader(),
570 GetPsduSize(m_mpdu, m_txParams.m_txVector),
571 m_txParams,
572 m_fragmentedPacket));
573
574 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
575 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
576 // aRxPHYStartDelay equals the time to transmit the PHY header.
577 auto normalAcknowledgment = static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
578
579 Time timeout =
580 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
581 WifiPhy::CalculatePhyPreambleAndHeaderDuration(normalAcknowledgment->ackTxVector);
582 NS_ASSERT(!m_txTimer.IsRunning());
583 m_txTimer.Set(WifiTxTimer::WAIT_NORMAL_ACK,
584 timeout,
585 {m_mpdu->GetHeader().GetAddr1()},
587 this,
588 m_mpdu,
589 m_txParams.m_txVector);
590 m_channelAccessManager->NotifyAckTimeoutStartNow(timeout);
591 }
592 else
593 {
594 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
595 << m_txParams.m_acknowledgment.get() << ")");
596 }
597
598 // transmit the MPDU
599 ForwardMpduDown(m_mpdu, m_txParams.m_txVector);
600
601 if (m_txTimer.IsRunning())
602 {
603 NS_ASSERT(m_sentFrameTo.empty());
604 m_sentFrameTo = {m_mpdu->GetHeader().GetAddr1()};
605 }
606}
607
608void
609FrameExchangeManager::ForwardMpduDown(Ptr<WifiMpdu> mpdu, WifiTxVector& txVector)
610{
611 NS_LOG_FUNCTION(this << *mpdu << txVector);
612
613 auto psdu = Create<WifiPsdu>(mpdu, false);
614 FinalizeMacHeader(psdu);
615 m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
616 const auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
617 SetTxNav(mpdu, txDuration);
618 m_phy->Send(psdu, txVector);
619}
620
621void
622FrameExchangeManager::FinalizeMacHeader(Ptr<const WifiPsdu> psdu)
623{
624 NS_LOG_FUNCTION(this << psdu);
625
626 if (m_mac->GetTypeOfStation() != STA)
627 {
628 return;
629 }
630
631 auto pmMode = StaticCast<StaWifiMac>(m_mac)->GetPmMode(m_linkId);
632
633 for (const auto& mpdu : *PeekPointer(psdu))
634 {
635 switch (pmMode)
636 {
637 case WIFI_PM_ACTIVE:
639 mpdu->GetHeader().SetNoPowerManagement();
640 break;
643 mpdu->GetHeader().SetPowerManagement();
644 break;
645 default:
646 NS_ABORT_MSG("Unknown PM mode: " << +pmMode);
647 }
648 }
649}
650
651void
652FrameExchangeManager::DequeueMpdu(Ptr<const WifiMpdu> mpdu)
653{
654 NS_LOG_DEBUG(this << *mpdu);
655
656 if (mpdu->IsQueued())
657 {
658 m_mac->GetTxopQueue(mpdu->GetQueueAc())->DequeueIfQueued({mpdu});
659 }
660}
661
663FrameExchangeManager::GetPsduSize(Ptr<const WifiMpdu> mpdu, const WifiTxVector& txVector) const
664{
665 return mpdu->GetSize();
666}
667
668void
669FrameExchangeManager::CalculateProtectionTime(WifiProtection* protection) const
670{
671 NS_LOG_FUNCTION(this << protection);
672 NS_ASSERT(protection);
673
674 if (protection->method == WifiProtection::NONE)
675 {
676 protection->protectionTime = Seconds(0);
677 }
678 else if (protection->method == WifiProtection::RTS_CTS)
679 {
680 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
681 rtsCtsProtection->protectionTime =
682 WifiPhy::CalculateTxDuration(GetRtsSize(),
683 rtsCtsProtection->rtsTxVector,
684 m_phy->GetPhyBand()) +
685 WifiPhy::CalculateTxDuration(GetCtsSize(),
686 rtsCtsProtection->ctsTxVector,
687 m_phy->GetPhyBand()) +
688 2 * m_phy->GetSifs();
689 }
690 else if (protection->method == WifiProtection::CTS_TO_SELF)
691 {
692 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(protection);
693 ctsToSelfProtection->protectionTime =
694 WifiPhy::CalculateTxDuration(GetCtsSize(),
695 ctsToSelfProtection->ctsTxVector,
696 m_phy->GetPhyBand()) +
697 m_phy->GetSifs();
698 }
699}
700
701void
702FrameExchangeManager::CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const
703{
704 NS_LOG_FUNCTION(this << acknowledgment);
705 NS_ASSERT(acknowledgment);
706
707 if (acknowledgment->method == WifiAcknowledgment::NONE)
708 {
709 acknowledgment->acknowledgmentTime = Seconds(0);
710 }
711 else if (acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
712 {
713 auto normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
714 normalAcknowledgment->acknowledgmentTime =
715 m_phy->GetSifs() + WifiPhy::CalculateTxDuration(GetAckSize(),
716 normalAcknowledgment->ackTxVector,
717 m_phy->GetPhyBand());
718 }
719}
720
721Time
722FrameExchangeManager::GetTxDuration(uint32_t ppduPayloadSize,
723 Mac48Address receiver,
724 const WifiTxParameters& txParams) const
725{
726 return WifiPhy::CalculateTxDuration(ppduPayloadSize, txParams.m_txVector, m_phy->GetPhyBand());
727}
728
729void
730FrameExchangeManager::UpdateTxDuration(Mac48Address receiver, WifiTxParameters& txParams) const
731{
732 txParams.m_txDuration = GetTxDuration(txParams.GetSize(receiver), receiver, txParams);
733}
734
735Time
736FrameExchangeManager::GetFrameDurationId(const WifiMacHeader& header,
737 uint32_t size,
738 const WifiTxParameters& txParams,
739 Ptr<Packet> fragmentedPacket) const
740{
741 NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
742
743 NS_ASSERT(txParams.m_acknowledgment &&
744 txParams.m_acknowledgment->acknowledgmentTime.has_value());
745 auto durationId = *txParams.m_acknowledgment->acknowledgmentTime;
746
747 // if the current frame is a fragment followed by another fragment, we have to
748 // update the Duration/ID to cover the next fragment and the corresponding Ack
749 if (header.IsMoreFragments())
750 {
751 uint32_t payloadSize = size - header.GetSize() - WIFI_MAC_FCS_LENGTH;
752 uint32_t nextFragmentOffset = (header.GetFragmentNumber() + 1) * payloadSize;
753 uint32_t nextFragmentSize =
754 std::min(fragmentedPacket->GetSize() - nextFragmentOffset, payloadSize);
755 WifiTxVector ackTxVector =
756 GetWifiRemoteStationManager()->GetAckTxVector(header.GetAddr1(), txParams.m_txVector);
757
758 durationId += 2 * m_phy->GetSifs() +
759 WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand()) +
760 WifiPhy::CalculateTxDuration(nextFragmentSize,
761 txParams.m_txVector,
762 m_phy->GetPhyBand());
763 }
764 return durationId;
765}
766
767Time
768FrameExchangeManager::GetRtsDurationId(const WifiTxVector& rtsTxVector,
769 Time txDuration,
770 Time response) const
771{
772 NS_LOG_FUNCTION(this << rtsTxVector << txDuration << response);
773
774 WifiTxVector ctsTxVector;
775 ctsTxVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_self, rtsTxVector.GetMode());
776
777 return m_phy->GetSifs() +
778 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) /* CTS */
779 + m_phy->GetSifs() + txDuration + response;
780}
781
782void
783FrameExchangeManager::SendRts(const WifiTxParameters& txParams)
784{
785 NS_LOG_FUNCTION(this << &txParams);
786
787 NS_ASSERT(txParams.GetPsduInfoMap().size() == 1);
788
789 const auto& hdr = txParams.GetPsduInfoMap().begin()->second.header;
790 const auto receiver = GetIndividuallyAddressedRecipient(m_mac, hdr);
791
792 WifiMacHeader rts;
794 rts.SetDsNotFrom();
795 rts.SetDsNotTo();
796 rts.SetNoRetry();
797 rts.SetNoMoreFragments();
798 rts.SetAddr1(receiver);
799 rts.SetAddr2(m_self);
800
801 NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
802 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
803
804 NS_ASSERT(txParams.m_txDuration.has_value());
805 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
806 rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
807 *txParams.m_txDuration,
808 *txParams.m_acknowledgment->acknowledgmentTime));
809 Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(Create<Packet>(), rts);
810
811 // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with
812 // a value of aSIFSTime + aSlotTime + aRxPHYStartDelay (IEEE 802.11-2016 sec. 10.3.2.7).
813 // aRxPHYStartDelay equals the time to transmit the PHY header.
814 Time timeout = WifiPhy::CalculateTxDuration(GetRtsSize(),
815 rtsCtsProtection->rtsTxVector,
816 m_phy->GetPhyBand()) +
817 m_phy->GetSifs() + m_phy->GetSlot() +
818 WifiPhy::CalculatePhyPreambleAndHeaderDuration(rtsCtsProtection->ctsTxVector);
819 NS_ASSERT(!m_txTimer.IsRunning());
820 m_txTimer.Set(WifiTxTimer::WAIT_CTS,
821 timeout,
822 {receiver},
823 &FrameExchangeManager::CtsTimeout,
824 this,
825 mpdu,
826 rtsCtsProtection->rtsTxVector);
827 m_channelAccessManager->NotifyCtsTimeoutStartNow(timeout);
828 NS_ASSERT(m_sentRtsTo.empty());
829 m_sentRtsTo = {receiver};
830
831 ForwardMpduDown(mpdu, rtsCtsProtection->rtsTxVector);
832}
833
834void
835FrameExchangeManager::DoSendCtsAfterRts(const WifiMacHeader& rtsHdr,
836 WifiTxVector& ctsTxVector,
837 double rtsSnr)
838{
839 NS_LOG_FUNCTION(this << rtsHdr << ctsTxVector << rtsSnr);
840
841 WifiMacHeader cts;
843 cts.SetDsNotFrom();
844 cts.SetDsNotTo();
845 cts.SetNoMoreFragments();
846 cts.SetNoRetry();
847 cts.SetAddr1(rtsHdr.GetAddr2());
848 Time duration = rtsHdr.GetDuration() - m_phy->GetSifs() -
849 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand());
850 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
851 if (duration.IsStrictlyNegative())
852 {
853 duration = Seconds(0);
854 }
855 cts.SetDuration(duration);
856
857 Ptr<Packet> packet = Create<Packet>();
858
859 SnrTag tag;
860 tag.Set(rtsSnr);
861 packet->AddPacketTag(tag);
862
863 // CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
864 ForwardMpduDown(Create<WifiMpdu>(packet, cts), ctsTxVector);
865}
866
867void
868FrameExchangeManager::SendCtsAfterRts(const WifiMacHeader& rtsHdr,
869 const WifiTxVector& rtsTxVector,
870 double rtsSnr)
871{
872 NS_LOG_FUNCTION(this << rtsHdr << rtsTxVector << rtsSnr);
873
874 WifiTxVector ctsTxVector =
875 GetWifiRemoteStationManager()->GetCtsTxVector(rtsHdr.GetAddr2(), rtsTxVector.GetMode());
876 DoSendCtsAfterRts(rtsHdr, ctsTxVector, rtsSnr);
877}
878
879Time
880FrameExchangeManager::GetCtsToSelfDurationId(const WifiTxVector& ctsTxVector,
881 Time txDuration,
882 Time response) const
883{
884 NS_LOG_FUNCTION(this << ctsTxVector << txDuration << response);
885
886 return m_phy->GetSifs() + txDuration + response;
887}
888
889void
890FrameExchangeManager::SendCtsToSelf(const WifiTxParameters& txParams)
891{
892 NS_LOG_FUNCTION(this << &txParams);
893
894 WifiMacHeader cts;
896 cts.SetDsNotFrom();
897 cts.SetDsNotTo();
898 cts.SetNoMoreFragments();
899 cts.SetNoRetry();
900 cts.SetAddr1(m_self);
901
902 NS_ASSERT(txParams.m_protection &&
903 txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
904 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
905
906 NS_ASSERT(txParams.m_txDuration.has_value());
907 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
908 cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
909 *txParams.m_txDuration,
910 *txParams.m_acknowledgment->acknowledgmentTime));
911
912 ForwardMpduDown(Create<WifiMpdu>(Create<Packet>(), cts), ctsToSelfProtection->ctsTxVector);
913
914 Time ctsDuration = WifiPhy::CalculateTxDuration(GetCtsSize(),
915 ctsToSelfProtection->ctsTxVector,
916 m_phy->GetPhyBand());
917 Simulator::Schedule(ctsDuration, &FrameExchangeManager::ProtectionCompleted, this);
918}
919
920void
921FrameExchangeManager::SendNormalAck(const WifiMacHeader& hdr,
922 const WifiTxVector& dataTxVector,
923 double dataSnr)
924{
925 NS_LOG_FUNCTION(this << hdr << dataTxVector << dataSnr);
926
927 WifiTxVector ackTxVector =
928 GetWifiRemoteStationManager()->GetAckTxVector(hdr.GetAddr2(), dataTxVector);
929 WifiMacHeader ack;
931 ack.SetDsNotFrom();
932 ack.SetDsNotTo();
933 ack.SetNoRetry();
934 ack.SetNoMoreFragments();
935 ack.SetAddr1(hdr.GetAddr2());
936 // 802.11-2016, Section 9.2.5.7: Duration/ID is received duration value
937 // minus the time to transmit the Ack frame and its SIFS interval
938 Time duration = hdr.GetDuration() - m_phy->GetSifs() -
939 WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand());
940 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
941 if (duration.IsStrictlyNegative())
942 {
943 duration = Seconds(0);
944 }
945 ack.SetDuration(duration);
946
947 Ptr<Packet> packet = Create<Packet>();
948
949 SnrTag tag;
950 tag.Set(dataSnr);
951 packet->AddPacketTag(tag);
952
953 ForwardMpduDown(Create<WifiMpdu>(packet, ack), ackTxVector);
954}
955
957FrameExchangeManager::GetNextFragment()
958{
959 NS_LOG_FUNCTION(this);
960 NS_ASSERT(m_mpdu->GetHeader().IsMoreFragments());
961
962 WifiMacHeader& hdr = m_mpdu->GetHeader();
964
965 uint32_t startOffset = hdr.GetFragmentNumber() * m_mpdu->GetPacketSize();
966 uint32_t size = m_fragmentedPacket->GetSize() - startOffset;
967
968 if (size > m_mpdu->GetPacketSize())
969 {
970 // this is not the last fragment
971 size = m_mpdu->GetPacketSize();
972 hdr.SetMoreFragments();
973 }
974 else
975 {
976 hdr.SetNoMoreFragments();
977 }
978
979 return Create<WifiMpdu>(m_fragmentedPacket->CreateFragment(startOffset, size), hdr);
980}
981
982void
983FrameExchangeManager::TransmissionSucceeded()
984{
985 NS_LOG_FUNCTION(this);
986 m_sentFrameTo.clear();
987
988 // Upon a transmission success, a non-QoS station transmits the next fragment,
989 // if any, or releases the channel, otherwise
990 if (m_moreFragments)
991 {
992 NS_LOG_DEBUG("Schedule transmission of next fragment in a SIFS");
993 Simulator::Schedule(m_phy->GetSifs(),
994 &FrameExchangeManager::StartTransmission,
995 this,
996 m_dcf,
997 m_allowedWidth);
998 m_moreFragments = false;
999 }
1000 else
1001 {
1002 NotifyChannelReleased(m_dcf);
1003 m_dcf = nullptr;
1004 }
1005}
1006
1007void
1008FrameExchangeManager::TransmissionFailed(bool forceCurrentCw)
1009{
1010 NS_LOG_FUNCTION(this << forceCurrentCw);
1011 if (!forceCurrentCw)
1012 {
1013 m_dcf->UpdateFailedCw(m_linkId);
1014 }
1015 m_sentFrameTo.clear();
1016 // reset TXNAV because transmission failed
1017 ResetTxNav();
1018 // A non-QoS station always releases the channel upon a transmission failure
1019 NotifyChannelReleased(m_dcf);
1020 m_dcf = nullptr;
1021}
1022
1023void
1024FrameExchangeManager::NotifyChannelReleased(Ptr<Txop> txop)
1025{
1026 NS_LOG_FUNCTION(this << txop);
1027 txop->NotifyChannelReleased(m_linkId);
1028 m_protectedStas.clear();
1029}
1030
1032FrameExchangeManager::DropMpduIfRetryLimitReached(Ptr<WifiPsdu> psdu)
1033{
1034 NS_LOG_FUNCTION(this << *psdu);
1035
1036 const auto mpdusToDrop = GetWifiRemoteStationManager()->GetMpdusToDropOnTxFailure(psdu);
1037 Ptr<WifiMpdu> droppedMpdu{nullptr};
1038
1039 for (const auto& mpdu : mpdusToDrop)
1040 {
1041 // this MPDU needs to be dropped
1042 droppedMpdu = mpdu;
1043 NotifyPacketDiscarded(mpdu);
1044 DequeueMpdu(mpdu);
1045 }
1046
1047 return droppedMpdu;
1048}
1049
1050void
1051FrameExchangeManager::NormalAckTimeout(Ptr<WifiMpdu> mpdu, const WifiTxVector& txVector)
1052{
1053 NS_LOG_FUNCTION(this << *mpdu << txVector);
1054
1055 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1056 if (auto droppedMpdu = DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1057 {
1058 // notify remote station manager if at least an MPDU was dropped
1059 GetWifiRemoteStationManager()->ReportFinalDataFailed(droppedMpdu);
1060 }
1061
1062 // the MPDU may have been dropped due to lifetime expiration or maximum amount of
1063 // retransmissions reached
1064 if (mpdu->IsQueued())
1065 {
1066 mpdu = m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu);
1067 mpdu->ResetInFlight(m_linkId);
1068 mpdu->GetHeader().SetRetry();
1069 RetransmitMpduAfterMissedAck(mpdu);
1070 }
1071
1072 m_mpdu = nullptr;
1073 TransmissionFailed();
1074}
1075
1076void
1077FrameExchangeManager::RetransmitMpduAfterMissedAck(Ptr<WifiMpdu> mpdu) const
1078{
1079 NS_LOG_FUNCTION(this << *mpdu);
1080}
1081
1082void
1083FrameExchangeManager::CtsTimeout(Ptr<WifiMpdu> rts, const WifiTxVector& txVector)
1084{
1085 NS_LOG_FUNCTION(this << *rts << txVector);
1086
1087 DoCtsTimeout(WifiPsduMap{{SU_STA_ID, Create<WifiPsdu>(m_mpdu, true)}});
1088 m_mpdu = nullptr;
1089}
1090
1091void
1092FrameExchangeManager::DoCtsTimeout(const WifiPsduMap& psduMap)
1093{
1094 NS_LOG_FUNCTION(this << psduMap);
1095
1096 // these functions need to be called before resetting m_sentRtsTo
1097 const auto updateCw = GetUpdateCwOnCtsTimeout();
1098 const auto reportRts = GetReportRtsFailed();
1099
1100 m_sentRtsTo.clear();
1101 for (const auto& [staId, psdu] : psduMap)
1102 {
1103 for (const auto& mpdu : *PeekPointer(psdu))
1104 {
1105 if (mpdu->IsQueued())
1106 {
1107 mpdu->ResetInFlight(m_linkId);
1108 }
1109 }
1110
1111 if (const auto& hdr = psdu->GetHeader(0);
1113 {
1114 if (reportRts)
1115 {
1116 GetWifiRemoteStationManager()->ReportRtsFailed(hdr);
1117 }
1118
1119 if (auto droppedMpdu = DropMpduIfRetryLimitReached(psdu))
1120 {
1121 GetWifiRemoteStationManager()->ReportFinalRtsFailed(droppedMpdu->GetHeader());
1122 }
1123 }
1124
1125 // Make the sequence numbers of the MPDUs available again if the MPDUs have never
1126 // been transmitted, both in case the MPDUs have been discarded and in case the
1127 // MPDUs have to be transmitted (because a new sequence number is assigned to
1128 // MPDUs that have never been transmitted and are selected for transmission)
1129 ReleaseSequenceNumbers(psdu);
1130 }
1131
1132 TransmissionFailed(!updateCw);
1133}
1134
1135bool
1136FrameExchangeManager::GetUpdateCwOnCtsTimeout() const
1137{
1138 return true;
1139}
1140
1141bool
1142FrameExchangeManager::GetReportRtsFailed() const
1143{
1144 return true;
1145}
1146
1147void
1148FrameExchangeManager::ReleaseSequenceNumbers(Ptr<const WifiPsdu> psdu) const
1149{
1150 NS_LOG_FUNCTION(this << *psdu);
1151
1152 NS_ASSERT_MSG(psdu->GetNMpdus() == 1, "A-MPDUs should be handled by the HT FEM override");
1153 auto mpdu = *psdu->begin();
1154
1155 // the MPDU should be still in the DCF queue, unless it expired.
1156 // If the MPDU has never been transmitted and is not in-flight, it will be assigned
1157 // a sequence number again the next time we try to transmit it. Therefore, we need to
1158 // make its sequence number available again
1159 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
1160 {
1161 mpdu->UnassignSeqNo();
1162 m_txMiddle->SetSequenceNumberFor(&mpdu->GetOriginal()->GetHeader());
1163 }
1164}
1165
1166void
1167FrameExchangeManager::NotifyInternalCollision(Ptr<Txop> txop)
1168{
1169 NS_LOG_FUNCTION(this);
1170
1171 // For internal collisions, the frame retry counts associated with the MSDUs, A-MSDUs, or MMPDUs
1172 // involved in the internal collision shall be incremented. (Sec. 10.23.2.12.1 of 802.11-2020)
1173 // We do not prepare the PSDU that the AC losing the internal collision would have
1174 // sent. As an approximation, we consider the frame peeked from the queues of the AC.
1175 Ptr<QosTxop> qosTxop = (txop->IsQosTxop() ? StaticCast<QosTxop>(txop) : nullptr);
1176
1177 if (auto mpdu =
1178 (qosTxop ? qosTxop->PeekNextMpdu(m_linkId) : txop->GetWifiMacQueue()->Peek(m_linkId));
1179 mpdu && !mpdu->GetHeader().GetAddr1().IsGroup())
1180 {
1181 if (mpdu->GetHeader().HasData())
1182 {
1183 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1184 }
1185
1186 if (DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1187 {
1188 GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
1189 }
1190 }
1191
1192 txop->UpdateFailedCw(m_linkId);
1193 txop->Txop::NotifyChannelReleased(m_linkId);
1194}
1195
1196void
1197FrameExchangeManager::NotifySwitchingStartNow(Time duration)
1198{
1199 NS_LOG_DEBUG("Switching channel. Cancelling MAC pending events");
1200 Simulator::Schedule(duration, &WifiMac::NotifyChannelSwitching, m_mac, m_linkId);
1201 if (m_txTimer.IsRunning())
1202 {
1203 // we were transmitting something before channel switching. Since we will
1204 // not be able to receive the response, have the timer expire now, so that
1205 // we perform the actions required in case of missing response
1206 m_txTimer.Reschedule(Seconds(0));
1207 }
1208 Simulator::ScheduleNow(&FrameExchangeManager::Reset, this);
1209}
1210
1211void
1212FrameExchangeManager::NotifySleepNow()
1213{
1214 NS_LOG_DEBUG("Device in sleep mode. Cancelling MAC pending events");
1215 Reset();
1216}
1217
1218void
1219FrameExchangeManager::NotifyOffNow()
1220{
1221 NS_LOG_DEBUG("Device is switched off. Cancelling MAC pending events");
1222 Reset();
1223}
1224
1225void
1226FrameExchangeManager::PsduRxError(Ptr<const WifiPsdu> psdu)
1227{
1228 NS_LOG_FUNCTION(this << psdu);
1229}
1230
1231void
1232FrameExchangeManager::Receive(Ptr<const WifiPsdu> psdu,
1233 RxSignalInfo rxSignalInfo,
1234 const WifiTxVector& txVector,
1235 const std::vector<bool>& perMpduStatus)
1236{
1238 this << psdu << rxSignalInfo << txVector << perMpduStatus.size()
1239 << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](bool v) { return v; }));
1240
1241 if (!perMpduStatus.empty())
1242 {
1243 // for A-MPDUs, we get here only once
1244 PreProcessFrame(psdu, txVector);
1245 }
1246
1247 Mac48Address addr1 = psdu->GetAddr1();
1248
1249 if (addr1.IsGroup() || addr1 == m_self)
1250 {
1251 // receive broadcast frames or frames addressed to us only
1252 if (psdu->GetNMpdus() == 1)
1253 {
1254 // if perMpduStatus is not empty (i.e., this MPDU is not included in an A-MPDU)
1255 // then it must contain a single value which must be true (i.e., the MPDU
1256 // has been correctly received)
1257 NS_ASSERT(perMpduStatus.empty() || (perMpduStatus.size() == 1 && perMpduStatus[0]));
1258 // Ack and CTS do not carry Addr2
1259 if (const auto& hdr = psdu->GetHeader(0); !hdr.IsAck() && !hdr.IsCts())
1260 {
1261 GetWifiRemoteStationManager()->ReportRxOk(psdu->GetAddr2(), rxSignalInfo, txVector);
1262 }
1263 ReceiveMpdu(*(psdu->begin()), rxSignalInfo, txVector, perMpduStatus.empty());
1264 }
1265 else
1266 {
1267 EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1268 }
1269 }
1270 else if (m_promisc)
1271 {
1272 for (const auto& mpdu : *PeekPointer(psdu))
1273 {
1274 if (!mpdu->GetHeader().IsCtl())
1275 {
1276 m_rxMiddle->Receive(mpdu, m_linkId);
1277 }
1278 }
1279 }
1280
1281 if (!perMpduStatus.empty())
1282 {
1283 // for A-MPDUs, we get here only once
1284 PostProcessFrame(psdu, txVector);
1285 }
1286}
1287
1288void
1289FrameExchangeManager::PreProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1290{
1291 NS_LOG_FUNCTION(this << psdu << txVector);
1292}
1293
1294void
1295FrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1296{
1297 NS_LOG_FUNCTION(this << psdu << txVector);
1298
1299 UpdateNav(psdu->GetHeader(0), txVector);
1300}
1301
1302void
1303FrameExchangeManager::UpdateNav(const WifiMacHeader& hdr,
1304 const WifiTxVector& txVector,
1305 const Time& surplus)
1306{
1307 NS_LOG_FUNCTION(this << hdr << txVector << surplus.As(Time::US));
1308
1309 if (!hdr.HasNav())
1310 {
1311 return;
1312 }
1313
1314 Time duration = hdr.GetDuration();
1315 NS_LOG_DEBUG("Duration/ID=" << duration);
1316 duration += surplus;
1317
1318 if (hdr.GetAddr1() == m_self)
1319 {
1320 // When the received frame's RA is equal to the STA's own MAC address, the STA
1321 // shall not update its NAV (IEEE 802.11-2016, sec. 10.3.2.4)
1322 return;
1323 }
1324
1325 // For all other received frames the STA shall update its NAV when the received
1326 // Duration is greater than the STA's current NAV value (IEEE 802.11-2016 sec. 10.3.2.4)
1327 Time navEnd = Simulator::Now() + duration;
1328 if (navEnd > m_navEnd)
1329 {
1330 m_navEnd = navEnd;
1331 NS_LOG_DEBUG("Updated NAV=" << m_navEnd);
1332
1333 // A STA that used information from an RTS frame as the most recent basis to update
1334 // its NAV setting is permitted to reset its NAV if no PHY-RXSTART.indication
1335 // primitive is received from the PHY during a NAVTimeout period starting when the
1336 // MAC receives a PHY-RXEND.indication primitive corresponding to the detection of
1337 // the RTS frame. NAVTimeout period is equal to:
1338 // (2 x aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 x aSlotTime)
1339 // The “CTS_Time” shall be calculated using the length of the CTS frame and the data
1340 // rate at which the RTS frame used for the most recent NAV update was received
1341 // (IEEE 802.11-2016 sec. 10.3.2.4)
1342 if (hdr.IsRts())
1343 {
1344 auto addr2 = hdr.GetAddr2();
1345 WifiTxVector ctsTxVector =
1346 GetWifiRemoteStationManager()->GetCtsTxVector(addr2, txVector.GetMode());
1347 Time navResetDelay =
1348 2 * m_phy->GetSifs() +
1349 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1350 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
1351 m_navResetEvent.Cancel();
1352 m_navResetEvent =
1353 Simulator::Schedule(navResetDelay, &FrameExchangeManager::NavResetTimeout, this);
1354 }
1355 }
1356 NS_LOG_DEBUG("Current NAV=" << m_navEnd);
1357
1358 m_channelAccessManager->NotifyNavStartNow(duration);
1359}
1360
1361void
1362FrameExchangeManager::NavResetTimeout()
1363{
1364 NS_LOG_FUNCTION(this);
1365 m_navEnd = Simulator::Now();
1366 m_channelAccessManager->NotifyNavResetNow(Seconds(0));
1367}
1368
1369void
1370FrameExchangeManager::SetTxNav(Ptr<const WifiMpdu> mpdu, const Time& txDuration)
1371{
1372 // The TXNAV timer is a single timer, shared by the EDCAFs within a STA, that is initialized
1373 // with the duration from the Duration/ID field in the frame most recently successfully
1374 // transmitted by the TXOP holder, except for PS-Poll frames. The TXNAV timer begins counting
1375 // down from the end of the transmission of the PPDU containing that frame.
1376 // (Sec.10.23.2.2 IEEE 802.11-2020)
1377 if (!mpdu->GetHeader().IsPsPoll())
1378 {
1379 const auto txNav = Simulator::Now() + txDuration + mpdu->GetHeader().GetDuration();
1380 NS_LOG_DEBUG("Setting TXNAV to " << txNav.As(Time::S));
1381 m_txNav = Max(m_txNav, txNav);
1382 }
1383}
1384
1385void
1386FrameExchangeManager::ResetTxNav()
1387{
1388 NS_LOG_FUNCTION(this);
1389 m_txNav = Simulator::Now();
1390}
1391
1392bool
1393FrameExchangeManager::VirtualCsMediumIdle() const
1394{
1395 return m_navEnd <= Simulator::Now();
1396}
1397
1398void
1399FrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
1400 RxSignalInfo rxSignalInfo,
1401 const WifiTxVector& txVector,
1402 bool inAmpdu)
1403{
1404 NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1405 // The received MPDU is either broadcast or addressed to this station
1406 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1407
1408 double rxSnr = rxSignalInfo.snr;
1409 const WifiMacHeader& hdr = mpdu->GetHeader();
1410
1411 if (hdr.IsCtl())
1412 {
1413 if (hdr.IsRts())
1414 {
1415 NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
1416
1417 // A non-VHT STA that is addressed by an RTS frame behaves as follows:
1418 // - If the NAV indicates idle, the STA shall respond with a CTS frame after a SIFS
1419 // - Otherwise, the STA shall not respond with a CTS frame
1420 // (IEEE 802.11-2016 sec. 10.3.2.7)
1421 if (VirtualCsMediumIdle())
1422 {
1423 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
1424 m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
1425 &FrameExchangeManager::SendCtsAfterRts,
1426 this,
1427 hdr,
1428 txVector,
1429 rxSnr);
1430 }
1431 else
1432 {
1433 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
1434 }
1435 }
1436 else if (hdr.IsCts() && m_txTimer.IsRunning() &&
1437 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_mpdu)
1438 {
1439 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1440 NS_ASSERT(hdr.GetAddr1() == m_self);
1441
1442 const auto sender = GetIndividuallyAddressedRecipient(m_mac, m_mpdu->GetHeader());
1443 NS_LOG_DEBUG("Received CTS from=" << sender);
1444
1445 SnrTag tag;
1446 mpdu->GetPacket()->PeekPacketTag(tag);
1447 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1448 GetWifiRemoteStationManager()->ReportRtsOk(m_mpdu->GetHeader(),
1449 rxSnr,
1450 txVector.GetMode(),
1451 tag.Get());
1452
1453 m_txTimer.Cancel();
1454 m_channelAccessManager->NotifyCtsTimeoutResetNow();
1455 ProtectionCompleted();
1456 }
1457 else if (hdr.IsAck() && m_mpdu && m_txTimer.IsRunning() &&
1458 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK)
1459 {
1460 NS_ASSERT(hdr.GetAddr1() == m_self);
1461 SnrTag tag;
1462 mpdu->GetPacket()->PeekPacketTag(tag);
1463 ReceivedNormalAck(m_mpdu, m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get());
1464 m_mpdu = nullptr;
1465 }
1466 }
1467 else if (hdr.IsMgt())
1468 {
1469 NS_ABORT_MSG_IF(inAmpdu, "Received management frame as part of an A-MPDU");
1470
1471 if (hdr.IsBeacon() || hdr.IsProbeResp())
1472 {
1473 // Apply SNR tag for beacon quality measurements
1474 SnrTag tag;
1475 tag.Set(rxSnr);
1476 Ptr<Packet> packet = mpdu->GetPacket()->Copy();
1477 packet->AddPacketTag(tag);
1478 mpdu = Create<WifiMpdu>(packet, hdr);
1479 }
1480
1481 if (hdr.GetAddr1() == m_self)
1482 {
1483 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1484 << ", schedule ACK");
1485 Simulator::Schedule(m_phy->GetSifs(),
1486 &FrameExchangeManager::SendNormalAck,
1487 this,
1488 hdr,
1489 txVector,
1490 rxSnr);
1491 }
1492
1493 m_rxMiddle->Receive(mpdu, m_linkId);
1494 }
1495 else if (hdr.IsData() && !hdr.IsQosData())
1496 {
1497 if (hdr.GetAddr1() == m_self)
1498 {
1499 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1500 << ", schedule ACK");
1501 Simulator::Schedule(m_phy->GetSifs(),
1502 &FrameExchangeManager::SendNormalAck,
1503 this,
1504 hdr,
1505 txVector,
1506 rxSnr);
1507 }
1508
1509 m_rxMiddle->Receive(mpdu, m_linkId);
1510 }
1511}
1512
1513void
1514FrameExchangeManager::ReceivedNormalAck(Ptr<WifiMpdu> mpdu,
1515 const WifiTxVector& txVector,
1516 const WifiTxVector& ackTxVector,
1517 const RxSignalInfo& rxInfo,
1518 double snr)
1519{
1520 Mac48Address sender = mpdu->GetHeader().GetAddr1();
1521 NS_LOG_DEBUG("Received ACK from=" << sender);
1522 m_txTimer.GotResponseFrom(sender);
1523
1524 NotifyReceivedNormalAck(mpdu);
1525
1526 // When fragmentation is used, only update manager when the last fragment is acknowledged
1527 if (!mpdu->GetHeader().IsMoreFragments())
1528 {
1529 GetWifiRemoteStationManager()->ReportRxOk(sender, rxInfo, ackTxVector);
1530 GetWifiRemoteStationManager()->ReportDataOk(mpdu,
1531 rxInfo.snr,
1532 ackTxVector.GetMode(),
1533 snr,
1534 txVector);
1535 }
1536 // cancel the timer
1537 m_txTimer.Cancel();
1538 m_channelAccessManager->NotifyAckTimeoutResetNow();
1539
1540 // The CW shall be reset to aCWmin after every successful attempt to transmit
1541 // a frame containing all or part of an MSDU or MMPDU (sec. 10.3.3 of 802.11-2016)
1542 m_dcf->ResetCw(m_linkId);
1543
1544 if (mpdu->GetHeader().IsMoreFragments())
1545 {
1546 // replace the current fragment with the next one
1547 m_dcf->GetWifiMacQueue()->Replace(mpdu, GetNextFragment());
1548 m_moreFragments = true;
1549 }
1550 else
1551 {
1552 // the MPDU has been acknowledged, we can now dequeue it if it is stored in a queue
1553 DequeueMpdu(mpdu);
1554 }
1555
1556 TransmissionSucceeded();
1557}
1558
1559void
1560FrameExchangeManager::NotifyReceivedNormalAck(Ptr<WifiMpdu> mpdu)
1561{
1562 NS_LOG_FUNCTION(this << *mpdu);
1563
1564 // inform the MAC that the transmission was successful
1565 if (!m_ackedMpduCallback.IsNull())
1566 {
1567 m_ackedMpduCallback(mpdu);
1568 }
1569}
1570
1571void
1572FrameExchangeManager::EndReceiveAmpdu(Ptr<const WifiPsdu> psdu,
1573 const RxSignalInfo& rxSignalInfo,
1574 const WifiTxVector& txVector,
1575 const std::vector<bool>& perMpduStatus)
1576{
1577 NS_ASSERT_MSG(false, "A non-QoS station should not receive an A-MPDU");
1578}
1579
1580void
1581FrameExchangeManager::NotifyLastGcrUrTx(Ptr<const WifiMpdu> mpdu)
1582{
1583 NS_ASSERT_MSG(false, "A non-QoS station should not use GCR-UR");
1584}
1585
1586} // namespace ns3
#define Max(a, b)
AttributeValue implementation for Boolean.
Definition boolean.h:26
bool IsNull() const
Check for null implementation.
Definition callback.h:555
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
Ptr< WifiMpdu > m_mpdu
the MPDU being transmitted
virtual void SetAckManager(Ptr< WifiAckManager > ackManager)
Set the Acknowledgment Manager to use.
virtual void NotifyLastGcrUrTx(Ptr< const WifiMpdu > mpdu)
Notify the last (re)transmission of a groupcast MPDU using the GCR-UR service.
static TypeId GetTypeId()
Get the type ID.
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
DroppedMpdu m_droppedMpduCallback
the dropped MPDU callback
bool m_protectedIfResponded
whether a STA is assumed to be protected if replied to a frame requiring acknowledgment
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the MAC layer to use.
virtual void ResetPhy()
Remove WifiPhy associated with this FrameExchangeManager.
void SendMpduWithProtection(Ptr< WifiMpdu > mpdu, WifiTxParameters &txParams)
Send an MPDU with the given TX parameters (with the specified protection).
Ptr< WifiAckManager > m_ackManager
Acknowledgment manager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
void UpdateTxDuration(Mac48Address receiver, WifiTxParameters &txParams) const
Update the TX duration field of the given TX parameters after that the PSDU addressed to the given re...
virtual void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
Ptr< Packet > m_fragmentedPacket
the MSDU being fragmented
virtual void SetDroppedMpduCallback(DroppedMpdu callback)
Set the callback to invoke when an MPDU is dropped.
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
virtual void NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu)
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
std::optional< std::reference_wrapper< const WifiMacHeader > > GetReceivedMacHdr() const
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.
Ptr< WifiProtectionManager > m_protectionManager
Protection manager.
OngoingRxInfo m_ongoingRxInfo
information about the MAC header of the MPDU being received
virtual void ProtectionCompleted()
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
virtual void SetLinkId(uint8_t linkId)
Set the ID of the link this Frame Exchange Manager is associated with.
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
virtual void NormalAckTimeout(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector)
Called when the Ack timeout expires.
virtual void SetBssid(Mac48Address bssid)
Set the Basic Service Set Identification.
void SendCtsToSelf(const WifiTxParameters &txParams)
Send CTS for a CTS-to-self mechanism.
virtual void ReceivedMacHdr(const WifiMacHeader &macHdr, const WifiTxVector &txVector, Time psduDuration)
Store information about the MAC header of the MPDU being received.
std::optional< std::reference_wrapper< const OngoingRxInfo > > GetOngoingRxInfo() const
virtual void SetAddress(Mac48Address address)
Set the MAC address.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
virtual void DequeueMpdu(Ptr< const WifiMpdu > mpdu)
Dequeue the given MPDU from the queue in which it is stored.
const std::set< Mac48Address > & GetProtectedStas() const
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
bool IsPromisc() const
Check if the device is operating in promiscuous mode.
void SendMpdu()
Send the current MPDU, which can be acknowledged by a Normal Ack.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
virtual void TransmissionSucceeded()
Take necessary actions upon a transmission success.
Ptr< Txop > m_dcf
the DCF/EDCAF that gained channel access
EventId m_sendCtsEvent
the event to send a CTS after an (MU-)RTS
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< WifiMpdu > GetFirstFragmentIfNeeded(Ptr< WifiMpdu > mpdu)
Fragment the given MPDU if needed.
void SetAckedMpduCallback(AckedMpdu callback)
Set the callback to invoke when an MPDU is successfully acked.
Ptr< ApWifiMac > m_apMac
AP MAC layer pointer (null if not an AP)
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual void SetWifiPhy(const Ptr< WifiPhy > phy)
Set the PHY layer to use.
void Receive(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
This method is intended to be called by the PHY layer every time an MPDU is received and also when th...
AckedMpdu m_ackedMpduCallback
the acknowledged MPDU callback
virtual uint32_t GetPsduSize(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector) const
Get the size in bytes of the given MPDU, which is to be transmitted with the given TXVECTOR.
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
bool m_promisc
Flag if the device is operating in promiscuous mode.
virtual void SetChannelAccessManager(const Ptr< ChannelAccessManager > channelAccessManager)
Set the channel access manager to use.
virtual bool StartTransmission(Ptr< Txop > dcf, MHz_u allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
void SetPromisc()
Enable promiscuous mode.
MHz_u m_allowedWidth
the allowed width for the current transmission
virtual void PsduRxError(Ptr< const WifiPsdu > psdu)
This method is called when the reception of a PSDU fails.
Time m_navEnd
NAV expiration time.
virtual void UpdateNav(const WifiMacHeader &hdr, const WifiTxVector &txVector, const Time &surplus=Time{0})
Update the NAV, if needed, based on the Duration/ID of the given MAC header and the given surplus.
virtual void SetMacTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set the MAC TX Middle to use.
virtual void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
virtual void SetProtectionManager(Ptr< WifiProtectionManager > protectionManager)
Set the Protection Manager to use.
Mac48Address GetBssid() const
Get the Basic Service Set Identification.
Ptr< StaWifiMac > m_staMac
STA MAC layer pointer (null if not a STA)
void DoDispose() override
Destructor implementation.
WifiTxParameters m_txParams
the TX parameters for the current frame
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
EventId m_navResetEvent
the event to reset the NAV after an RTS
const WifiTxTimer & GetWifiTxTimer() const
Get a const reference to the WifiTxTimer object.
an EUI-48 address
bool IsGroup() const
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
bool TraceDisconnectWithoutContext(std::string name, const CallbackBase &cb)
Disconnect from a TraceSource a Callback previously connected without a context.
A base class which provides memory management and object aggregation.
Definition object.h:78
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Create a new packet which contains a fragment of the original packet.
Definition packet.cc:227
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Introspection did not find any typical Config paths.
Definition snr-tag.h:24
void Set(double snr)
Set the SNR to the given value.
Definition snr-tag.cc:73
double Get() const
Return the SNR value.
Definition snr-tag.cc:79
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:403
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:340
@ US
microsecond
Definition nstime.h:107
@ MS
millisecond
Definition nstime.h:106
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
Definition nstime.h:331
virtual void NotifyChannelAccessed(uint8_t linkId, Time txopDuration=Seconds(0))
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
Definition txop.cc:769
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
static void SetQosAckPolicy(Ptr< WifiMpdu > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
Implements the IEEE 802.11 MAC header.
bool IsAck() const
Return true if the header is an Ack header.
bool IsCts() const
Return true if the header is a CTS header.
bool IsBeacon() const
Return true if the header is a Beacon header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsMoreFragments() const
Return if the More Fragment bit is set.
void SetNoMoreFragments()
Un-set the More Fragment bit in the Frame Control Field.
bool IsMgt() const
Return true if the Type is Management.
bool IsCtl() const
Return true if the Type is Control.
Time GetDuration() const
Return the duration from the Duration/ID field (Time object).
virtual uint32_t GetSize() const
Return the size of the WifiMacHeader in octets.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsProbeResp() const
Return true if the header is a Probe Response header.
void SetMoreFragments()
Set the More Fragment bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
virtual const char * GetTypeString() const
Return a string corresponds to the header type.
void SetDuration(Time duration)
Set the Duration/ID field with the given duration (Time object).
bool IsData() const
Return true if the Type is DATA.
bool IsRts() const
Return true if the header is a RTS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
uint8_t GetFragmentNumber() const
Return the fragment number of the header.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
void SetFragmentNumber(uint8_t frag)
Set the fragment number of the header.
void SetNoRetry()
Un-set the Retry bit in the Frame Control field.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition wifi-phy.cc:837
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition wifi-phy.cc:492
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition wifi-phy.cc:480
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1057
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:486
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1556
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
const PsduInfoMap & GetPsduInfoMap() const
Get a const reference to the map containing information about PSDUs.
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMpdu > mpdu)
Record that an MPDU is being added to the current frame.
void Clear()
Reset the TX parameters.
This class is used to handle the timer that a station starts when transmitting a frame that solicits ...
bool IsRunning() const
Return true if the timer is running.
void Cancel()
Cancel the timer.
void Reschedule(const Time &delay)
Reschedule the timer to time out the given amount of time from the moment this function is called.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
MHz_u GetChannelWidth() const
#define PSDU_DURATION_SAFEGUARD
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
@ STA
Definition wifi-mac.h:59
@ AP
Definition wifi-mac.h:60
@ WIFI_MAC_DROP_REACHED_RETRY_LIMIT
Definition wifi-mac.h:74
@ WIFI_PM_SWITCHING_TO_ACTIVE
@ WIFI_PM_POWERSAVE
@ WIFI_PM_SWITCHING_TO_PS
@ WIFI_PM_ACTIVE
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Definition wifi-utils.cc:98
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
Definition wifi-mac.h:78
@ WIFI_MAC_CTL_RTS
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_CTL_ACK
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
Definition wifi-utils.cc:53
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
Mac48Address GetIndividuallyAddressedRecipient(Ptr< WifiMac > mac, const WifiMacHeader &hdr)
Get the MAC address of the individually addressed recipient to use for a given packet.
ns3::Time timeout
Time endOfPsduRx
time when reception of PSDU ends
std::optional< WifiMacHeader > macHdr
MAC header of the MPDU being received.
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:78
double snr
SNR in linear scale.
Definition wifi-types.h:79
WifiAcknowledgment is an abstract base struct.
const Method method
acknowledgment method
std::optional< Time > acknowledgmentTime
time required by the acknowledgment method
WifiCtsToSelfProtection specifies that CTS-to-self protection method is used.
WifiNormalAck specifies that acknowledgment via Normal Ack is required.
WifiProtection is an abstract base struct.
std::optional< Time > protectionTime
time required by the protection method
const Method method
protection method
WifiRtsCtsProtection specifies that RTS/CTS protection method is used.