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 const WifiTxVector& rtsTxVector,
875 double rtsSnr)
876{
877 NS_LOG_FUNCTION(this << rtsHdr << rtsTxVector << rtsSnr);
878
879 WifiTxVector ctsTxVector =
880 GetWifiRemoteStationManager()->GetCtsTxVector(rtsHdr.GetAddr2(), rtsTxVector.GetMode());
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(WifiPsduMap{{SU_STA_ID, Create<WifiPsdu>(m_mpdu, true)}});
1093 m_mpdu = nullptr;
1094}
1095
1096void
1097FrameExchangeManager::DoCtsTimeout(const WifiPsduMap& psduMap)
1098{
1099 NS_LOG_FUNCTION(this << psduMap);
1100
1101 // these functions need to be called before resetting m_sentRtsTo
1102 const auto updateCw = GetUpdateCwOnCtsTimeout();
1103 const auto reportRts = GetReportRtsFailed();
1104
1105 m_sentRtsTo.clear();
1106 for (const auto& [staId, psdu] : psduMap)
1107 {
1108 for (const auto& mpdu : *PeekPointer(psdu))
1109 {
1110 if (mpdu->IsQueued())
1111 {
1112 mpdu->ResetInFlight(m_linkId);
1113 }
1114 }
1115
1116 if (const auto& hdr = psdu->GetHeader(0);
1118 {
1119 if (reportRts)
1120 {
1121 GetWifiRemoteStationManager()->ReportRtsFailed(hdr);
1122 }
1123
1124 if (auto droppedMpdu = DropMpduIfRetryLimitReached(psdu))
1125 {
1126 GetWifiRemoteStationManager()->ReportFinalRtsFailed(droppedMpdu->GetHeader());
1127 }
1128 }
1129
1130 // Make the sequence numbers of the MPDUs available again if the MPDUs have never
1131 // been transmitted, both in case the MPDUs have been discarded and in case the
1132 // MPDUs have to be transmitted (because a new sequence number is assigned to
1133 // MPDUs that have never been transmitted and are selected for transmission)
1134 ReleaseSequenceNumbers(psdu);
1135 }
1136
1137 TransmissionFailed(!updateCw);
1138}
1139
1140bool
1141FrameExchangeManager::GetUpdateCwOnCtsTimeout() const
1142{
1143 return true;
1144}
1145
1146bool
1147FrameExchangeManager::GetReportRtsFailed() const
1148{
1149 return true;
1150}
1151
1152void
1153FrameExchangeManager::ReleaseSequenceNumbers(Ptr<const WifiPsdu> psdu) const
1154{
1155 NS_LOG_FUNCTION(this << *psdu);
1156
1157 NS_ASSERT_MSG(psdu->GetNMpdus() == 1, "A-MPDUs should be handled by the HT FEM override");
1158 auto mpdu = *psdu->begin();
1159
1160 // the MPDU should be still in the DCF queue, unless it expired.
1161 // If the MPDU has never been transmitted and is not in-flight, it will be assigned
1162 // a sequence number again the next time we try to transmit it. Therefore, we need to
1163 // make its sequence number available again
1164 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
1165 {
1166 mpdu->UnassignSeqNo();
1167 m_txMiddle->SetSequenceNumberFor(&mpdu->GetOriginal()->GetHeader());
1168 }
1169}
1170
1171void
1172FrameExchangeManager::NotifyInternalCollision(Ptr<Txop> txop)
1173{
1174 NS_LOG_FUNCTION(this);
1175
1176 // For internal collisions, the frame retry counts associated with the MSDUs, A-MSDUs, or MMPDUs
1177 // involved in the internal collision shall be incremented. (Sec. 10.23.2.12.1 of 802.11-2020)
1178 // We do not prepare the PSDU that the AC losing the internal collision would have
1179 // sent. As an approximation, we consider the frame peeked from the queues of the AC.
1180 Ptr<QosTxop> qosTxop = (txop->IsQosTxop() ? StaticCast<QosTxop>(txop) : nullptr);
1181
1182 if (auto mpdu =
1183 (qosTxop ? qosTxop->PeekNextMpdu(m_linkId) : txop->GetWifiMacQueue()->Peek(m_linkId));
1184 mpdu && !mpdu->GetHeader().GetAddr1().IsGroup())
1185 {
1186 if (mpdu->GetHeader().HasData())
1187 {
1188 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1189 }
1190
1191 if (DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1192 {
1193 GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
1194 }
1195 }
1196
1197 txop->UpdateFailedCw(m_linkId);
1198 txop->Txop::NotifyChannelReleased(m_linkId);
1199}
1200
1201void
1202FrameExchangeManager::NotifySwitchingStartNow(Time duration)
1203{
1204 NS_LOG_DEBUG("Switching channel. Cancelling MAC pending events");
1205 Simulator::Schedule(duration, &WifiMac::NotifyChannelSwitching, m_mac, m_linkId);
1206 if (m_txTimer.IsRunning())
1207 {
1208 // we were transmitting something before channel switching. Since we will
1209 // not be able to receive the response, have the timer expire now, so that
1210 // we perform the actions required in case of missing response
1211 m_txTimer.Reschedule(Seconds(0));
1212 }
1213 Simulator::ScheduleNow(&FrameExchangeManager::Reset, this);
1214}
1215
1216void
1217FrameExchangeManager::NotifySleepNow()
1218{
1219 NS_LOG_DEBUG("Device in sleep mode. Cancelling MAC pending events");
1220 Reset();
1221}
1222
1223void
1224FrameExchangeManager::NotifyOffNow()
1225{
1226 NS_LOG_DEBUG("Device is switched off. Cancelling MAC pending events");
1227 Reset();
1228}
1229
1230void
1231FrameExchangeManager::PsduRxError(Ptr<const WifiPsdu> psdu)
1232{
1233 NS_LOG_FUNCTION(this << psdu);
1234}
1235
1236void
1237FrameExchangeManager::Receive(Ptr<const WifiPsdu> psdu,
1238 RxSignalInfo rxSignalInfo,
1239 const WifiTxVector& txVector,
1240 const std::vector<bool>& perMpduStatus)
1241{
1243 this << psdu << rxSignalInfo << txVector << perMpduStatus.size()
1244 << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](bool v) { return v; }));
1245
1246 if (!perMpduStatus.empty())
1247 {
1248 // for A-MPDUs, we get here only once
1249 PreProcessFrame(psdu, txVector);
1250 }
1251
1252 Mac48Address addr1 = psdu->GetAddr1();
1253
1254 if (addr1.IsGroup() || addr1 == m_self)
1255 {
1256 // receive broadcast frames or frames addressed to us only
1257 if (psdu->GetNMpdus() == 1)
1258 {
1259 // if perMpduStatus is not empty (i.e., this MPDU is not included in an A-MPDU)
1260 // then it must contain a single value which must be true (i.e., the MPDU
1261 // has been correctly received)
1262 NS_ASSERT(perMpduStatus.empty() || (perMpduStatus.size() == 1 && perMpduStatus[0]));
1263 // Ack and CTS do not carry Addr2
1264 if (!psdu->GetHeader(0).IsAck() && !psdu->GetHeader(0).IsCts())
1265 {
1266 GetWifiRemoteStationManager()->ReportRxOk(psdu->GetHeader(0).GetAddr2(),
1267 rxSignalInfo,
1268 txVector);
1269 }
1270 ReceiveMpdu(*(psdu->begin()), rxSignalInfo, txVector, perMpduStatus.empty());
1271 }
1272 else
1273 {
1274 EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1275 }
1276 }
1277 else if (m_promisc)
1278 {
1279 for (const auto& mpdu : *PeekPointer(psdu))
1280 {
1281 if (!mpdu->GetHeader().IsCtl())
1282 {
1283 m_rxMiddle->Receive(mpdu, m_linkId);
1284 }
1285 }
1286 }
1287
1288 if (!perMpduStatus.empty())
1289 {
1290 // for A-MPDUs, we get here only once
1291 PostProcessFrame(psdu, txVector);
1292 }
1293}
1294
1295void
1296FrameExchangeManager::PreProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1297{
1298 NS_LOG_FUNCTION(this << psdu << txVector);
1299}
1300
1301void
1302FrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1303{
1304 NS_LOG_FUNCTION(this << psdu << txVector);
1305
1306 UpdateNav(psdu, txVector);
1307}
1308
1309void
1310FrameExchangeManager::UpdateNav(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
1311{
1312 NS_LOG_FUNCTION(this << psdu << txVector);
1313
1314 if (!psdu->HasNav())
1315 {
1316 return;
1317 }
1318
1319 Time duration = psdu->GetDuration();
1320 NS_LOG_DEBUG("Duration/ID=" << duration);
1321
1322 if (psdu->GetAddr1() == m_self)
1323 {
1324 // When the received frame's RA is equal to the STA's own MAC address, the STA
1325 // shall not update its NAV (IEEE 802.11-2016, sec. 10.3.2.4)
1326 return;
1327 }
1328
1329 // For all other received frames the STA shall update its NAV when the received
1330 // Duration is greater than the STA's current NAV value (IEEE 802.11-2016 sec. 10.3.2.4)
1331 Time navEnd = Simulator::Now() + duration;
1332 if (navEnd > m_navEnd)
1333 {
1334 m_navEnd = navEnd;
1335 NS_LOG_DEBUG("Updated NAV=" << m_navEnd);
1336
1337 // A STA that used information from an RTS frame as the most recent basis to update
1338 // its NAV setting is permitted to reset its NAV if no PHY-RXSTART.indication
1339 // primitive is received from the PHY during a NAVTimeout period starting when the
1340 // MAC receives a PHY-RXEND.indication primitive corresponding to the detection of
1341 // the RTS frame. NAVTimeout period is equal to:
1342 // (2 x aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 x aSlotTime)
1343 // The “CTS_Time” shall be calculated using the length of the CTS frame and the data
1344 // rate at which the RTS frame used for the most recent NAV update was received
1345 // (IEEE 802.11-2016 sec. 10.3.2.4)
1346 if (psdu->GetHeader(0).IsRts())
1347 {
1348 WifiTxVector ctsTxVector =
1349 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode());
1350 Time navResetDelay =
1351 2 * m_phy->GetSifs() +
1352 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1353 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
1354 m_navResetEvent =
1355 Simulator::Schedule(navResetDelay, &FrameExchangeManager::NavResetTimeout, this);
1356 }
1357 }
1358 NS_LOG_DEBUG("Current NAV=" << m_navEnd);
1359
1360 m_channelAccessManager->NotifyNavStartNow(duration);
1361}
1362
1363void
1364FrameExchangeManager::NavResetTimeout()
1365{
1366 NS_LOG_FUNCTION(this);
1367 m_navEnd = Simulator::Now();
1368 m_channelAccessManager->NotifyNavResetNow(Seconds(0));
1369}
1370
1371bool
1372FrameExchangeManager::VirtualCsMediumIdle() const
1373{
1374 return m_navEnd <= Simulator::Now();
1375}
1376
1377void
1378FrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
1379 RxSignalInfo rxSignalInfo,
1380 const WifiTxVector& txVector,
1381 bool inAmpdu)
1382{
1383 NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1384 // The received MPDU is either broadcast or addressed to this station
1385 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1386
1387 double rxSnr = rxSignalInfo.snr;
1388 const WifiMacHeader& hdr = mpdu->GetHeader();
1389
1390 if (hdr.IsCtl())
1391 {
1392 if (hdr.IsRts())
1393 {
1394 NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
1395
1396 // A non-VHT STA that is addressed by an RTS frame behaves as follows:
1397 // - If the NAV indicates idle, the STA shall respond with a CTS frame after a SIFS
1398 // - Otherwise, the STA shall not respond with a CTS frame
1399 // (IEEE 802.11-2016 sec. 10.3.2.7)
1400 if (VirtualCsMediumIdle())
1401 {
1402 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
1403 m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
1404 &FrameExchangeManager::SendCtsAfterRts,
1405 this,
1406 hdr,
1407 txVector,
1408 rxSnr);
1409 }
1410 else
1411 {
1412 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
1413 }
1414 }
1415 else if (hdr.IsCts() && m_txTimer.IsRunning() &&
1416 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_mpdu)
1417 {
1418 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1419 NS_ASSERT(hdr.GetAddr1() == m_self);
1420
1421 const auto sender = GetIndividuallyAddressedRecipient(m_mac, m_mpdu->GetHeader());
1422 NS_LOG_DEBUG("Received CTS from=" << sender);
1423
1424 SnrTag tag;
1425 mpdu->GetPacket()->PeekPacketTag(tag);
1426 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1427 GetWifiRemoteStationManager()->ReportRtsOk(m_mpdu->GetHeader(),
1428 rxSnr,
1429 txVector.GetMode(),
1430 tag.Get());
1431
1432 m_txTimer.Cancel();
1433 m_channelAccessManager->NotifyCtsTimeoutResetNow();
1434 ProtectionCompleted();
1435 }
1436 else if (hdr.IsAck() && m_mpdu && m_txTimer.IsRunning() &&
1437 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK)
1438 {
1439 NS_ASSERT(hdr.GetAddr1() == m_self);
1440 SnrTag tag;
1441 mpdu->GetPacket()->PeekPacketTag(tag);
1442 ReceivedNormalAck(m_mpdu, m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get());
1443 m_mpdu = nullptr;
1444 }
1445 }
1446 else if (hdr.IsMgt())
1447 {
1448 NS_ABORT_MSG_IF(inAmpdu, "Received management frame as part of an A-MPDU");
1449
1450 if (hdr.IsBeacon() || hdr.IsProbeResp())
1451 {
1452 // Apply SNR tag for beacon quality measurements
1453 SnrTag tag;
1454 tag.Set(rxSnr);
1455 Ptr<Packet> packet = mpdu->GetPacket()->Copy();
1456 packet->AddPacketTag(tag);
1457 mpdu = Create<WifiMpdu>(packet, hdr);
1458 }
1459
1460 if (hdr.GetAddr1() == m_self)
1461 {
1462 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1463 << ", schedule ACK");
1464 Simulator::Schedule(m_phy->GetSifs(),
1465 &FrameExchangeManager::SendNormalAck,
1466 this,
1467 hdr,
1468 txVector,
1469 rxSnr);
1470 }
1471
1472 m_rxMiddle->Receive(mpdu, m_linkId);
1473 }
1474 else if (hdr.IsData() && !hdr.IsQosData())
1475 {
1476 if (hdr.GetAddr1() == m_self)
1477 {
1478 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1479 << ", schedule ACK");
1480 Simulator::Schedule(m_phy->GetSifs(),
1481 &FrameExchangeManager::SendNormalAck,
1482 this,
1483 hdr,
1484 txVector,
1485 rxSnr);
1486 }
1487
1488 m_rxMiddle->Receive(mpdu, m_linkId);
1489 }
1490}
1491
1492void
1493FrameExchangeManager::ReceivedNormalAck(Ptr<WifiMpdu> mpdu,
1494 const WifiTxVector& txVector,
1495 const WifiTxVector& ackTxVector,
1496 const RxSignalInfo& rxInfo,
1497 double snr)
1498{
1499 Mac48Address sender = mpdu->GetHeader().GetAddr1();
1500 NS_LOG_DEBUG("Received ACK from=" << sender);
1501 m_txTimer.GotResponseFrom(sender);
1502
1503 NotifyReceivedNormalAck(mpdu);
1504
1505 // When fragmentation is used, only update manager when the last fragment is acknowledged
1506 if (!mpdu->GetHeader().IsMoreFragments())
1507 {
1508 GetWifiRemoteStationManager()->ReportRxOk(sender, rxInfo, ackTxVector);
1509 GetWifiRemoteStationManager()->ReportDataOk(mpdu,
1510 rxInfo.snr,
1511 ackTxVector.GetMode(),
1512 snr,
1513 txVector);
1514 }
1515 // cancel the timer
1516 m_txTimer.Cancel();
1517 m_channelAccessManager->NotifyAckTimeoutResetNow();
1518
1519 // The CW shall be reset to aCWmin after every successful attempt to transmit
1520 // a frame containing all or part of an MSDU or MMPDU (sec. 10.3.3 of 802.11-2016)
1521 m_dcf->ResetCw(m_linkId);
1522
1523 if (mpdu->GetHeader().IsMoreFragments())
1524 {
1525 // replace the current fragment with the next one
1526 m_dcf->GetWifiMacQueue()->Replace(mpdu, GetNextFragment());
1527 m_moreFragments = true;
1528 }
1529 else
1530 {
1531 // the MPDU has been acknowledged, we can now dequeue it if it is stored in a queue
1532 DequeueMpdu(mpdu);
1533 }
1534
1535 TransmissionSucceeded();
1536}
1537
1538void
1539FrameExchangeManager::NotifyReceivedNormalAck(Ptr<WifiMpdu> mpdu)
1540{
1541 NS_LOG_FUNCTION(this << *mpdu);
1542
1543 // inform the MAC that the transmission was successful
1544 if (!m_ackedMpduCallback.IsNull())
1545 {
1546 m_ackedMpduCallback(mpdu);
1547 }
1548}
1549
1550void
1551FrameExchangeManager::EndReceiveAmpdu(Ptr<const WifiPsdu> psdu,
1552 const RxSignalInfo& rxSignalInfo,
1553 const WifiTxVector& txVector,
1554 const std::vector<bool>& perMpduStatus)
1555{
1556 NS_ASSERT_MSG(false, "A non-QoS station should not receive an A-MPDU");
1557}
1558
1559void
1560FrameExchangeManager::NotifyLastGcrUrTx(Ptr<const WifiMpdu> mpdu)
1561{
1562 NS_ASSERT_MSG(false, "A non-QoS station should not use GCR-UR");
1563}
1564
1565} // 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 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:830
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition wifi-phy.cc:485
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1588
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition wifi-phy.cc:473
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1070
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:479
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1581
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: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
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: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: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.