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}
326
327std::optional<std::reference_wrapper<const FrameExchangeManager::OngoingRxInfo>>
329{
331 {
332 return m_ongoingRxInfo;
333 }
334 return std::nullopt;
335}
336
337std::optional<std::reference_wrapper<const WifiMacHeader>>
339{
340 if (auto info = GetOngoingRxInfo(); info.has_value() && info->get().macHdr.has_value())
341 {
342 return info->get().macHdr.value();
343 }
344 return std::nullopt;
345}
346
347bool
349{
350 NS_LOG_FUNCTION(this << dcf << allowedWidth);
351
353 if (m_txTimer.IsRunning())
354 {
356 }
357 m_dcf = dcf;
358 m_allowedWidth = allowedWidth;
359
360 Ptr<WifiMacQueue> queue = dcf->GetWifiMacQueue();
361
362 // Even though channel access is requested when the queue is not empty, at
363 // the time channel access is granted the lifetime of the packet might be
364 // expired and the queue might be empty.
365 queue->WipeAllExpiredMpdus();
366
367 Ptr<WifiMpdu> mpdu = queue->Peek(m_linkId);
368
369 if (!mpdu)
370 {
371 NS_LOG_DEBUG("Queue empty");
373 m_dcf = nullptr;
374 return false;
375 }
376
378
379 NS_ASSERT(mpdu->GetHeader().IsData() || mpdu->GetHeader().IsMgt());
380
381 // assign a sequence number if this is not a fragment nor a retransmission
382 if (!mpdu->IsFragment() && !mpdu->GetHeader().IsRetry())
383 {
384 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
385 mpdu->AssignSeqNo(sequence);
386 }
387
388 NS_LOG_DEBUG("MPDU payload size=" << mpdu->GetPacketSize()
389 << ", to=" << mpdu->GetHeader().GetAddr1()
390 << ", seq=" << mpdu->GetHeader().GetSequenceControl());
391
392 // check if the MSDU needs to be fragmented
393 mpdu = GetFirstFragmentIfNeeded(mpdu);
394
397 WifiTxParameters txParams;
398 txParams.m_txVector =
399 GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
400 txParams.AddMpdu(mpdu);
401 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
402 txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
403 txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
404
405 SendMpduWithProtection(mpdu, txParams);
406
407 return true;
408}
409
412{
413 NS_LOG_FUNCTION(this << *mpdu);
414
415 if (mpdu->IsFragment())
416 {
417 // a fragment cannot be further fragmented
419 }
420 else if (GetWifiRemoteStationManager()->NeedFragmentation(mpdu))
421 {
422 NS_LOG_DEBUG("Fragmenting the MSDU");
423 m_fragmentedPacket = mpdu->GetPacket()->Copy();
424 // create the first fragment
426 0,
427 GetWifiRemoteStationManager()->GetFragmentSize(mpdu, 0));
428 // enqueue the first fragment
429 Ptr<WifiMpdu> item = Create<WifiMpdu>(fragment, mpdu->GetHeader());
430 item->GetHeader().SetMoreFragments();
431 m_mac->GetTxopQueue(mpdu->GetQueueAc())->Replace(mpdu, item);
432 return item;
433 }
434 return mpdu;
435}
436
437void
439{
440 NS_LOG_FUNCTION(this << *mpdu << &txParams);
441
442 m_mpdu = mpdu;
443 m_txParams = std::move(txParams);
444
445 // If protection is required, the MPDU must be stored in some queue because
446 // it is not put back in a queue if the RTS/CTS exchange fails
448 m_mpdu->GetHeader().IsCtl() || m_mpdu->IsQueued());
449
450 // Make sure that the acknowledgment time has been computed, so that SendRts()
451 // and SendCtsToSelf() can reuse this value.
453
454 if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
455 {
457 }
458
459 // Set QoS Ack policy if this is a QoS data frame
461
462 if (m_mpdu->IsQueued())
463 {
464 m_mpdu->SetInFlight(m_linkId);
465 }
466
468}
469
470void
472{
473 NS_LOG_FUNCTION(this << &txParams);
474
475 switch (txParams.m_protection->method)
476 {
478 SendRts(txParams);
479 break;
481 SendCtsToSelf(txParams);
482 break;
485 break;
486 default:
487 NS_ABORT_MSG("Unknown protection type: " << txParams.m_protection.get());
488 }
489}
490
491void
507
508const std::set<Mac48Address>&
513
514void
516{
517 NS_LOG_FUNCTION(this);
518
521 m_phy->GetPhyBand());
522
524
526 {
527 if (m_mac->GetTypeOfStation() == AP && m_apMac->UseGcr(m_mpdu->GetHeader()))
528 {
529 if (m_apMac->GetGcrManager()->KeepGroupcastQueued(m_mpdu))
530 {
531 // keep the groupcast frame in the queue for future retransmission
532 Simulator::Schedule(txDuration + m_phy->GetSifs(), [=, this, mpdu = m_mpdu]() {
533 NS_LOG_DEBUG("Prepare groupcast MPDU for retry");
534 mpdu->ResetInFlight(m_linkId);
535 // restore addr1 to the group address instead of the concealment address
536 if (m_apMac->GetGcrManager()->UseConcealment(mpdu->GetHeader()))
537 {
538 mpdu->GetHeader().SetAddr1(mpdu->begin()->second.GetDestinationAddr());
539 }
540 mpdu->GetHeader().SetRetry();
541 });
542 }
543 else
544 {
545 if (m_apMac->GetGcrManager()->GetRetransmissionPolicy() ==
547 {
549 }
551 }
552 }
553 else if (!m_mpdu->GetHeader().IsQosData() ||
554 m_mpdu->GetHeader().GetQosAckPolicy() == WifiMacHeader::NO_ACK)
555 {
556 // No acknowledgment, hence dequeue the MPDU if it is stored in a queue
558 }
559
560 Simulator::Schedule(txDuration, [=, this]() {
562 m_mpdu = nullptr;
563 });
564 }
565 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
566 {
567 m_mpdu->GetHeader().SetDuration(
568 GetFrameDurationId(m_mpdu->GetHeader(),
569 GetPsduSize(m_mpdu, m_txParams.m_txVector),
570 m_txParams,
571 m_fragmentedPacket));
572
573 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
574 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
575 // aRxPHYStartDelay equals the time to transmit the PHY header.
576 auto normalAcknowledgment = static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
577
578 Time timeout =
579 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
580 WifiPhy::CalculatePhyPreambleAndHeaderDuration(normalAcknowledgment->ackTxVector);
581 NS_ASSERT(!m_txTimer.IsRunning());
582 m_txTimer.Set(WifiTxTimer::WAIT_NORMAL_ACK,
583 timeout,
584 {m_mpdu->GetHeader().GetAddr1()},
586 this,
587 m_mpdu,
588 m_txParams.m_txVector);
589 m_channelAccessManager->NotifyAckTimeoutStartNow(timeout);
590 }
591 else
592 {
593 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
594 << m_txParams.m_acknowledgment.get() << ")");
595 }
596
597 // transmit the MPDU
598 ForwardMpduDown(m_mpdu, m_txParams.m_txVector);
599
600 if (m_txTimer.IsRunning())
601 {
602 NS_ASSERT(m_sentFrameTo.empty());
603 m_sentFrameTo = {m_mpdu->GetHeader().GetAddr1()};
604 }
605}
606
607void
608FrameExchangeManager::ForwardMpduDown(Ptr<WifiMpdu> mpdu, WifiTxVector& txVector)
609{
610 NS_LOG_FUNCTION(this << *mpdu << txVector);
611
612 auto psdu = Create<WifiPsdu>(mpdu, false);
613 FinalizeMacHeader(psdu);
614 m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
615 auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
616 // The TXNAV timer is a single timer, shared by the EDCAFs within a STA, that is initialized
617 // with the duration from the Duration/ID field in the frame most recently successfully
618 // transmitted by the TXOP holder, except for PS-Poll frames. (Sec.10.23.2.2 IEEE 802.11-2020)
619 if (!mpdu->GetHeader().IsPsPoll())
620 {
621 m_txNav = Max(m_txNav, Simulator::Now() + txDuration + mpdu->GetHeader().GetDuration());
622 }
623 m_phy->Send(psdu, txVector);
624}
625
626void
627FrameExchangeManager::FinalizeMacHeader(Ptr<const WifiPsdu> psdu)
628{
629 NS_LOG_FUNCTION(this << psdu);
630
631 if (m_mac->GetTypeOfStation() != STA)
632 {
633 return;
634 }
635
636 auto pmMode = StaticCast<StaWifiMac>(m_mac)->GetPmMode(m_linkId);
637
638 for (const auto& mpdu : *PeekPointer(psdu))
639 {
640 switch (pmMode)
641 {
642 case WIFI_PM_ACTIVE:
644 mpdu->GetHeader().SetNoPowerManagement();
645 break;
648 mpdu->GetHeader().SetPowerManagement();
649 break;
650 default:
651 NS_ABORT_MSG("Unknown PM mode: " << +pmMode);
652 }
653 }
654}
655
656void
657FrameExchangeManager::DequeueMpdu(Ptr<const WifiMpdu> mpdu)
658{
659 NS_LOG_DEBUG(this << *mpdu);
660
661 if (mpdu->IsQueued())
662 {
663 m_mac->GetTxopQueue(mpdu->GetQueueAc())->DequeueIfQueued({mpdu});
664 }
665}
666
668FrameExchangeManager::GetPsduSize(Ptr<const WifiMpdu> mpdu, const WifiTxVector& txVector) const
669{
670 return mpdu->GetSize();
671}
672
673void
674FrameExchangeManager::CalculateProtectionTime(WifiProtection* protection) const
675{
676 NS_LOG_FUNCTION(this << protection);
677 NS_ASSERT(protection);
678
679 if (protection->method == WifiProtection::NONE)
680 {
681 protection->protectionTime = Seconds(0);
682 }
683 else if (protection->method == WifiProtection::RTS_CTS)
684 {
685 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
686 rtsCtsProtection->protectionTime =
687 WifiPhy::CalculateTxDuration(GetRtsSize(),
688 rtsCtsProtection->rtsTxVector,
689 m_phy->GetPhyBand()) +
690 WifiPhy::CalculateTxDuration(GetCtsSize(),
691 rtsCtsProtection->ctsTxVector,
692 m_phy->GetPhyBand()) +
693 2 * m_phy->GetSifs();
694 }
695 else if (protection->method == WifiProtection::CTS_TO_SELF)
696 {
697 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(protection);
698 ctsToSelfProtection->protectionTime =
699 WifiPhy::CalculateTxDuration(GetCtsSize(),
700 ctsToSelfProtection->ctsTxVector,
701 m_phy->GetPhyBand()) +
702 m_phy->GetSifs();
703 }
704}
705
706void
707FrameExchangeManager::CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const
708{
709 NS_LOG_FUNCTION(this << acknowledgment);
710 NS_ASSERT(acknowledgment);
711
712 if (acknowledgment->method == WifiAcknowledgment::NONE)
713 {
714 acknowledgment->acknowledgmentTime = Seconds(0);
715 }
716 else if (acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
717 {
718 auto normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
719 normalAcknowledgment->acknowledgmentTime =
720 m_phy->GetSifs() + WifiPhy::CalculateTxDuration(GetAckSize(),
721 normalAcknowledgment->ackTxVector,
722 m_phy->GetPhyBand());
723 }
724}
725
726Time
727FrameExchangeManager::GetTxDuration(uint32_t ppduPayloadSize,
728 Mac48Address receiver,
729 const WifiTxParameters& txParams) const
730{
731 return WifiPhy::CalculateTxDuration(ppduPayloadSize, txParams.m_txVector, m_phy->GetPhyBand());
732}
733
734void
735FrameExchangeManager::UpdateTxDuration(Mac48Address receiver, WifiTxParameters& txParams) const
736{
737 txParams.m_txDuration = GetTxDuration(txParams.GetSize(receiver), receiver, txParams);
738}
739
740Time
741FrameExchangeManager::GetFrameDurationId(const WifiMacHeader& header,
742 uint32_t size,
743 const WifiTxParameters& txParams,
744 Ptr<Packet> fragmentedPacket) const
745{
746 NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
747
748 NS_ASSERT(txParams.m_acknowledgment &&
749 txParams.m_acknowledgment->acknowledgmentTime.has_value());
750 auto durationId = *txParams.m_acknowledgment->acknowledgmentTime;
751
752 // if the current frame is a fragment followed by another fragment, we have to
753 // update the Duration/ID to cover the next fragment and the corresponding Ack
754 if (header.IsMoreFragments())
755 {
756 uint32_t payloadSize = size - header.GetSize() - WIFI_MAC_FCS_LENGTH;
757 uint32_t nextFragmentOffset = (header.GetFragmentNumber() + 1) * payloadSize;
758 uint32_t nextFragmentSize =
759 std::min(fragmentedPacket->GetSize() - nextFragmentOffset, payloadSize);
760 WifiTxVector ackTxVector =
761 GetWifiRemoteStationManager()->GetAckTxVector(header.GetAddr1(), txParams.m_txVector);
762
763 durationId += 2 * m_phy->GetSifs() +
764 WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand()) +
765 WifiPhy::CalculateTxDuration(nextFragmentSize,
766 txParams.m_txVector,
767 m_phy->GetPhyBand());
768 }
769 return durationId;
770}
771
772Time
773FrameExchangeManager::GetRtsDurationId(const WifiTxVector& rtsTxVector,
774 Time txDuration,
775 Time response) const
776{
777 NS_LOG_FUNCTION(this << rtsTxVector << txDuration << response);
778
779 WifiTxVector ctsTxVector;
780 ctsTxVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_self, rtsTxVector.GetMode());
781
782 return m_phy->GetSifs() +
783 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) /* CTS */
784 + m_phy->GetSifs() + txDuration + response;
785}
786
787void
788FrameExchangeManager::SendRts(const WifiTxParameters& txParams)
789{
790 NS_LOG_FUNCTION(this << &txParams);
791
792 NS_ASSERT(txParams.GetPsduInfoMap().size() == 1);
793
794 const auto& hdr = txParams.GetPsduInfoMap().begin()->second.header;
795 const auto receiver = GetIndividuallyAddressedRecipient(m_mac, hdr);
796
797 WifiMacHeader rts;
799 rts.SetDsNotFrom();
800 rts.SetDsNotTo();
801 rts.SetNoRetry();
802 rts.SetNoMoreFragments();
803 rts.SetAddr1(receiver);
804 rts.SetAddr2(m_self);
805
806 NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
807 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
808
809 NS_ASSERT(txParams.m_txDuration.has_value());
810 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
811 rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
812 *txParams.m_txDuration,
813 *txParams.m_acknowledgment->acknowledgmentTime));
814 Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(Create<Packet>(), rts);
815
816 // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with
817 // a value of aSIFSTime + aSlotTime + aRxPHYStartDelay (IEEE 802.11-2016 sec. 10.3.2.7).
818 // aRxPHYStartDelay equals the time to transmit the PHY header.
819 Time timeout = WifiPhy::CalculateTxDuration(GetRtsSize(),
820 rtsCtsProtection->rtsTxVector,
821 m_phy->GetPhyBand()) +
822 m_phy->GetSifs() + m_phy->GetSlot() +
823 WifiPhy::CalculatePhyPreambleAndHeaderDuration(rtsCtsProtection->ctsTxVector);
824 NS_ASSERT(!m_txTimer.IsRunning());
825 m_txTimer.Set(WifiTxTimer::WAIT_CTS,
826 timeout,
827 {receiver},
828 &FrameExchangeManager::CtsTimeout,
829 this,
830 mpdu,
831 rtsCtsProtection->rtsTxVector);
832 m_channelAccessManager->NotifyCtsTimeoutStartNow(timeout);
833 NS_ASSERT(m_sentRtsTo.empty());
834 m_sentRtsTo = {receiver};
835
836 ForwardMpduDown(mpdu, rtsCtsProtection->rtsTxVector);
837}
838
839void
840FrameExchangeManager::DoSendCtsAfterRts(const WifiMacHeader& rtsHdr,
841 WifiTxVector& ctsTxVector,
842 double rtsSnr)
843{
844 NS_LOG_FUNCTION(this << rtsHdr << ctsTxVector << rtsSnr);
845
846 WifiMacHeader cts;
848 cts.SetDsNotFrom();
849 cts.SetDsNotTo();
850 cts.SetNoMoreFragments();
851 cts.SetNoRetry();
852 cts.SetAddr1(rtsHdr.GetAddr2());
853 Time duration = rtsHdr.GetDuration() - m_phy->GetSifs() -
854 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand());
855 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
856 if (duration.IsStrictlyNegative())
857 {
858 duration = Seconds(0);
859 }
860 cts.SetDuration(duration);
861
862 Ptr<Packet> packet = Create<Packet>();
863
864 SnrTag tag;
865 tag.Set(rtsSnr);
866 packet->AddPacketTag(tag);
867
868 // CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
869 ForwardMpduDown(Create<WifiMpdu>(packet, cts), ctsTxVector);
870}
871
872void
873FrameExchangeManager::SendCtsAfterRts(const WifiMacHeader& rtsHdr,
874 WifiMode rtsTxMode,
875 double rtsSnr)
876{
877 NS_LOG_FUNCTION(this << rtsHdr << rtsTxMode << rtsSnr);
878
879 WifiTxVector ctsTxVector =
880 GetWifiRemoteStationManager()->GetCtsTxVector(rtsHdr.GetAddr2(), rtsTxMode);
881 DoSendCtsAfterRts(rtsHdr, ctsTxVector, rtsSnr);
882}
883
884Time
885FrameExchangeManager::GetCtsToSelfDurationId(const WifiTxVector& ctsTxVector,
886 Time txDuration,
887 Time response) const
888{
889 NS_LOG_FUNCTION(this << ctsTxVector << txDuration << response);
890
891 return m_phy->GetSifs() + txDuration + response;
892}
893
894void
895FrameExchangeManager::SendCtsToSelf(const WifiTxParameters& txParams)
896{
897 NS_LOG_FUNCTION(this << &txParams);
898
899 WifiMacHeader cts;
901 cts.SetDsNotFrom();
902 cts.SetDsNotTo();
903 cts.SetNoMoreFragments();
904 cts.SetNoRetry();
905 cts.SetAddr1(m_self);
906
907 NS_ASSERT(txParams.m_protection &&
908 txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
909 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
910
911 NS_ASSERT(txParams.m_txDuration.has_value());
912 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
913 cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
914 *txParams.m_txDuration,
915 *txParams.m_acknowledgment->acknowledgmentTime));
916
917 ForwardMpduDown(Create<WifiMpdu>(Create<Packet>(), cts), ctsToSelfProtection->ctsTxVector);
918
919 Time ctsDuration = WifiPhy::CalculateTxDuration(GetCtsSize(),
920 ctsToSelfProtection->ctsTxVector,
921 m_phy->GetPhyBand());
922 Simulator::Schedule(ctsDuration, &FrameExchangeManager::ProtectionCompleted, this);
923}
924
925void
926FrameExchangeManager::SendNormalAck(const WifiMacHeader& hdr,
927 const WifiTxVector& dataTxVector,
928 double dataSnr)
929{
930 NS_LOG_FUNCTION(this << hdr << dataTxVector << dataSnr);
931
932 WifiTxVector ackTxVector =
933 GetWifiRemoteStationManager()->GetAckTxVector(hdr.GetAddr2(), dataTxVector);
934 WifiMacHeader ack;
936 ack.SetDsNotFrom();
937 ack.SetDsNotTo();
938 ack.SetNoRetry();
939 ack.SetNoMoreFragments();
940 ack.SetAddr1(hdr.GetAddr2());
941 // 802.11-2016, Section 9.2.5.7: Duration/ID is received duration value
942 // minus the time to transmit the Ack frame and its SIFS interval
943 Time duration = hdr.GetDuration() - m_phy->GetSifs() -
944 WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand());
945 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
946 if (duration.IsStrictlyNegative())
947 {
948 duration = Seconds(0);
949 }
950 ack.SetDuration(duration);
951
952 Ptr<Packet> packet = Create<Packet>();
953
954 SnrTag tag;
955 tag.Set(dataSnr);
956 packet->AddPacketTag(tag);
957
958 ForwardMpduDown(Create<WifiMpdu>(packet, ack), ackTxVector);
959}
960
962FrameExchangeManager::GetNextFragment()
963{
964 NS_LOG_FUNCTION(this);
965 NS_ASSERT(m_mpdu->GetHeader().IsMoreFragments());
966
967 WifiMacHeader& hdr = m_mpdu->GetHeader();
969
970 uint32_t startOffset = hdr.GetFragmentNumber() * m_mpdu->GetPacketSize();
971 uint32_t size = m_fragmentedPacket->GetSize() - startOffset;
972
973 if (size > m_mpdu->GetPacketSize())
974 {
975 // this is not the last fragment
976 size = m_mpdu->GetPacketSize();
977 hdr.SetMoreFragments();
978 }
979 else
980 {
981 hdr.SetNoMoreFragments();
982 }
983
984 return Create<WifiMpdu>(m_fragmentedPacket->CreateFragment(startOffset, size), hdr);
985}
986
987void
988FrameExchangeManager::TransmissionSucceeded()
989{
990 NS_LOG_FUNCTION(this);
991 m_sentFrameTo.clear();
992
993 // Upon a transmission success, a non-QoS station transmits the next fragment,
994 // if any, or releases the channel, otherwise
995 if (m_moreFragments)
996 {
997 NS_LOG_DEBUG("Schedule transmission of next fragment in a SIFS");
998 Simulator::Schedule(m_phy->GetSifs(),
999 &FrameExchangeManager::StartTransmission,
1000 this,
1001 m_dcf,
1002 m_allowedWidth);
1003 m_moreFragments = false;
1004 }
1005 else
1006 {
1007 NotifyChannelReleased(m_dcf);
1008 m_dcf = nullptr;
1009 }
1010}
1011
1012void
1013FrameExchangeManager::TransmissionFailed(bool forceCurrentCw)
1014{
1015 NS_LOG_FUNCTION(this << forceCurrentCw);
1016 if (!forceCurrentCw)
1017 {
1018 m_dcf->UpdateFailedCw(m_linkId);
1019 }
1020 m_sentFrameTo.clear();
1021 // A non-QoS station always releases the channel upon a transmission failure
1022 NotifyChannelReleased(m_dcf);
1023 m_dcf = nullptr;
1024 // reset TXNAV because transmission failed
1025 m_txNav = Simulator::Now();
1026}
1027
1028void
1029FrameExchangeManager::NotifyChannelReleased(Ptr<Txop> txop)
1030{
1031 NS_LOG_FUNCTION(this << txop);
1032 txop->NotifyChannelReleased(m_linkId);
1033 m_protectedStas.clear();
1034}
1035
1037FrameExchangeManager::DropMpduIfRetryLimitReached(Ptr<WifiPsdu> psdu)
1038{
1039 NS_LOG_FUNCTION(this << *psdu);
1040
1041 const auto mpdusToDrop = GetWifiRemoteStationManager()->GetMpdusToDropOnTxFailure(psdu);
1042 Ptr<WifiMpdu> droppedMpdu{nullptr};
1043
1044 for (const auto& mpdu : mpdusToDrop)
1045 {
1046 // this MPDU needs to be dropped
1047 droppedMpdu = mpdu;
1048 NotifyPacketDiscarded(mpdu);
1049 DequeueMpdu(mpdu);
1050 }
1051
1052 return droppedMpdu;
1053}
1054
1055void
1056FrameExchangeManager::NormalAckTimeout(Ptr<WifiMpdu> mpdu, const WifiTxVector& txVector)
1057{
1058 NS_LOG_FUNCTION(this << *mpdu << txVector);
1059
1060 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1061 if (auto droppedMpdu = DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1062 {
1063 // notify remote station manager if at least an MPDU was dropped
1064 GetWifiRemoteStationManager()->ReportFinalDataFailed(droppedMpdu);
1065 }
1066
1067 // the MPDU may have been dropped due to lifetime expiration or maximum amount of
1068 // retransmissions reached
1069 if (mpdu->IsQueued())
1070 {
1071 mpdu = m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu);
1072 mpdu->ResetInFlight(m_linkId);
1073 mpdu->GetHeader().SetRetry();
1074 RetransmitMpduAfterMissedAck(mpdu);
1075 }
1076
1077 m_mpdu = nullptr;
1078 TransmissionFailed();
1079}
1080
1081void
1082FrameExchangeManager::RetransmitMpduAfterMissedAck(Ptr<WifiMpdu> mpdu) const
1083{
1084 NS_LOG_FUNCTION(this << *mpdu);
1085}
1086
1087void
1088FrameExchangeManager::CtsTimeout(Ptr<WifiMpdu> rts, const WifiTxVector& txVector)
1089{
1090 NS_LOG_FUNCTION(this << *rts << txVector);
1091
1092 DoCtsTimeout(Create<WifiPsdu>(m_mpdu, true));
1093 m_mpdu = nullptr;
1094}
1095
1096void
1097FrameExchangeManager::DoCtsTimeout(Ptr<WifiPsdu> psdu)
1098{
1099 NS_LOG_FUNCTION(this << *psdu);
1100
1101 // GetUpdateCwOnCtsTimeout() needs to be called before resetting m_sentRtsTo
1102 const auto updateCw = GetUpdateCwOnCtsTimeout();
1103
1104 m_sentRtsTo.clear();
1105 for (const auto& mpdu : *PeekPointer(psdu))
1106 {
1107 if (mpdu->IsQueued())
1108 {
1109 mpdu->ResetInFlight(m_linkId);
1110 }
1111 }
1112
1113 GetWifiRemoteStationManager()->ReportRtsFailed(psdu->GetHeader(0));
1114 if (auto droppedMpdu = DropMpduIfRetryLimitReached(psdu))
1115 {
1116 GetWifiRemoteStationManager()->ReportFinalRtsFailed(droppedMpdu->GetHeader());
1117 }
1118
1119 // Make the sequence numbers of the MPDUs available again if the MPDUs have never
1120 // been transmitted, both in case the MPDUs have been discarded and in case the
1121 // MPDUs have to be transmitted (because a new sequence number is assigned to
1122 // MPDUs that have never been transmitted and are selected for transmission)
1123 ReleaseSequenceNumbers(psdu);
1124
1125 TransmissionFailed(!updateCw);
1126}
1127
1128bool
1129FrameExchangeManager::GetUpdateCwOnCtsTimeout() const
1130{
1131 return true;
1132}
1133
1134void
1135FrameExchangeManager::ReleaseSequenceNumbers(Ptr<const WifiPsdu> psdu) const
1136{
1137 NS_LOG_FUNCTION(this << *psdu);
1138
1139 NS_ASSERT_MSG(psdu->GetNMpdus() == 1, "A-MPDUs should be handled by the HT FEM override");
1140 auto mpdu = *psdu->begin();
1141
1142 // the MPDU should be still in the DCF queue, unless it expired.
1143 // If the MPDU has never been transmitted and is not in-flight, it will be assigned
1144 // a sequence number again the next time we try to transmit it. Therefore, we need to
1145 // make its sequence number available again
1146 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
1147 {
1148 mpdu->UnassignSeqNo();
1149 m_txMiddle->SetSequenceNumberFor(&mpdu->GetOriginal()->GetHeader());
1150 }
1151}
1152
1153void
1154FrameExchangeManager::NotifyInternalCollision(Ptr<Txop> txop)
1155{
1156 NS_LOG_FUNCTION(this);
1157
1158 // For internal collisions, the frame retry counts associated with the MSDUs, A-MSDUs, or MMPDUs
1159 // involved in the internal collision shall be incremented. (Sec. 10.23.2.12.1 of 802.11-2020)
1160 // We do not prepare the PSDU that the AC losing the internal collision would have
1161 // sent. As an approximation, we consider the frame peeked from the queues of the AC.
1162 Ptr<QosTxop> qosTxop = (txop->IsQosTxop() ? StaticCast<QosTxop>(txop) : nullptr);
1163
1164 if (auto mpdu =
1165 (qosTxop ? qosTxop->PeekNextMpdu(m_linkId) : txop->GetWifiMacQueue()->Peek(m_linkId));
1166 mpdu && !mpdu->GetHeader().GetAddr1().IsGroup())
1167 {
1168 if (mpdu->GetHeader().HasData())
1169 {
1170 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1171 }
1172
1173 if (DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1174 {
1175 GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
1176 }
1177 }
1178
1179 txop->UpdateFailedCw(m_linkId);
1180 txop->Txop::NotifyChannelReleased(m_linkId);
1181}
1182
1183void
1184FrameExchangeManager::NotifySwitchingStartNow(Time duration)
1185{
1186 NS_LOG_DEBUG("Switching channel. Cancelling MAC pending events");
1187 Simulator::Schedule(duration, &WifiMac::NotifyChannelSwitching, m_mac, m_linkId);
1188 if (m_txTimer.IsRunning())
1189 {
1190 // we were transmitting something before channel switching. Since we will
1191 // not be able to receive the response, have the timer expire now, so that
1192 // we perform the actions required in case of missing response
1193 m_txTimer.Reschedule(Seconds(0));
1194 }
1195 Simulator::ScheduleNow(&FrameExchangeManager::Reset, this);
1196}
1197
1198void
1199FrameExchangeManager::NotifySleepNow()
1200{
1201 NS_LOG_DEBUG("Device in sleep mode. Cancelling MAC pending events");
1202 Reset();
1203}
1204
1205void
1206FrameExchangeManager::NotifyOffNow()
1207{
1208 NS_LOG_DEBUG("Device is switched off. Cancelling MAC pending events");
1209 Reset();
1210}
1211
1212void
1213FrameExchangeManager::PsduRxError(Ptr<const WifiPsdu> psdu)
1214{
1215 NS_LOG_FUNCTION(this << psdu);
1216}
1217
1218void
1219FrameExchangeManager::Receive(Ptr<const WifiPsdu> psdu,
1220 RxSignalInfo rxSignalInfo,
1221 const WifiTxVector& txVector,
1222 const std::vector<bool>& perMpduStatus)
1223{
1225 this << psdu << rxSignalInfo << txVector << perMpduStatus.size()
1226 << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](bool v) { return v; }));
1227
1228 if (!perMpduStatus.empty())
1229 {
1230 // for A-MPDUs, we get here only once
1231 PreProcessFrame(psdu, txVector);
1232 }
1233
1234 Mac48Address addr1 = psdu->GetAddr1();
1235
1236 if (addr1.IsGroup() || addr1 == m_self)
1237 {
1238 // receive broadcast frames or frames addressed to us only
1239 if (psdu->GetNMpdus() == 1)
1240 {
1241 // if perMpduStatus is not empty (i.e., this MPDU is not included in an A-MPDU)
1242 // then it must contain a single value which must be true (i.e., the MPDU
1243 // has been correctly received)
1244 NS_ASSERT(perMpduStatus.empty() || (perMpduStatus.size() == 1 && perMpduStatus[0]));
1245 // Ack and CTS do not carry Addr2
1246 if (!psdu->GetHeader(0).IsAck() && !psdu->GetHeader(0).IsCts())
1247 {
1248 GetWifiRemoteStationManager()->ReportRxOk(psdu->GetHeader(0).GetAddr2(),
1249 rxSignalInfo,
1250 txVector);
1251 }
1252 ReceiveMpdu(*(psdu->begin()), rxSignalInfo, txVector, perMpduStatus.empty());
1253 }
1254 else
1255 {
1256 EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1257 }
1258 }
1259 else if (m_promisc)
1260 {
1261 for (const auto& mpdu : *PeekPointer(psdu))
1262 {
1263 if (!mpdu->GetHeader().IsCtl())
1264 {
1265 m_rxMiddle->Receive(mpdu, m_linkId);
1266 }
1267 }
1268 }
1269
1270 if (!perMpduStatus.empty())
1271 {
1272 // for A-MPDUs, we get here only once
1273 PostProcessFrame(psdu, txVector);
1274 }
1275}
1276
1277void
1278FrameExchangeManager::PreProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1279{
1280 NS_LOG_FUNCTION(this << psdu << txVector);
1281}
1282
1283void
1284FrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1285{
1286 NS_LOG_FUNCTION(this << psdu << txVector);
1287
1288 UpdateNav(psdu, txVector);
1289}
1290
1291void
1292FrameExchangeManager::UpdateNav(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1293{
1294 NS_LOG_FUNCTION(this << psdu << txVector);
1295
1296 if (!psdu->HasNav())
1297 {
1298 return;
1299 }
1300
1301 Time duration = psdu->GetDuration();
1302 NS_LOG_DEBUG("Duration/ID=" << duration);
1303
1304 if (psdu->GetAddr1() == m_self)
1305 {
1306 // When the received frame's RA is equal to the STA's own MAC address, the STA
1307 // shall not update its NAV (IEEE 802.11-2016, sec. 10.3.2.4)
1308 return;
1309 }
1310
1311 // For all other received frames the STA shall update its NAV when the received
1312 // Duration is greater than the STA's current NAV value (IEEE 802.11-2016 sec. 10.3.2.4)
1313 Time navEnd = Simulator::Now() + duration;
1314 if (navEnd > m_navEnd)
1315 {
1316 m_navEnd = navEnd;
1317 NS_LOG_DEBUG("Updated NAV=" << m_navEnd);
1318
1319 // A STA that used information from an RTS frame as the most recent basis to update
1320 // its NAV setting is permitted to reset its NAV if no PHY-RXSTART.indication
1321 // primitive is received from the PHY during a NAVTimeout period starting when the
1322 // MAC receives a PHY-RXEND.indication primitive corresponding to the detection of
1323 // the RTS frame. NAVTimeout period is equal to:
1324 // (2 x aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 x aSlotTime)
1325 // The “CTS_Time” shall be calculated using the length of the CTS frame and the data
1326 // rate at which the RTS frame used for the most recent NAV update was received
1327 // (IEEE 802.11-2016 sec. 10.3.2.4)
1328 if (psdu->GetHeader(0).IsRts())
1329 {
1330 WifiTxVector ctsTxVector =
1331 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode());
1332 Time navResetDelay =
1333 2 * m_phy->GetSifs() +
1334 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1335 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
1336 m_navResetEvent =
1337 Simulator::Schedule(navResetDelay, &FrameExchangeManager::NavResetTimeout, this);
1338 }
1339 }
1340 NS_LOG_DEBUG("Current NAV=" << m_navEnd);
1341
1342 m_channelAccessManager->NotifyNavStartNow(duration);
1343}
1344
1345void
1346FrameExchangeManager::NavResetTimeout()
1347{
1348 NS_LOG_FUNCTION(this);
1349 m_navEnd = Simulator::Now();
1350 m_channelAccessManager->NotifyNavResetNow(Seconds(0));
1351}
1352
1353bool
1354FrameExchangeManager::VirtualCsMediumIdle() const
1355{
1356 return m_navEnd <= Simulator::Now();
1357}
1358
1359void
1360FrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
1361 RxSignalInfo rxSignalInfo,
1362 const WifiTxVector& txVector,
1363 bool inAmpdu)
1364{
1365 NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1366 // The received MPDU is either broadcast or addressed to this station
1367 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1368
1369 double rxSnr = rxSignalInfo.snr;
1370 const WifiMacHeader& hdr = mpdu->GetHeader();
1371
1372 if (hdr.IsCtl())
1373 {
1374 if (hdr.IsRts())
1375 {
1376 NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
1377
1378 // A non-VHT STA that is addressed by an RTS frame behaves as follows:
1379 // - If the NAV indicates idle, the STA shall respond with a CTS frame after a SIFS
1380 // - Otherwise, the STA shall not respond with a CTS frame
1381 // (IEEE 802.11-2016 sec. 10.3.2.7)
1382 if (VirtualCsMediumIdle())
1383 {
1384 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
1385 m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
1386 &FrameExchangeManager::SendCtsAfterRts,
1387 this,
1388 hdr,
1389 txVector.GetMode(),
1390 rxSnr);
1391 }
1392 else
1393 {
1394 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
1395 }
1396 }
1397 else if (hdr.IsCts() && m_txTimer.IsRunning() &&
1398 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_mpdu)
1399 {
1400 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1401 NS_ASSERT(hdr.GetAddr1() == m_self);
1402
1403 const auto sender = GetIndividuallyAddressedRecipient(m_mac, m_mpdu->GetHeader());
1404 NS_LOG_DEBUG("Received CTS from=" << sender);
1405
1406 SnrTag tag;
1407 mpdu->GetPacket()->PeekPacketTag(tag);
1408 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1409 GetWifiRemoteStationManager()->ReportRtsOk(m_mpdu->GetHeader(),
1410 rxSnr,
1411 txVector.GetMode(),
1412 tag.Get());
1413
1414 m_txTimer.Cancel();
1415 m_channelAccessManager->NotifyCtsTimeoutResetNow();
1416 ProtectionCompleted();
1417 }
1418 else if (hdr.IsAck() && m_mpdu && m_txTimer.IsRunning() &&
1419 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK)
1420 {
1421 NS_ASSERT(hdr.GetAddr1() == m_self);
1422 SnrTag tag;
1423 mpdu->GetPacket()->PeekPacketTag(tag);
1424 ReceivedNormalAck(m_mpdu, m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get());
1425 m_mpdu = nullptr;
1426 }
1427 }
1428 else if (hdr.IsMgt())
1429 {
1430 NS_ABORT_MSG_IF(inAmpdu, "Received management frame as part of an A-MPDU");
1431
1432 if (hdr.IsBeacon() || hdr.IsProbeResp())
1433 {
1434 // Apply SNR tag for beacon quality measurements
1435 SnrTag tag;
1436 tag.Set(rxSnr);
1437 Ptr<Packet> packet = mpdu->GetPacket()->Copy();
1438 packet->AddPacketTag(tag);
1439 mpdu = Create<WifiMpdu>(packet, hdr);
1440 }
1441
1442 if (hdr.GetAddr1() == m_self)
1443 {
1444 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1445 << ", schedule ACK");
1446 Simulator::Schedule(m_phy->GetSifs(),
1447 &FrameExchangeManager::SendNormalAck,
1448 this,
1449 hdr,
1450 txVector,
1451 rxSnr);
1452 }
1453
1454 m_rxMiddle->Receive(mpdu, m_linkId);
1455 }
1456 else if (hdr.IsData() && !hdr.IsQosData())
1457 {
1458 if (hdr.GetAddr1() == m_self)
1459 {
1460 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1461 << ", schedule ACK");
1462 Simulator::Schedule(m_phy->GetSifs(),
1463 &FrameExchangeManager::SendNormalAck,
1464 this,
1465 hdr,
1466 txVector,
1467 rxSnr);
1468 }
1469
1470 m_rxMiddle->Receive(mpdu, m_linkId);
1471 }
1472}
1473
1474void
1475FrameExchangeManager::ReceivedNormalAck(Ptr<WifiMpdu> mpdu,
1476 const WifiTxVector& txVector,
1477 const WifiTxVector& ackTxVector,
1478 const RxSignalInfo& rxInfo,
1479 double snr)
1480{
1481 Mac48Address sender = mpdu->GetHeader().GetAddr1();
1482 NS_LOG_DEBUG("Received ACK from=" << sender);
1483 m_txTimer.GotResponseFrom(sender);
1484
1485 NotifyReceivedNormalAck(mpdu);
1486
1487 // When fragmentation is used, only update manager when the last fragment is acknowledged
1488 if (!mpdu->GetHeader().IsMoreFragments())
1489 {
1490 GetWifiRemoteStationManager()->ReportRxOk(sender, rxInfo, ackTxVector);
1491 GetWifiRemoteStationManager()->ReportDataOk(mpdu,
1492 rxInfo.snr,
1493 ackTxVector.GetMode(),
1494 snr,
1495 txVector);
1496 }
1497 // cancel the timer
1498 m_txTimer.Cancel();
1499 m_channelAccessManager->NotifyAckTimeoutResetNow();
1500
1501 // The CW shall be reset to aCWmin after every successful attempt to transmit
1502 // a frame containing all or part of an MSDU or MMPDU (sec. 10.3.3 of 802.11-2016)
1503 m_dcf->ResetCw(m_linkId);
1504
1505 if (mpdu->GetHeader().IsMoreFragments())
1506 {
1507 // replace the current fragment with the next one
1508 m_dcf->GetWifiMacQueue()->Replace(mpdu, GetNextFragment());
1509 m_moreFragments = true;
1510 }
1511 else
1512 {
1513 // the MPDU has been acknowledged, we can now dequeue it if it is stored in a queue
1514 DequeueMpdu(mpdu);
1515 }
1516
1517 TransmissionSucceeded();
1518}
1519
1520void
1521FrameExchangeManager::NotifyReceivedNormalAck(Ptr<WifiMpdu> mpdu)
1522{
1523 NS_LOG_FUNCTION(this << *mpdu);
1524
1525 // inform the MAC that the transmission was successful
1526 if (!m_ackedMpduCallback.IsNull())
1527 {
1528 m_ackedMpduCallback(mpdu);
1529 }
1530}
1531
1532void
1533FrameExchangeManager::EndReceiveAmpdu(Ptr<const WifiPsdu> psdu,
1534 const RxSignalInfo& rxSignalInfo,
1535 const WifiTxVector& txVector,
1536 const std::vector<bool>& perMpduStatus)
1537{
1538 NS_ASSERT_MSG(false, "A non-QoS station should not receive an A-MPDU");
1539}
1540
1541void
1542FrameExchangeManager::NotifyLastGcrUrTx(Ptr<const WifiMpdu> mpdu)
1543{
1544 NS_ASSERT_MSG(false, "A non-QoS station should not use GCR-UR");
1545}
1546
1547} // namespace ns3
#define Max(a, b)
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 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:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
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:404
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:762
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.
represent a single transmission mode
Definition wifi-mode.h:40
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition wifi-phy.cc:829
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition wifi-phy.cc:484
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition wifi-phy.cc:472
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1069
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:478
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1580
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
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:1380
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
@ 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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
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:97
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
@ WIFI_MAC_CTL_RTS
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_CTL_ACK
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
Definition wifi-utils.cc:52
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:72
double snr
SNR in linear scale.
Definition wifi-types.h:73
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.