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 "snr-tag.h"
13#include "sta-wifi-mac.h"
14#include "wifi-mac-queue.h"
15#include "wifi-mac-trailer.h"
16#include "wifi-utils.h"
17
18#include "ns3/abort.h"
19#include "ns3/log.h"
20
21#undef NS_LOG_APPEND_CONTEXT
22#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
23
24// Time (in nanoseconds) to be added to the PSDU duration to yield the duration
25// of the timer that is started when the PHY indicates the start of the reception
26// of a frame and we are waiting for a response.
27#define PSDU_DURATION_SAFEGUARD 400
28
29namespace ns3
30{
31
32NS_LOG_COMPONENT_DEFINE("FrameExchangeManager");
33
34NS_OBJECT_ENSURE_REGISTERED(FrameExchangeManager);
35
36TypeId
38{
39 static TypeId tid =
40 TypeId("ns3::FrameExchangeManager")
42 .AddConstructor<FrameExchangeManager>()
43 .SetGroupName("Wifi")
44 .AddAttribute("ProtectedIfResponded",
45 "Whether a station is assumed to be protected if replied to a frame "
46 "requiring acknowledgment. If a station is protected, subsequent "
47 "transmissions to the same station in the same TXOP are not "
48 "preceded by protection mechanisms.",
49 BooleanValue(true),
52 return tid;
53}
54
56 : m_navEnd(0),
57 m_txNav(0),
58 m_linkId(0),
59 m_allowedWidth{0},
60 m_promisc(false),
61 m_moreFragments(false)
62{
63 NS_LOG_FUNCTION(this);
64}
65
70
71void
85
86void
88{
89 NS_LOG_FUNCTION(this);
90 Reset();
91 m_fragmentedPacket = nullptr;
92 m_mac = nullptr;
93 m_apMac = nullptr;
94 m_staMac = nullptr;
95 m_txMiddle = nullptr;
96 m_rxMiddle = nullptr;
97 m_channelAccessManager = nullptr;
98 m_protectionManager = nullptr;
99 m_ackManager = nullptr;
100 ResetPhy();
102}
103
104void
106{
107 NS_LOG_FUNCTION(this << protectionManager);
108 m_protectionManager = protectionManager;
109}
110
116
117void
119{
120 NS_LOG_FUNCTION(this << ackManager);
121 m_ackManager = ackManager;
122}
123
129
130void
132{
133 NS_LOG_FUNCTION(this << +linkId);
134 m_linkId = linkId;
135}
136
137void
145
146void
148{
149 NS_LOG_FUNCTION(this << txMiddle);
150 m_txMiddle = txMiddle;
151}
152
153void
155{
156 NS_LOG_FUNCTION(this << rxMiddle);
157 m_rxMiddle = rxMiddle;
158}
159
160void
162{
163 NS_LOG_FUNCTION(this << channelAccessManager);
164 m_channelAccessManager = channelAccessManager;
165}
166
169{
170 return m_mac->GetWifiRemoteStationManager(m_linkId);
171}
172
173void
185
186void
188{
189 NS_LOG_FUNCTION(this);
190 if (m_phy)
191 {
193 "PhyRxPayloadBegin",
196 "PhyRxMacHeaderEnd",
198 if (m_phy->GetState())
199 {
203 const WifiTxVector&,
204 const std::vector<bool>&>());
206 }
207 m_phy = nullptr;
208 m_ongoingRxInfo.macHdr.reset();
210 }
211}
212
213void
215{
216 NS_LOG_FUNCTION(this << address);
217 // For APs, the BSSID is the MAC address. For STAs, the BSSID will be overwritten
218 // when receiving Beacon frames or Probe Response frames
219 SetBssid(address);
220 m_self = address;
221}
222
225{
226 return m_self;
227}
228
229void
231{
232 NS_LOG_FUNCTION(this << bssid);
233 m_bssid = bssid;
234}
235
238{
239 return m_bssid;
240}
241
242MHz_u
247
248void
250{
251 NS_LOG_FUNCTION(this << &callback);
252 m_droppedMpduCallback = callback;
253}
254
255void
257{
258 NS_LOG_FUNCTION(this << &callback);
259 m_ackedMpduCallback = callback;
260}
261
262void
267
268bool
270{
271 return m_promisc;
272}
273
274const WifiTxTimer&
279
280void
287
288void
290{
291 NS_LOG_FUNCTION(this << "PSDU reception started for " << psduDuration.As(Time::US)
292 << " (txVector: " << txVector << ")");
293
295 "The TX timer and the NAV reset event cannot be both running");
296
297 // No need to reschedule timeouts if PSDU duration is null. In this case,
298 // PHY-RXEND immediately follows PHY-RXSTART (e.g. when PPDU has been filtered)
299 // and CCA will take over
300 if (m_txTimer.IsRunning() && psduDuration.IsStrictlyPositive())
301 {
302 // we are waiting for a response and something arrived
303 NS_LOG_DEBUG("Rescheduling timeout event");
305 // PHY has switched to RX, so we can reset the ack timeout
306 m_channelAccessManager->NotifyAckTimeoutResetNow();
307 }
308
310 {
312 }
313
314 m_ongoingRxInfo = {std::nullopt, txVector, Simulator::Now() + psduDuration};
315}
316
317void
319 const WifiTxVector& txVector,
320 Time psduDuration)
321{
322 NS_LOG_FUNCTION(this << macHdr << txVector << psduDuration.As(Time::MS));
323 m_ongoingRxInfo = {macHdr, txVector, Simulator::Now() + psduDuration};
324}
325
326std::optional<std::reference_wrapper<const FrameExchangeManager::OngoingRxInfo>>
328{
330 {
331 return m_ongoingRxInfo;
332 }
333 return std::nullopt;
334}
335
336std::optional<std::reference_wrapper<const WifiMacHeader>>
338{
339 if (auto info = GetOngoingRxInfo(); info.has_value() && info->get().macHdr.has_value())
340 {
341 return info->get().macHdr.value();
342 }
343 return std::nullopt;
344}
345
346bool
348{
349 NS_LOG_FUNCTION(this << dcf << allowedWidth);
350
352 if (m_txTimer.IsRunning())
353 {
355 }
356 m_dcf = dcf;
357 m_allowedWidth = allowedWidth;
358
359 Ptr<WifiMacQueue> queue = dcf->GetWifiMacQueue();
360
361 // Even though channel access is requested when the queue is not empty, at
362 // the time channel access is granted the lifetime of the packet might be
363 // expired and the queue might be empty.
364 queue->WipeAllExpiredMpdus();
365
366 Ptr<WifiMpdu> mpdu = queue->Peek(m_linkId);
367
368 if (!mpdu)
369 {
370 NS_LOG_DEBUG("Queue empty");
372 m_dcf = nullptr;
373 return false;
374 }
375
377
378 NS_ASSERT(mpdu->GetHeader().IsData() || mpdu->GetHeader().IsMgt());
379
380 // assign a sequence number if this is not a fragment nor a retransmission
381 if (!mpdu->IsFragment() && !mpdu->GetHeader().IsRetry())
382 {
383 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
384 mpdu->AssignSeqNo(sequence);
385 }
386
387 NS_LOG_DEBUG("MPDU payload size=" << mpdu->GetPacketSize()
388 << ", to=" << mpdu->GetHeader().GetAddr1()
389 << ", seq=" << mpdu->GetHeader().GetSequenceControl());
390
391 // check if the MSDU needs to be fragmented
392 mpdu = GetFirstFragmentIfNeeded(mpdu);
393
396 WifiTxParameters txParams;
397 txParams.m_txVector =
398 GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
399 txParams.AddMpdu(mpdu);
400 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
401 txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
402 txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
403
404 SendMpduWithProtection(mpdu, txParams);
405
406 return true;
407}
408
411{
412 NS_LOG_FUNCTION(this << *mpdu);
413
414 if (mpdu->IsFragment())
415 {
416 // a fragment cannot be further fragmented
418 }
419 else if (GetWifiRemoteStationManager()->NeedFragmentation(mpdu))
420 {
421 NS_LOG_DEBUG("Fragmenting the MSDU");
422 m_fragmentedPacket = mpdu->GetPacket()->Copy();
423 // create the first fragment
425 0,
426 GetWifiRemoteStationManager()->GetFragmentSize(mpdu, 0));
427 // enqueue the first fragment
428 Ptr<WifiMpdu> item = Create<WifiMpdu>(fragment, mpdu->GetHeader());
429 item->GetHeader().SetMoreFragments();
430 m_mac->GetTxopQueue(mpdu->GetQueueAc())->Replace(mpdu, item);
431 return item;
432 }
433 return mpdu;
434}
435
436void
438{
439 NS_LOG_FUNCTION(this << *mpdu << &txParams);
440
441 m_mpdu = mpdu;
442 m_txParams = std::move(txParams);
443
444 // If protection is required, the MPDU must be stored in some queue because
445 // it is not put back in a queue if the RTS/CTS exchange fails
447 m_mpdu->GetHeader().IsCtl() || m_mpdu->IsQueued());
448
449 // Make sure that the acknowledgment time has been computed, so that SendRts()
450 // and SendCtsToSelf() can reuse this value.
452
453 if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
454 {
456 }
457
458 // Set QoS Ack policy if this is a QoS data frame
460
461 if (m_mpdu->IsQueued())
462 {
463 m_mpdu->SetInFlight(m_linkId);
464 }
465
467}
468
469void
471{
472 NS_LOG_FUNCTION(this << &txParams);
473
474 switch (txParams.m_protection->method)
475 {
477 SendRts(txParams);
478 break;
480 SendCtsToSelf(txParams);
481 break;
484 break;
485 default:
486 NS_ABORT_MSG("Unknown protection type: " << txParams.m_protection.get());
487 }
488}
489
490void
506
507const std::set<Mac48Address>&
512
513void
515{
516 NS_LOG_FUNCTION(this);
517
520 m_phy->GetPhyBand());
521
523
525 {
526 if (!m_mpdu->GetHeader().IsQosData() ||
527 m_mpdu->GetHeader().GetQosAckPolicy() == WifiMacHeader::NO_ACK)
528 {
529 // No acknowledgment, hence dequeue the MPDU if it is stored in a queue
531 }
532
533 Simulator::Schedule(txDuration, [=, this]() {
535 m_mpdu = nullptr;
536 });
537 }
539 {
540 m_mpdu->GetHeader().SetDuration(
541 GetFrameDurationId(m_mpdu->GetHeader(),
545
546 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
547 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
548 // aRxPHYStartDelay equals the time to transmit the PHY header.
549 auto normalAcknowledgment = static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
550
551 Time timeout =
552 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
553 m_phy->CalculatePhyPreambleAndHeaderDuration(normalAcknowledgment->ackTxVector);
556 timeout,
557 {m_mpdu->GetHeader().GetAddr1()},
559 this,
560 m_mpdu,
562 m_channelAccessManager->NotifyAckTimeoutStartNow(timeout);
563 }
564 else
565 {
566 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
567 << m_txParams.m_acknowledgment.get() << ")");
568 }
569
570 // transmit the MPDU
572
573 if (m_txTimer.IsRunning())
574 {
575 NS_ASSERT(m_sentFrameTo.empty());
576 m_sentFrameTo = {m_mpdu->GetHeader().GetAddr1()};
577 }
578}
579
580void
582{
583 NS_LOG_FUNCTION(this << *mpdu << txVector);
584
585 auto psdu = Create<WifiPsdu>(mpdu, false);
586 FinalizeMacHeader(psdu);
587 m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
588 auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
589 // The TXNAV timer is a single timer, shared by the EDCAFs within a STA, that is initialized
590 // with the duration from the Duration/ID field in the frame most recently successfully
591 // transmitted by the TXOP holder, except for PS-Poll frames. (Sec.10.23.2.2 IEEE 802.11-2020)
592 if (!mpdu->GetHeader().IsPsPoll())
593 {
594 m_txNav = Max(m_txNav, Simulator::Now() + txDuration + mpdu->GetHeader().GetDuration());
595 }
596 m_phy->Send(psdu, txVector);
597}
598
599void
601{
602 NS_LOG_FUNCTION(this << psdu);
603
604 if (m_mac->GetTypeOfStation() != STA)
605 {
606 return;
607 }
608
609 auto pmMode = StaticCast<StaWifiMac>(m_mac)->GetPmMode(m_linkId);
610
611 for (const auto& mpdu : *PeekPointer(psdu))
612 {
613 switch (pmMode)
614 {
615 case WIFI_PM_ACTIVE:
617 mpdu->GetHeader().SetNoPowerManagement();
618 break;
621 mpdu->GetHeader().SetPowerManagement();
622 break;
623 default:
624 NS_ABORT_MSG("Unknown PM mode: " << +pmMode);
625 }
626 }
627}
628
629void
631{
632 NS_LOG_DEBUG(this << *mpdu);
633
634 if (mpdu->IsQueued())
635 {
636 m_mac->GetTxopQueue(mpdu->GetQueueAc())->DequeueIfQueued({mpdu});
637 }
638}
639
642{
643 return mpdu->GetSize();
644}
645
646void
648{
649 NS_LOG_FUNCTION(this << protection);
650 NS_ASSERT(protection);
651
652 if (protection->method == WifiProtection::NONE)
653 {
654 protection->protectionTime = Seconds(0);
655 }
656 else if (protection->method == WifiProtection::RTS_CTS)
657 {
658 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
659 rtsCtsProtection->protectionTime = m_phy->CalculateTxDuration(GetRtsSize(),
660 rtsCtsProtection->rtsTxVector,
661 m_phy->GetPhyBand()) +
663 rtsCtsProtection->ctsTxVector,
664 m_phy->GetPhyBand()) +
665 2 * m_phy->GetSifs();
666 }
667 else if (protection->method == WifiProtection::CTS_TO_SELF)
668 {
669 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(protection);
670 ctsToSelfProtection->protectionTime =
672 ctsToSelfProtection->ctsTxVector,
673 m_phy->GetPhyBand()) +
674 m_phy->GetSifs();
675 }
676}
677
678void
680{
681 NS_LOG_FUNCTION(this << acknowledgment);
682 NS_ASSERT(acknowledgment);
683
684 if (acknowledgment->method == WifiAcknowledgment::NONE)
685 {
686 acknowledgment->acknowledgmentTime = Seconds(0);
687 }
688 else if (acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
689 {
690 auto normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
691 normalAcknowledgment->acknowledgmentTime =
693 normalAcknowledgment->ackTxVector,
694 m_phy->GetPhyBand());
695 }
696}
697
698Time
700 Mac48Address receiver,
701 const WifiTxParameters& txParams) const
702{
703 return m_phy->CalculateTxDuration(ppduPayloadSize, txParams.m_txVector, m_phy->GetPhyBand());
704}
705
706void
708{
709 txParams.m_txDuration = GetTxDuration(txParams.GetSize(receiver), receiver, txParams);
710}
711
712Time
714 uint32_t size,
715 const WifiTxParameters& txParams,
716 Ptr<Packet> fragmentedPacket) const
717{
718 NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
719
720 NS_ASSERT(txParams.m_acknowledgment &&
721 txParams.m_acknowledgment->acknowledgmentTime.has_value());
722 auto durationId = *txParams.m_acknowledgment->acknowledgmentTime;
723
724 // if the current frame is a fragment followed by another fragment, we have to
725 // update the Duration/ID to cover the next fragment and the corresponding Ack
726 if (header.IsMoreFragments())
727 {
728 uint32_t payloadSize = size - header.GetSize() - WIFI_MAC_FCS_LENGTH;
729 uint32_t nextFragmentOffset = (header.GetFragmentNumber() + 1) * payloadSize;
730 uint32_t nextFragmentSize =
731 std::min(fragmentedPacket->GetSize() - nextFragmentOffset, payloadSize);
732 WifiTxVector ackTxVector =
733 GetWifiRemoteStationManager()->GetAckTxVector(header.GetAddr1(), txParams.m_txVector);
734
735 durationId +=
736 2 * m_phy->GetSifs() +
738 m_phy->CalculateTxDuration(nextFragmentSize, txParams.m_txVector, m_phy->GetPhyBand());
739 }
740 return durationId;
741}
742
743Time
745 Time txDuration,
746 Time response) const
747{
748 NS_LOG_FUNCTION(this << rtsTxVector << txDuration << response);
749
750 WifiTxVector ctsTxVector;
751 ctsTxVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_self, rtsTxVector.GetMode());
752
753 return m_phy->GetSifs() +
754 m_phy->CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) /* CTS */
755 + m_phy->GetSifs() + txDuration + response;
756}
757
758void
760{
761 NS_LOG_FUNCTION(this << &txParams);
762
763 NS_ASSERT(txParams.GetPsduInfoMap().size() == 1);
764 Mac48Address receiver = txParams.GetPsduInfoMap().begin()->first;
765
766 WifiMacHeader rts;
768 rts.SetDsNotFrom();
769 rts.SetDsNotTo();
770 rts.SetNoRetry();
771 rts.SetNoMoreFragments();
772 rts.SetAddr1(receiver);
773 rts.SetAddr2(m_self);
774
775 NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
776 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
777
778 NS_ASSERT(txParams.m_txDuration.has_value());
779 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
780 rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
781 *txParams.m_txDuration,
782 *txParams.m_acknowledgment->acknowledgmentTime));
784
785 // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with
786 // a value of aSIFSTime + aSlotTime + aRxPHYStartDelay (IEEE 802.11-2016 sec. 10.3.2.7).
787 // aRxPHYStartDelay equals the time to transmit the PHY header.
789 rtsCtsProtection->rtsTxVector,
790 m_phy->GetPhyBand()) +
791 m_phy->GetSifs() + m_phy->GetSlot() +
792 m_phy->CalculatePhyPreambleAndHeaderDuration(rtsCtsProtection->ctsTxVector);
795 timeout,
796 {receiver},
798 this,
799 mpdu,
800 rtsCtsProtection->rtsTxVector);
801 m_channelAccessManager->NotifyCtsTimeoutStartNow(timeout);
802 NS_ASSERT(m_sentRtsTo.empty());
803 m_sentRtsTo = {receiver};
804
805 ForwardMpduDown(mpdu, rtsCtsProtection->rtsTxVector);
806}
807
808void
810 WifiTxVector& ctsTxVector,
811 double rtsSnr)
812{
813 NS_LOG_FUNCTION(this << rtsHdr << ctsTxVector << rtsSnr);
814
815 WifiMacHeader cts;
817 cts.SetDsNotFrom();
818 cts.SetDsNotTo();
819 cts.SetNoMoreFragments();
820 cts.SetNoRetry();
821 cts.SetAddr1(rtsHdr.GetAddr2());
822 Time duration = rtsHdr.GetDuration() - m_phy->GetSifs() -
824 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
825 if (duration.IsStrictlyNegative())
826 {
827 duration = Seconds(0);
828 }
829 cts.SetDuration(duration);
830
831 Ptr<Packet> packet = Create<Packet>();
832
833 SnrTag tag;
834 tag.Set(rtsSnr);
835 packet->AddPacketTag(tag);
836
837 // CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
838 ForwardMpduDown(Create<WifiMpdu>(packet, cts), ctsTxVector);
839}
840
841void
843 WifiMode rtsTxMode,
844 double rtsSnr)
845{
846 NS_LOG_FUNCTION(this << rtsHdr << rtsTxMode << rtsSnr);
847
848 WifiTxVector ctsTxVector =
849 GetWifiRemoteStationManager()->GetCtsTxVector(rtsHdr.GetAddr2(), rtsTxMode);
850 DoSendCtsAfterRts(rtsHdr, ctsTxVector, rtsSnr);
851}
852
853Time
855 Time txDuration,
856 Time response) const
857{
858 NS_LOG_FUNCTION(this << ctsTxVector << txDuration << response);
859
860 return m_phy->GetSifs() + txDuration + response;
861}
862
863void
865{
866 NS_LOG_FUNCTION(this << &txParams);
867
868 WifiMacHeader cts;
870 cts.SetDsNotFrom();
871 cts.SetDsNotTo();
872 cts.SetNoMoreFragments();
873 cts.SetNoRetry();
874 cts.SetAddr1(m_self);
875
876 NS_ASSERT(txParams.m_protection &&
877 txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
878 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
879
880 NS_ASSERT(txParams.m_txDuration.has_value());
881 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
882 cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
883 *txParams.m_txDuration,
884 *txParams.m_acknowledgment->acknowledgmentTime));
885
886 ForwardMpduDown(Create<WifiMpdu>(Create<Packet>(), cts), ctsToSelfProtection->ctsTxVector);
887
888 Time ctsDuration = m_phy->CalculateTxDuration(GetCtsSize(),
889 ctsToSelfProtection->ctsTxVector,
890 m_phy->GetPhyBand());
892}
893
894void
896 const WifiTxVector& dataTxVector,
897 double dataSnr)
898{
899 NS_LOG_FUNCTION(this << hdr << dataTxVector << dataSnr);
900
901 WifiTxVector ackTxVector =
902 GetWifiRemoteStationManager()->GetAckTxVector(hdr.GetAddr2(), dataTxVector);
903 WifiMacHeader ack;
905 ack.SetDsNotFrom();
906 ack.SetDsNotTo();
907 ack.SetNoRetry();
908 ack.SetNoMoreFragments();
909 ack.SetAddr1(hdr.GetAddr2());
910 // 802.11-2016, Section 9.2.5.7: Duration/ID is received duration value
911 // minus the time to transmit the Ack frame and its SIFS interval
912 Time duration = hdr.GetDuration() - m_phy->GetSifs() -
914 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
915 if (duration.IsStrictlyNegative())
916 {
917 duration = Seconds(0);
918 }
919 ack.SetDuration(duration);
920
921 Ptr<Packet> packet = Create<Packet>();
922
923 SnrTag tag;
924 tag.Set(dataSnr);
925 packet->AddPacketTag(tag);
926
927 ForwardMpduDown(Create<WifiMpdu>(packet, ack), ackTxVector);
928}
929
932{
933 NS_LOG_FUNCTION(this);
934 NS_ASSERT(m_mpdu->GetHeader().IsMoreFragments());
935
936 WifiMacHeader& hdr = m_mpdu->GetHeader();
938
939 uint32_t startOffset = hdr.GetFragmentNumber() * m_mpdu->GetPacketSize();
940 uint32_t size = m_fragmentedPacket->GetSize() - startOffset;
941
942 if (size > m_mpdu->GetPacketSize())
943 {
944 // this is not the last fragment
945 size = m_mpdu->GetPacketSize();
946 hdr.SetMoreFragments();
947 }
948 else
949 {
950 hdr.SetNoMoreFragments();
951 }
952
953 return Create<WifiMpdu>(m_fragmentedPacket->CreateFragment(startOffset, size), hdr);
954}
955
956void
958{
959 NS_LOG_FUNCTION(this);
960 m_sentFrameTo.clear();
961
962 // Upon a transmission success, a non-QoS station transmits the next fragment,
963 // if any, or releases the channel, otherwise
964 if (m_moreFragments)
965 {
966 NS_LOG_DEBUG("Schedule transmission of next fragment in a SIFS");
969 this,
970 m_dcf,
972 m_moreFragments = false;
973 }
974 else
975 {
977 m_dcf = nullptr;
978 }
979}
980
981void
983{
984 NS_LOG_FUNCTION(this << forceCurrentCw);
985 if (!forceCurrentCw)
986 {
988 }
989 m_sentFrameTo.clear();
990 // A non-QoS station always releases the channel upon a transmission failure
992 m_dcf = nullptr;
993 // reset TXNAV because transmission failed
995}
996
997void
999{
1000 NS_LOG_FUNCTION(this << txop);
1001 txop->NotifyChannelReleased(m_linkId);
1002 m_protectedStas.clear();
1003}
1004
1007{
1008 NS_LOG_FUNCTION(this << *psdu);
1009
1010 const auto mpdusToDrop = GetWifiRemoteStationManager()->GetMpdusToDropOnTxFailure(psdu);
1011 Ptr<WifiMpdu> droppedMpdu{nullptr};
1012
1013 for (const auto& mpdu : mpdusToDrop)
1014 {
1015 // this MPDU needs to be dropped
1016 droppedMpdu = mpdu;
1018 DequeueMpdu(mpdu);
1019 }
1020
1021 return droppedMpdu;
1022}
1023
1024void
1026{
1027 NS_LOG_FUNCTION(this << *mpdu << txVector);
1028
1029 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1030 if (auto droppedMpdu = DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1031 {
1032 // notify remote station manager if at least an MPDU was dropped
1033 GetWifiRemoteStationManager()->ReportFinalDataFailed(droppedMpdu);
1034 }
1035
1036 // the MPDU may have been dropped due to lifetime expiration or maximum amount of
1037 // retransmissions reached
1038 if (mpdu->IsQueued())
1039 {
1040 mpdu = m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu);
1041 mpdu->ResetInFlight(m_linkId);
1042 mpdu->GetHeader().SetRetry();
1044 }
1045
1046 m_mpdu = nullptr;
1048}
1049
1050void
1055
1056void
1058{
1059 NS_LOG_FUNCTION(this << *rts << txVector);
1060
1062 m_mpdu = nullptr;
1063}
1064
1065void
1067{
1068 NS_LOG_FUNCTION(this << *psdu);
1069
1070 m_sentRtsTo.clear();
1071 for (const auto& mpdu : *PeekPointer(psdu))
1072 {
1073 if (mpdu->IsQueued())
1074 {
1075 mpdu->ResetInFlight(m_linkId);
1076 }
1077 }
1078
1079 GetWifiRemoteStationManager()->ReportRtsFailed(psdu->GetHeader(0));
1080 if (auto droppedMpdu = DropMpduIfRetryLimitReached(psdu))
1081 {
1082 GetWifiRemoteStationManager()->ReportFinalRtsFailed(droppedMpdu->GetHeader());
1083 }
1084
1085 // Make the sequence numbers of the MPDUs available again if the MPDUs have never
1086 // been transmitted, both in case the MPDUs have been discarded and in case the
1087 // MPDUs have to be transmitted (because a new sequence number is assigned to
1088 // MPDUs that have never been transmitted and are selected for transmission)
1090
1092}
1093
1094void
1096{
1097 NS_LOG_FUNCTION(this << *psdu);
1098
1099 NS_ASSERT_MSG(psdu->GetNMpdus() == 1, "A-MPDUs should be handled by the HT FEM override");
1100 auto mpdu = *psdu->begin();
1101
1102 // the MPDU should be still in the DCF queue, unless it expired.
1103 // If the MPDU has never been transmitted and is not in-flight, it will be assigned
1104 // a sequence number again the next time we try to transmit it. Therefore, we need to
1105 // make its sequence number available again
1106 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
1107 {
1108 mpdu->UnassignSeqNo();
1109 m_txMiddle->SetSequenceNumberFor(&mpdu->GetOriginal()->GetHeader());
1110 }
1111}
1112
1113void
1115{
1116 NS_LOG_FUNCTION(this);
1117
1118 // For internal collisions, the frame retry counts associated with the MSDUs, A-MSDUs, or MMPDUs
1119 // involved in the internal collision shall be incremented. (Sec. 10.23.2.12.1 of 802.11-2020)
1120 // We do not prepare the PSDU that the AC losing the internal collision would have
1121 // sent. As an approximation, we consider the frame peeked from the queues of the AC.
1122 Ptr<QosTxop> qosTxop = (txop->IsQosTxop() ? StaticCast<QosTxop>(txop) : nullptr);
1123
1124 if (auto mpdu =
1125 (qosTxop ? qosTxop->PeekNextMpdu(m_linkId) : txop->GetWifiMacQueue()->Peek(m_linkId));
1126 mpdu && !mpdu->GetHeader().GetAddr1().IsGroup())
1127 {
1128 if (mpdu->GetHeader().HasData())
1129 {
1130 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1131 }
1132
1134 {
1135 GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
1136 }
1137 }
1138
1139 txop->UpdateFailedCw(m_linkId);
1140 txop->Txop::NotifyChannelReleased(m_linkId);
1141}
1142
1143void
1145{
1146 NS_LOG_DEBUG("Switching channel. Cancelling MAC pending events");
1148 if (m_txTimer.IsRunning())
1149 {
1150 // we were transmitting something before channel switching. Since we will
1151 // not be able to receive the response, have the timer expire now, so that
1152 // we perform the actions required in case of missing response
1154 }
1156}
1157
1158void
1160{
1161 NS_LOG_DEBUG("Device in sleep mode. Cancelling MAC pending events");
1162 Reset();
1163}
1164
1165void
1167{
1168 NS_LOG_DEBUG("Device is switched off. Cancelling MAC pending events");
1169 Reset();
1170}
1171
1172void
1177
1178void
1180 RxSignalInfo rxSignalInfo,
1181 const WifiTxVector& txVector,
1182 const std::vector<bool>& perMpduStatus)
1183{
1185 this << psdu << rxSignalInfo << txVector << perMpduStatus.size()
1186 << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](bool v) { return v; }));
1187
1188 if (!perMpduStatus.empty())
1189 {
1190 // for A-MPDUs, we get here only once
1191 PreProcessFrame(psdu, txVector);
1192 }
1193
1194 Mac48Address addr1 = psdu->GetAddr1();
1195
1196 if (addr1.IsGroup() || addr1 == m_self)
1197 {
1198 // receive broadcast frames or frames addressed to us only
1199 if (psdu->GetNMpdus() == 1)
1200 {
1201 // if perMpduStatus is not empty (i.e., this MPDU is not included in an A-MPDU)
1202 // then it must contain a single value which must be true (i.e., the MPDU
1203 // has been correctly received)
1204 NS_ASSERT(perMpduStatus.empty() || (perMpduStatus.size() == 1 && perMpduStatus[0]));
1205 // Ack and CTS do not carry Addr2
1206 if (!psdu->GetHeader(0).IsAck() && !psdu->GetHeader(0).IsCts())
1207 {
1208 GetWifiRemoteStationManager()->ReportRxOk(psdu->GetHeader(0).GetAddr2(),
1209 rxSignalInfo,
1210 txVector);
1211 }
1212 ReceiveMpdu(*(psdu->begin()), rxSignalInfo, txVector, perMpduStatus.empty());
1213 }
1214 else
1215 {
1216 EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1217 }
1218 }
1219 else if (m_promisc)
1220 {
1221 for (const auto& mpdu : *PeekPointer(psdu))
1222 {
1223 if (!mpdu->GetHeader().IsCtl())
1224 {
1225 m_rxMiddle->Receive(mpdu, m_linkId);
1226 }
1227 }
1228 }
1229
1230 if (!perMpduStatus.empty())
1231 {
1232 // for A-MPDUs, we get here only once
1233 PostProcessFrame(psdu, txVector);
1234 }
1235}
1236
1237void
1239{
1240 NS_LOG_FUNCTION(this << psdu << txVector);
1241}
1242
1243void
1245{
1246 NS_LOG_FUNCTION(this << psdu << txVector);
1247
1248 UpdateNav(psdu, txVector);
1249}
1250
1251void
1253{
1254 NS_LOG_FUNCTION(this << psdu << txVector);
1255
1256 if (!psdu->HasNav())
1257 {
1258 return;
1259 }
1260
1261 Time duration = psdu->GetDuration();
1262 NS_LOG_DEBUG("Duration/ID=" << duration);
1263
1264 if (psdu->GetAddr1() == m_self)
1265 {
1266 // When the received frame's RA is equal to the STA's own MAC address, the STA
1267 // shall not update its NAV (IEEE 802.11-2016, sec. 10.3.2.4)
1268 return;
1269 }
1270
1271 // For all other received frames the STA shall update its NAV when the received
1272 // Duration is greater than the STA's current NAV value (IEEE 802.11-2016 sec. 10.3.2.4)
1273 Time navEnd = Simulator::Now() + duration;
1274 if (navEnd > m_navEnd)
1275 {
1276 m_navEnd = navEnd;
1277 NS_LOG_DEBUG("Updated NAV=" << m_navEnd);
1278
1279 // A STA that used information from an RTS frame as the most recent basis to update
1280 // its NAV setting is permitted to reset its NAV if no PHY-RXSTART.indication
1281 // primitive is received from the PHY during a NAVTimeout period starting when the
1282 // MAC receives a PHY-RXEND.indication primitive corresponding to the detection of
1283 // the RTS frame. NAVTimeout period is equal to:
1284 // (2 x aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 x aSlotTime)
1285 // The “CTS_Time” shall be calculated using the length of the CTS frame and the data
1286 // rate at which the RTS frame used for the most recent NAV update was received
1287 // (IEEE 802.11-2016 sec. 10.3.2.4)
1288 if (psdu->GetHeader(0).IsRts())
1289 {
1290 WifiTxVector ctsTxVector =
1291 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode());
1292 Time navResetDelay =
1293 2 * m_phy->GetSifs() +
1298 }
1299 }
1300 NS_LOG_DEBUG("Current NAV=" << m_navEnd);
1301
1302 m_channelAccessManager->NotifyNavStartNow(duration);
1303}
1304
1305void
1312
1313bool
1318
1319void
1321 RxSignalInfo rxSignalInfo,
1322 const WifiTxVector& txVector,
1323 bool inAmpdu)
1324{
1325 NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1326 // The received MPDU is either broadcast or addressed to this station
1327 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1328
1329 double rxSnr = rxSignalInfo.snr;
1330 const WifiMacHeader& hdr = mpdu->GetHeader();
1331
1332 if (hdr.IsCtl())
1333 {
1334 if (hdr.IsRts())
1335 {
1336 NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
1337
1338 // A non-VHT STA that is addressed by an RTS frame behaves as follows:
1339 // - If the NAV indicates idle, the STA shall respond with a CTS frame after a SIFS
1340 // - Otherwise, the STA shall not respond with a CTS frame
1341 // (IEEE 802.11-2016 sec. 10.3.2.7)
1342 if (VirtualCsMediumIdle())
1343 {
1344 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
1347 this,
1348 hdr,
1349 txVector.GetMode(),
1350 rxSnr);
1351 }
1352 else
1353 {
1354 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
1355 }
1356 }
1357 else if (hdr.IsCts() && m_txTimer.IsRunning() &&
1359 {
1360 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1361 NS_ASSERT(hdr.GetAddr1() == m_self);
1362
1363 Mac48Address sender = m_mpdu->GetHeader().GetAddr1();
1364 NS_LOG_DEBUG("Received CTS from=" << sender);
1365
1366 SnrTag tag;
1367 mpdu->GetPacket()->PeekPacketTag(tag);
1368 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1369 GetWifiRemoteStationManager()->ReportRtsOk(m_mpdu->GetHeader(),
1370 rxSnr,
1371 txVector.GetMode(),
1372 tag.Get());
1373
1374 m_txTimer.Cancel();
1375 m_channelAccessManager->NotifyCtsTimeoutResetNow();
1377 }
1378 else if (hdr.IsAck() && m_mpdu && m_txTimer.IsRunning() &&
1380 {
1381 NS_ASSERT(hdr.GetAddr1() == m_self);
1382 SnrTag tag;
1383 mpdu->GetPacket()->PeekPacketTag(tag);
1384 ReceivedNormalAck(m_mpdu, m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get());
1385 m_mpdu = nullptr;
1386 }
1387 }
1388 else if (hdr.IsMgt())
1389 {
1390 NS_ABORT_MSG_IF(inAmpdu, "Received management frame as part of an A-MPDU");
1391
1392 if (hdr.IsBeacon() || hdr.IsProbeResp())
1393 {
1394 // Apply SNR tag for beacon quality measurements
1395 SnrTag tag;
1396 tag.Set(rxSnr);
1397 Ptr<Packet> packet = mpdu->GetPacket()->Copy();
1398 packet->AddPacketTag(tag);
1399 mpdu = Create<WifiMpdu>(packet, hdr);
1400 }
1401
1402 if (hdr.GetAddr1() == m_self)
1403 {
1404 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1405 << ", schedule ACK");
1408 this,
1409 hdr,
1410 txVector,
1411 rxSnr);
1412 }
1413
1414 m_rxMiddle->Receive(mpdu, m_linkId);
1415 }
1416 else if (hdr.IsData() && !hdr.IsQosData())
1417 {
1418 if (hdr.GetAddr1() == m_self)
1419 {
1420 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1421 << ", schedule ACK");
1424 this,
1425 hdr,
1426 txVector,
1427 rxSnr);
1428 }
1429
1430 m_rxMiddle->Receive(mpdu, m_linkId);
1431 }
1432}
1433
1434void
1436 const WifiTxVector& txVector,
1437 const WifiTxVector& ackTxVector,
1438 const RxSignalInfo& rxInfo,
1439 double snr)
1440{
1441 Mac48Address sender = mpdu->GetHeader().GetAddr1();
1442 NS_LOG_DEBUG("Received ACK from=" << sender);
1443 m_txTimer.GotResponseFrom(sender);
1444
1446
1447 // When fragmentation is used, only update manager when the last fragment is acknowledged
1448 if (!mpdu->GetHeader().IsMoreFragments())
1449 {
1450 GetWifiRemoteStationManager()->ReportRxOk(sender, rxInfo, ackTxVector);
1451 GetWifiRemoteStationManager()->ReportDataOk(mpdu,
1452 rxInfo.snr,
1453 ackTxVector.GetMode(),
1454 snr,
1455 txVector);
1456 }
1457 // cancel the timer
1458 m_txTimer.Cancel();
1459 m_channelAccessManager->NotifyAckTimeoutResetNow();
1460
1461 // The CW shall be reset to aCWmin after every successful attempt to transmit
1462 // a frame containing all or part of an MSDU or MMPDU (sec. 10.3.3 of 802.11-2016)
1464
1465 if (mpdu->GetHeader().IsMoreFragments())
1466 {
1467 // replace the current fragment with the next one
1468 m_dcf->GetWifiMacQueue()->Replace(mpdu, GetNextFragment());
1469 m_moreFragments = true;
1470 }
1471 else
1472 {
1473 // the MPDU has been acknowledged, we can now dequeue it if it is stored in a queue
1474 DequeueMpdu(mpdu);
1475 }
1476
1478}
1479
1480void
1482{
1483 NS_LOG_FUNCTION(this << *mpdu);
1484
1485 // inform the MAC that the transmission was successful
1487 {
1488 m_ackedMpduCallback(mpdu);
1489 }
1490}
1491
1492void
1494 const RxSignalInfo& rxSignalInfo,
1495 const WifiTxVector& txVector,
1496 const std::vector<bool>& perMpduStatus)
1497{
1498 NS_ASSERT_MSG(false, "A non-QoS station should not receive an A-MPDU");
1499}
1500
1501} // 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)
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
Ptr< WifiMpdu > m_mpdu
the MPDU being transmitted
virtual void SetAckManager(Ptr< WifiAckManager > ackManager)
Set the Acknowledgment Manager to use.
void NotifyOffNow()
This method is typically invoked by the PhyListener to notify the MAC layer that the device has been ...
virtual void NotifyInternalCollision(Ptr< Txop > txop)
Notify that an internal collision has occurred for the given Txop.
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.
virtual void UpdateNav(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Update the NAV, if needed, based on the Duration/ID of the given psdu.
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
void SendNormalAck(const WifiMacHeader &hdr, const WifiTxVector &dataTxVector, double dataSnr)
Send Normal Ack.
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
virtual void SendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiMode rtsTxMode, double rtsSnr)
Send CTS after receiving RTS.
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const
Retransmit an MPDU that was not acknowledged.
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 ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector)
Forward an MPDU down to the PHY layer.
virtual void SetLinkId(uint8_t linkId)
Set the ID of the link this Frame Exchange Manager is associated with.
virtual bool VirtualCsMediumIdle() const
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
virtual void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu)
Notify other components that an MPDU was acknowledged.
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 NotifySwitchingStartNow(Time duration)
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 CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
virtual void ReceivedMacHdr(const WifiMacHeader &macHdr, const WifiTxVector &txVector, Time psduDuration)
Store information about the MAC header of the MPDU being received.
virtual void CalculateProtectionTime(WifiProtection *protection) const
Calculate the time required to protect a frame according to the given protection method.
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.
virtual void NavResetTimeout()
Reset the NAV upon expiration of the NAV reset timer.
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.
virtual void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
This method is called when the reception of an A-MPDU including multiple MPDUs is completed.
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.
Ptr< WifiMpdu > DropMpduIfRetryLimitReached(Ptr< WifiPsdu > psdu)
Wrapper for the GetMpdusToDropOnTxFailure function of the remote station manager that additionally dr...
Ptr< WifiMpdu > GetNextFragment()
Get the next fragment of the current MSDU.
virtual void ReleaseSequenceNumbers(Ptr< const WifiPsdu > psdu) const
Make the sequence numbers of MPDUs included in the given PSDU available again if the MPDUs have never...
std::set< Mac48Address > m_sentFrameTo
the STA(s) to which we sent a frame requesting a response
void SetAckedMpduCallback(AckedMpdu callback)
Set the callback to invoke when an MPDU is successfully acked.
virtual void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
virtual Time GetFrameDurationId(const WifiMacHeader &header, uint32_t size, const WifiTxParameters &txParams, Ptr< Packet > fragmentedPacket) const
Compute how to set the Duration/ID field of a frame being transmitted with the given TX parameters.
virtual Time GetCtsToSelfDurationId(const WifiTxVector &ctsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of a CTS-to-self frame to send to protect a frame transmitte...
void DoSendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiTxVector &ctsTxVector, double rtsSnr)
Send CTS after receiving RTS.
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...
virtual void TransmissionFailed(bool forceCurrentCw=false)
Take necessary actions upon a transmission failure.
AckedMpdu m_ackedMpduCallback
the acknowledged MPDU callback
virtual void FinalizeMacHeader(Ptr< const WifiPsdu > psdu)
Finalize the MAC header of the MPDUs in the given PSDU before transmission.
virtual void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
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
virtual void ReceivedNormalAck(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector, const WifiTxVector &ackTxVector, const RxSignalInfo &rxInfo, double snr)
Perform the actions needed when a Normal Ack is received.
bool m_promisc
Flag if the device is operating in promiscuous mode.
void NotifySleepNow()
This method is typically invoked by the PhyListener to notify the MAC layer that the device has been ...
virtual void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu)
This method handles the reception of an MPDU (possibly included in an A-MPDU)
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.
bool m_moreFragments
true if a fragment has to be sent after a SIFS
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.
virtual Time GetTxDuration(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams) const
Get the updated TX duration of the frame associated with the given TX parameters if the size of the P...
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
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition packet.h:850
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
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
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: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
void UpdateFailedCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission failure.
Definition txop.cc:378
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition txop.cc:264
void ResetCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission success or...
Definition txop.cc:368
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:48
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.
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition wifi-mac.cc:694
represent a single transmission mode
Definition wifi-mode.h:40
void Send(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
This function is a wrapper for the Send variant that accepts a WifiConstPsduMap as first argument.
Definition wifi-phy.cc:1807
Time GetSlot() const
Return the slot duration for this PHY.
Definition wifi-phy.cc:841
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 Set(Reason reason, const Time &delay, const std::set< Mac48Address > &from, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
Reason GetReason() const
Get the reason why the timer was started.
void GotResponseFrom(const Mac48Address &from)
Notify that a response was got from the given station.
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:1380
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
@ STA
Definition wifi-mac.h:59
@ 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
static const uint16_t WIFI_MAC_FCS_LENGTH
The length in octets of the IEEE 802.11 MAC FCS field.
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:95
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< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
Definition wifi-utils.cc:50
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
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.