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
66
71
72void
74{
75 NS_LOG_FUNCTION(this);
76 m_txTimer.Cancel();
77 m_navResetEvent.Cancel();
78 m_sendCtsEvent.Cancel();
80 m_mpdu = nullptr;
81 m_txParams.Clear();
82 m_ongoingRxInfo.macHdr.reset();
83 m_ongoingRxInfo.endOfPsduRx = Time{};
84 m_dcf = nullptr;
85}
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
176{
177 NS_LOG_FUNCTION(this << phy);
178 m_phy = phy;
179 m_phy->TraceConnectWithoutContext("PhyRxPayloadBegin",
181 m_phy->TraceConnectWithoutContext("PhyRxMacHeaderEnd",
183 m_phy->SetReceiveOkCallback(MakeCallback(&FrameExchangeManager::Receive, this));
184 m_phy->SetReceiveErrorCallback(MakeCallback(&FrameExchangeManager::PsduRxError, this));
185}
186
187void
189{
190 NS_LOG_FUNCTION(this);
191 if (m_phy)
192 {
193 m_phy->TraceDisconnectWithoutContext(
194 "PhyRxPayloadBegin",
196 m_phy->TraceDisconnectWithoutContext(
197 "PhyRxMacHeaderEnd",
199 if (m_phy->GetState())
200 {
201 m_phy->SetReceiveOkCallback(MakeNullCallback<void,
204 const WifiTxVector&,
205 const std::vector<bool>&>());
206 m_phy->SetReceiveErrorCallback(MakeNullCallback<void, Ptr<const WifiPsdu>>());
207 }
208 m_phy = nullptr;
209 m_ongoingRxInfo.macHdr.reset();
210 m_ongoingRxInfo.endOfPsduRx = Time{};
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
295 NS_ASSERT_MSG(!m_txTimer.IsRunning() || !m_navResetEvent.IsPending(),
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 {
307 // postpone the timer expiration by an additional SIFS, so that SendNormalAck() and
308 // SendBlockAck() detect that this is a frame exchange initiated by us and take usual
309 // actions in case of successful transmission
310 m_txTimer.Reschedule(psduDuration + m_phy->GetSifs() +
312 }
313 else
314 {
315 m_txTimer.Reschedule(psduDuration + NanoSeconds(PSDU_DURATION_SAFEGUARD));
316 // PHY has switched to RX, so we can reset the ack timeout
317 m_channelAccessManager->NotifyAckTimeoutResetNow();
318 }
319 }
320
321 if (m_navResetEvent.IsPending())
322 {
323 m_navResetEvent.Cancel();
324 }
325
326 m_ongoingRxInfo = {std::nullopt, txVector, Simulator::Now() + psduDuration};
327}
328
329void
331 const WifiTxVector& txVector,
332 Time psduDuration)
333{
334 NS_LOG_FUNCTION(this << macHdr << txVector << psduDuration.As(Time::MS));
335 m_ongoingRxInfo = {macHdr, txVector, Simulator::Now() + psduDuration};
336 UpdateNav(macHdr, txVector, psduDuration);
337}
338
339std::optional<std::reference_wrapper<const FrameExchangeManager::OngoingRxInfo>>
341{
342 if (m_ongoingRxInfo.endOfPsduRx >= Simulator::Now())
343 {
344 return m_ongoingRxInfo;
345 }
346 return std::nullopt;
347}
348
349std::optional<std::reference_wrapper<const WifiMacHeader>>
351{
352 if (auto info = GetOngoingRxInfo(); info.has_value() && info->get().macHdr.has_value())
353 {
354 return info->get().macHdr.value();
355 }
356 return std::nullopt;
357}
358
359bool
361{
362 NS_LOG_FUNCTION(this << dcf << allowedWidth);
363
365 if (m_txTimer.IsRunning())
366 {
367 m_txTimer.Cancel();
368 }
369 m_dcf = dcf;
370 m_allowedWidth = allowedWidth;
371
372 Ptr<WifiMacQueue> queue = dcf->GetWifiMacQueue();
373
374 // Even though channel access is requested when the queue is not empty, at
375 // the time channel access is granted the lifetime of the packet might be
376 // expired and the queue might be empty.
377 queue->WipeAllExpiredMpdus();
378
379 Ptr<WifiMpdu> mpdu = queue->Peek(m_linkId);
380
381 if (!mpdu)
382 {
383 NS_LOG_DEBUG("Queue empty");
385 m_dcf = nullptr;
386 return false;
387 }
388
389 m_dcf->NotifyChannelAccessed(m_linkId);
390 const auto& hdr = mpdu->GetHeader();
391
392 NS_ASSERT(hdr.IsData() || hdr.IsMgt() || hdr.IsPsPoll());
393
394 PrepareFrameToSend(mpdu);
395 return true;
396}
397
398void
400{
401 NS_ASSERT(peekedItem);
402
403 if (!peekedItem->IsFragment() && !peekedItem->HasSeqNoAssigned())
404 {
405 // in case of 11be MLDs, sequence numbers refer to the MLD address
406 uint16_t sequence =
407 m_txMiddle->GetNextSequenceNumberFor(&peekedItem->GetOriginal()->GetHeader());
408 peekedItem->AssignSeqNo(sequence);
409 }
410
411 NS_LOG_FUNCTION(this << *peekedItem);
412
413 // check if the MSDU needs to be fragmented
414 auto mpdu = GetFirstFragmentIfNeeded(peekedItem);
415
418 WifiTxParameters txParams;
419 txParams.m_txVector =
420 GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
421 txParams.AddMpdu(mpdu);
422 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
423 txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
424 txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
425
426 SendMpduWithProtection(mpdu, txParams);
427}
428
429bool
431{
432 NS_ASSERT_MSG(GetWifiRemoteStationManager()->IsInPsMode(sender),
433 sender << " is not in powersave mode");
434
435 auto senderMld = GetWifiRemoteStationManager()->GetMldAddress(sender).value_or(sender);
436 auto bu = m_apMac->GetBufferedDataFor(senderMld, m_linkId);
437 if (!bu)
438 {
439 bu = m_apMac->GetBufferedMmpduFor(senderMld, m_linkId);
440 }
441 if (bu)
442 {
444 return true;
445 }
446 return false;
447}
448
451{
452 NS_LOG_FUNCTION(this << *mpdu);
453
454 if (mpdu->IsFragment())
455 {
456 // a fragment cannot be further fragmented
458 }
459 else if (GetWifiRemoteStationManager()->NeedFragmentation(mpdu))
460 {
461 NS_LOG_DEBUG("Fragmenting the MSDU");
462 m_fragmentedPacket = mpdu->GetPacket()->Copy();
463 // create the first fragment
464 Ptr<Packet> fragment = m_fragmentedPacket->CreateFragment(
465 0,
466 GetWifiRemoteStationManager()->GetFragmentSize(mpdu, 0));
467 // enqueue the first fragment
468 Ptr<WifiMpdu> item = Create<WifiMpdu>(fragment, mpdu->GetHeader());
469 item->GetHeader().SetMoreFragments();
470 m_mac->GetTxopQueue(mpdu->GetQueueAc())->Replace(mpdu, item);
471 return item;
472 }
473 return mpdu;
474}
475
476void
478{
479 NS_LOG_FUNCTION(this << *mpdu << &txParams);
480
481 m_mpdu = mpdu;
482 m_txParams = std::move(txParams);
483
484 // If protection is required, the MPDU must be stored in some queue because
485 // it is not put back in a queue if the RTS/CTS exchange fails
486 NS_ASSERT(m_txParams.m_protection->method == WifiProtection::NONE ||
487 m_mpdu->GetHeader().IsCtl() || m_mpdu->IsQueued());
488
489 // Make sure that the acknowledgment time has been computed, so that SendRts()
490 // and SendCtsToSelf() can reuse this value.
491 NS_ASSERT(m_txParams.m_acknowledgment);
492
493 if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
494 {
495 CalculateAcknowledgmentTime(m_txParams.m_acknowledgment.get());
496 }
497
498 // Set QoS Ack policy if this is a QoS data frame
499 WifiAckManager::SetQosAckPolicy(m_mpdu, m_txParams.m_acknowledgment.get());
500
501 if (m_mpdu->IsQueued())
502 {
503 m_mpdu->SetInFlight(m_linkId);
504 }
505
507}
508
509void
511{
512 NS_LOG_FUNCTION(this << &txParams);
513
514 switch (txParams.m_protection->method)
515 {
517 SendRts(txParams);
518 break;
520 SendCtsToSelf(txParams);
521 break;
524 break;
525 default:
526 NS_ABORT_MSG("Unknown protection type: " << txParams.m_protection.get());
527 }
528}
529
530void
532{
533 NS_LOG_FUNCTION(this);
535 m_sentRtsTo.clear();
537 if (m_txParams.m_protection->method == WifiProtection::NONE)
538 {
539 SendMpdu();
540 }
541 else
542 {
544 }
545}
546
547const std::set<Mac48Address>&
552
553void
555{
556 NS_LOG_FUNCTION(this);
557
559 m_txParams.m_txVector,
560 m_phy->GetPhyBand());
561
562 NS_ASSERT(m_txParams.m_acknowledgment);
563
564 if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
565 {
566 if (m_mac->GetTypeOfStation() == AP && m_apMac->UseGcr(m_mpdu->GetHeader()))
567 {
568 if (m_apMac->GetGcrManager()->KeepGroupcastQueued(m_mpdu))
569 {
570 // keep the groupcast frame in the queue for future retransmission
571 Simulator::Schedule(txDuration + m_phy->GetSifs(), [=, this, mpdu = m_mpdu]() {
572 NS_LOG_DEBUG("Prepare groupcast MPDU for retry");
573 mpdu->ResetInFlight(m_linkId);
574 // restore addr1 to the group address instead of the concealment address
575 if (m_apMac->GetGcrManager()->UseConcealment(mpdu->GetHeader()))
576 {
577 mpdu->GetHeader().SetAddr1(mpdu->begin()->second.GetDestinationAddr());
578 }
579 mpdu->GetHeader().SetRetry();
580 });
581 }
582 else
583 {
584 if (m_apMac->GetGcrManager()->GetRetransmissionPolicy() ==
586 {
588 }
590 }
591 }
592 else if (m_mpdu->GetHeader().IsPsPoll())
593 {
594 // the Duration/ID field has been already set to the AID of the STA. We assume that the
595 // AP will use the same modulation class as the PS-Poll frame to send us a data frame
596 const auto timeout =
597 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
599 NS_ASSERT(!m_txTimer.IsRunning());
601 timeout,
602 {m_mpdu->GetHeader().GetAddr1()},
604 this,
605 m_mpdu,
606 m_txParams.m_txVector);
607 m_channelAccessManager->NotifyAckTimeoutStartNow(timeout);
608 }
609
610 if (!m_mpdu->GetHeader().IsPsPoll())
611 {
612 Simulator::Schedule(txDuration, [=, this]() {
613 if ((!m_apMac || !m_apMac->UseGcr(m_mpdu->GetHeader())) &&
614 (!m_mpdu->GetHeader().IsQosData() ||
615 m_mpdu->GetHeader().GetQosAckPolicy() == WifiMacHeader::NO_ACK))
616 {
617 // No acknowledgment, hence dequeue the MPDU if it is stored in a queue
619 }
621 m_mpdu = nullptr;
622 });
623 }
624 }
625 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
626 {
627 m_mpdu->GetHeader().SetDuration(
628 GetFrameDurationId(m_mpdu->GetHeader(),
629 GetPsduSize(m_mpdu, m_txParams.m_txVector),
630 m_txParams,
631 m_fragmentedPacket));
632
633 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
634 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
635 // aRxPHYStartDelay equals the time to transmit the PHY header.
636 auto normalAcknowledgment = static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
637
638 Time timeout =
639 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
640 WifiPhy::CalculatePhyPreambleAndHeaderDuration(normalAcknowledgment->ackTxVector);
641 NS_ASSERT(!m_txTimer.IsRunning());
642 m_txTimer.Set(WifiTxTimer::WAIT_NORMAL_ACK,
643 timeout,
644 {m_mpdu->GetHeader().GetAddr1()},
646 this,
647 m_mpdu,
648 m_txParams.m_txVector);
649 m_channelAccessManager->NotifyAckTimeoutStartNow(timeout);
650 }
651 else
652 {
653 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
654 << m_txParams.m_acknowledgment.get() << ")");
655 }
656
657 // transmit the MPDU
658 ForwardMpduDown(m_mpdu, m_txParams.m_txVector);
659
660 if (m_txTimer.IsRunning())
661 {
662 NS_ASSERT(m_sentFrameTo.empty());
663 m_sentFrameTo = {m_mpdu->GetHeader().GetAddr1()};
664 }
665}
666
667void
669{
670 NS_LOG_FUNCTION(this << *mpdu << txVector);
671
672 auto psdu = Create<WifiPsdu>(mpdu, false);
673 FinalizeMacHeader(psdu);
674 m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
675 const auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
676 SetTxNav(mpdu, txDuration);
677
678 const auto& hdr = psdu->GetHeader(0);
679 // if this is an Ack sent to acknowledge a frame in response to a PS-Poll that we
680 // sent, we need to take the actions required to conclude a frame exchange
681 if (m_txTimer.IsRunning() && m_txTimer.GetReason() == WifiTxTimer::WAIT_DATA_AFTER_PS_POLL &&
682 hdr.IsAck() && hdr.GetAddr1() == m_bssid)
683 {
686 }
687
688 m_phy->Send(psdu, txVector);
689}
690
691void
693{
694 NS_LOG_FUNCTION(this << psdu);
695
696 // The More Data subfield is valid in individually addressed Data or Management frames
697 // transmitted by an AP to a STA in PS mode (Sec. 9.2.4.1.8 of 802.11-2020)
698 // The More Data subfield of each group addressed frame shall be set to indicate the presence
699 // of further buffered non-GCR-SP group addressed BUs that will be delivered using MPDUs with
700 // an RA other than a SYNRA (Sec. 11.2.3.6 of 802.11-2020)
701 if (m_apMac)
702 {
703 const auto& hdr = psdu->GetHeader(0);
704 const auto staInPsModeOrGroupDest =
705 hdr.GetAddr1().IsGroup() || GetWifiRemoteStationManager()->IsInPsMode(hdr.GetAddr1());
706 const auto txGroupAddrFramesAfterDtimOrUnicastDest =
707 !hdr.GetAddr1().IsGroup() || m_apMac->GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(
708 m_linkId,
711 if ((hdr.IsData() || hdr.IsMgt() || hdr.IsBlockAckReq()) && staInPsModeOrGroupDest &&
712 txGroupAddrFramesAfterDtimOrUnicastDest)
713 {
714 // All MPDUs but the last one certainly have the More Data flag set.
715 for (const auto& mpdu : *PeekPointer(psdu))
716 {
717 mpdu->GetHeader().SetMoreData(true);
718 }
719 // set the More Data flag of the last MPDU if there are other queued frames
720 auto mpdu = *std::prev(psdu->end());
721 mpdu->GetHeader().SetMoreData(m_apMac->HasMoreDataAfter(mpdu, m_linkId));
722 }
723 }
724
725 if (m_mac->GetTypeOfStation() != STA)
726 {
727 return;
728 }
729
730 auto pmMode = StaticCast<StaWifiMac>(m_mac)->GetPmMode(m_linkId);
731
732 for (const auto& mpdu : *PeekPointer(psdu))
733 {
734 switch (pmMode)
735 {
736 case WIFI_PM_ACTIVE:
738 mpdu->GetHeader().SetNoPowerManagement();
739 break;
742 mpdu->GetHeader().SetPowerManagement();
743 break;
744 default:
745 NS_ABORT_MSG("Unknown PM mode: " << +pmMode);
746 }
747 }
748}
749
750void
752{
753 NS_LOG_DEBUG(this << *mpdu);
754
755 if (mpdu->IsQueued())
756 {
757 m_mac->GetTxopQueue(mpdu->GetQueueAc())->DequeueIfQueued({mpdu});
758 }
759}
760
763{
764 return mpdu->GetSize();
765}
766
767void
769{
770 NS_LOG_FUNCTION(this << protection);
771 NS_ASSERT(protection);
772
773 if (protection->method == WifiProtection::NONE)
774 {
775 protection->protectionTime = Seconds(0);
776 }
777 else if (protection->method == WifiProtection::RTS_CTS)
778 {
779 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
780 rtsCtsProtection->protectionTime =
782 rtsCtsProtection->rtsTxVector,
783 m_phy->GetPhyBand()) +
785 rtsCtsProtection->ctsTxVector,
786 m_phy->GetPhyBand()) +
787 2 * m_phy->GetSifs();
788 }
789 else if (protection->method == WifiProtection::CTS_TO_SELF)
790 {
791 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(protection);
792 ctsToSelfProtection->protectionTime =
794 ctsToSelfProtection->ctsTxVector,
795 m_phy->GetPhyBand()) +
796 m_phy->GetSifs();
797 }
798}
799
800void
802{
803 NS_LOG_FUNCTION(this << acknowledgment);
804 NS_ASSERT(acknowledgment);
805
806 if (acknowledgment->method == WifiAcknowledgment::NONE)
807 {
808 acknowledgment->acknowledgmentTime = Seconds(0);
809 }
810 else if (acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
811 {
812 auto normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
813 normalAcknowledgment->acknowledgmentTime =
815 normalAcknowledgment->ackTxVector,
816 m_phy->GetPhyBand());
817 }
818}
819
820Time
822 Mac48Address receiver,
823 const WifiTxParameters& txParams) const
824{
825 return WifiPhy::CalculateTxDuration(ppduPayloadSize, txParams.m_txVector, m_phy->GetPhyBand());
826}
827
828void
830{
831 txParams.m_txDuration = GetTxDuration(txParams.GetSize(receiver), receiver, txParams);
832}
833
834Time
836 uint32_t size,
837 const WifiTxParameters& txParams,
838 Ptr<Packet> fragmentedPacket) const
839{
840 NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
841
842 NS_ASSERT(txParams.m_acknowledgment &&
843 txParams.m_acknowledgment->acknowledgmentTime.has_value());
844 auto durationId = *txParams.m_acknowledgment->acknowledgmentTime;
845
846 // if the current frame is a fragment followed by another fragment, we have to
847 // update the Duration/ID to cover the next fragment and the corresponding Ack
848 if (header.IsMoreFragments())
849 {
850 uint32_t payloadSize = size - header.GetSize() - WIFI_MAC_FCS_LENGTH;
851 uint32_t nextFragmentOffset = (header.GetFragmentNumber() + 1) * payloadSize;
852 uint32_t nextFragmentSize =
853 std::min(fragmentedPacket->GetSize() - nextFragmentOffset, payloadSize);
854 WifiTxVector ackTxVector =
855 GetWifiRemoteStationManager()->GetAckTxVector(header.GetAddr1(), txParams.m_txVector);
856
857 durationId += 2 * m_phy->GetSifs() +
858 WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand()) +
859 WifiPhy::CalculateTxDuration(nextFragmentSize,
860 txParams.m_txVector,
861 m_phy->GetPhyBand());
862 }
863 return durationId;
864}
865
866Time
868 Time txDuration,
869 Time response) const
870{
871 NS_LOG_FUNCTION(this << rtsTxVector << txDuration << response);
872
873 WifiTxVector ctsTxVector;
874 ctsTxVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_self, rtsTxVector.GetMode());
875
876 return m_phy->GetSifs() +
877 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) /* CTS */
878 + m_phy->GetSifs() + txDuration + response;
879}
880
881void
883{
884 NS_LOG_FUNCTION(this << &txParams);
885
886 NS_ASSERT(txParams.GetPsduInfoMap().size() == 1);
887
888 const auto& hdr = txParams.GetPsduInfoMap().begin()->second.header;
889 const auto receiver = GetIndividuallyAddressedRecipient(m_mac, hdr);
890
891 WifiMacHeader rts;
893 rts.SetDsNotFrom();
894 rts.SetDsNotTo();
895 rts.SetNoRetry();
896 rts.SetNoMoreFragments();
897 rts.SetAddr1(receiver);
898 rts.SetAddr2(m_self);
899
900 NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
901 auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
902
903 NS_ASSERT(txParams.m_txDuration.has_value());
904 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
905 rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
906 *txParams.m_txDuration,
907 *txParams.m_acknowledgment->acknowledgmentTime));
909
910 // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with
911 // a value of aSIFSTime + aSlotTime + aRxPHYStartDelay (IEEE 802.11-2016 sec. 10.3.2.7).
912 // aRxPHYStartDelay equals the time to transmit the PHY header.
914 rtsCtsProtection->rtsTxVector,
915 m_phy->GetPhyBand()) +
916 m_phy->GetSifs() + m_phy->GetSlot() +
917 WifiPhy::CalculatePhyPreambleAndHeaderDuration(rtsCtsProtection->ctsTxVector);
918 NS_ASSERT(!m_txTimer.IsRunning());
920 timeout,
921 {receiver},
923 this,
924 mpdu,
925 rtsCtsProtection->rtsTxVector);
926 m_channelAccessManager->NotifyCtsTimeoutStartNow(timeout);
927 NS_ASSERT(m_sentRtsTo.empty());
928 m_sentRtsTo = {receiver};
929
930 ForwardMpduDown(mpdu, rtsCtsProtection->rtsTxVector);
931}
932
933void
935 WifiTxVector& ctsTxVector,
936 double rtsSnr)
937{
938 NS_LOG_FUNCTION(this << rtsHdr << ctsTxVector << rtsSnr);
939
940 WifiMacHeader cts;
942 cts.SetDsNotFrom();
943 cts.SetDsNotTo();
944 cts.SetNoMoreFragments();
945 cts.SetNoRetry();
946 cts.SetAddr1(rtsHdr.GetAddr2());
947 Time duration = rtsHdr.GetDuration() - m_phy->GetSifs() -
948 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand());
949 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
950 if (duration.IsStrictlyNegative())
951 {
952 duration = Seconds(0);
953 }
954 cts.SetDuration(duration);
955
956 Ptr<Packet> packet = Create<Packet>();
957
958 SnrTag tag;
959 tag.Set(rtsSnr);
960 packet->AddPacketTag(tag);
961
962 // CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
963 ForwardMpduDown(Create<WifiMpdu>(packet, cts), ctsTxVector);
964}
965
966void
968 const WifiTxVector& rtsTxVector,
969 double rtsSnr)
970{
971 NS_LOG_FUNCTION(this << rtsHdr << rtsTxVector << rtsSnr);
972
973 WifiTxVector ctsTxVector =
974 GetWifiRemoteStationManager()->GetCtsTxVector(rtsHdr.GetAddr2(), rtsTxVector.GetMode());
975 DoSendCtsAfterRts(rtsHdr, ctsTxVector, rtsSnr);
976}
977
978Time
980 Time txDuration,
981 Time response) const
982{
983 NS_LOG_FUNCTION(this << ctsTxVector << txDuration << response);
984
985 return m_phy->GetSifs() + txDuration + response;
986}
987
988void
990{
991 NS_LOG_FUNCTION(this << &txParams);
992
993 WifiMacHeader cts;
995 cts.SetDsNotFrom();
996 cts.SetDsNotTo();
997 cts.SetNoMoreFragments();
998 cts.SetNoRetry();
999 cts.SetAddr1(m_self);
1000
1001 NS_ASSERT(txParams.m_protection &&
1002 txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
1003 auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
1004
1005 NS_ASSERT(txParams.m_txDuration.has_value());
1006 NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
1007 cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
1008 *txParams.m_txDuration,
1009 *txParams.m_acknowledgment->acknowledgmentTime));
1010
1011 ForwardMpduDown(Create<WifiMpdu>(Create<Packet>(), cts), ctsToSelfProtection->ctsTxVector);
1012
1014 ctsToSelfProtection->ctsTxVector,
1015 m_phy->GetPhyBand());
1017}
1018
1019void
1021 const WifiTxVector& dataTxVector,
1022 double dataSnr)
1023{
1024 NS_LOG_FUNCTION(this << hdr << dataTxVector << dataSnr);
1025
1026 WifiTxVector ackTxVector =
1027 GetWifiRemoteStationManager()->GetAckTxVector(hdr.GetAddr2(), dataTxVector);
1028 WifiMacHeader ack;
1030 ack.SetDsNotFrom();
1031 ack.SetDsNotTo();
1032 ack.SetNoRetry();
1033 ack.SetNoMoreFragments();
1034 ack.SetAddr1(hdr.GetAddr2());
1035 // 802.11-2016, Section 9.2.5.7: Duration/ID is received duration value
1036 // minus the time to transmit the Ack frame and its SIFS interval, unless this Ack follows a
1037 // PS-Poll frame, whose Duration/ID contains the AID of the STA
1038 auto duration =
1039 hdr.IsPsPoll()
1040 ? Time{0}
1041 : hdr.GetDuration() - m_phy->GetSifs() -
1042 WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand());
1043 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1044 if (duration.IsStrictlyNegative())
1045 {
1046 duration = Seconds(0);
1047 }
1048 ack.SetDuration(duration);
1049
1050 Ptr<Packet> packet = Create<Packet>();
1051
1052 SnrTag tag;
1053 tag.Set(dataSnr);
1054 packet->AddPacketTag(tag);
1055
1056 ForwardMpduDown(Create<WifiMpdu>(packet, ack), ackTxVector);
1057}
1058
1061{
1062 NS_LOG_FUNCTION(this);
1063 NS_ASSERT(m_mpdu->GetHeader().IsMoreFragments());
1064
1065 WifiMacHeader& hdr = m_mpdu->GetHeader();
1066 hdr.SetFragmentNumber(hdr.GetFragmentNumber() + 1);
1067
1068 uint32_t startOffset = hdr.GetFragmentNumber() * m_mpdu->GetPacketSize();
1069 uint32_t size = m_fragmentedPacket->GetSize() - startOffset;
1070
1071 if (size > m_mpdu->GetPacketSize())
1072 {
1073 // this is not the last fragment
1074 size = m_mpdu->GetPacketSize();
1075 hdr.SetMoreFragments();
1076 }
1077 else
1078 {
1079 hdr.SetNoMoreFragments();
1080 }
1081
1082 return Create<WifiMpdu>(m_fragmentedPacket->CreateFragment(startOffset, size), hdr);
1083}
1084
1085void
1087{
1088 NS_LOG_FUNCTION(this);
1089 m_sentFrameTo.clear();
1090
1091 // Upon a transmission success, a non-QoS station transmits the next fragment,
1092 // if any, or releases the channel, otherwise
1093 if (m_moreFragments)
1094 {
1095 NS_LOG_DEBUG("Schedule transmission of next fragment in a SIFS");
1096 Simulator::Schedule(m_phy->GetSifs(),
1098 this,
1099 m_dcf,
1101 m_moreFragments = false;
1102 }
1103 else
1104 {
1106 m_dcf = nullptr;
1107 }
1108}
1109
1110void
1112{
1113 NS_LOG_FUNCTION(this << forceCurrentCw);
1114 if (!forceCurrentCw)
1115 {
1116 m_dcf->UpdateFailedCw(m_linkId);
1117 }
1118 m_sentFrameTo.clear();
1119 // reset TXNAV because transmission failed
1120 ResetTxNav();
1121 // A non-QoS station always releases the channel upon a transmission failure
1123 m_dcf = nullptr;
1124}
1125
1126void
1128{
1129 NS_LOG_FUNCTION(this << txop);
1130 txop->NotifyChannelReleased(m_linkId);
1131 m_protectedStas.clear();
1132}
1133
1136{
1137 NS_LOG_FUNCTION(this << *psdu);
1138
1139 const auto mpdusToDrop = GetWifiRemoteStationManager()->GetMpdusToDropOnTxFailure(psdu);
1140 Ptr<WifiMpdu> droppedMpdu{nullptr};
1141
1142 for (const auto& mpdu : mpdusToDrop)
1143 {
1144 // this MPDU needs to be dropped
1145 droppedMpdu = mpdu;
1147 DequeueMpdu(mpdu);
1148 }
1149
1150 return droppedMpdu;
1151}
1152
1153void
1155{
1156 NS_LOG_FUNCTION(this << *mpdu << txVector);
1157
1158 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1159 if (auto droppedMpdu = DropMpduIfRetryLimitReached(Create<WifiPsdu>(mpdu, false)))
1160 {
1161 // notify remote station manager if at least an MPDU was dropped
1162 GetWifiRemoteStationManager()->ReportFinalDataFailed(droppedMpdu);
1163 }
1164
1165 // the MPDU may have been dropped due to lifetime expiration or maximum amount of
1166 // retransmissions reached
1167 if (mpdu->IsQueued())
1168 {
1169 mpdu = m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu);
1170 mpdu->ResetInFlight(m_linkId);
1171 mpdu->GetHeader().SetRetry();
1173 }
1174
1175 m_mpdu = nullptr;
1176 // m_dcf is null if we were given the right to transmit a frame (e.g., we received a PS-Poll
1177 // frame), we transmitted a frame but we did not receive an Ack; in such a case, we shall not
1178 // take usual actions, such as updating the CW.
1179 if (m_dcf)
1180 {
1182 }
1183 else
1184 {
1185 m_sentFrameTo.clear();
1186 }
1187}
1188
1189void
1194
1195void
1197{
1198 NS_LOG_FUNCTION(this << *rts << txVector);
1199
1201 m_mpdu = nullptr;
1202}
1203
1204void
1206{
1207 NS_LOG_FUNCTION(this << psduMap);
1208
1209 // these functions need to be called before resetting m_sentRtsTo
1210 const auto updateCw = GetUpdateCwOnCtsTimeout();
1211 const auto reportRts = GetReportRtsFailed();
1212
1213 m_sentRtsTo.clear();
1214 for (const auto& [staId, psdu] : psduMap)
1215 {
1216 for (const auto& mpdu : *PeekPointer(psdu))
1217 {
1218 if (mpdu->IsQueued())
1219 {
1220 mpdu->ResetInFlight(m_linkId);
1221 }
1222 }
1223
1224 if (const auto& hdr = psdu->GetHeader(0);
1226 {
1227 if (reportRts)
1228 {
1229 GetWifiRemoteStationManager()->ReportRtsFailed(hdr);
1230 }
1231
1232 if (auto droppedMpdu = DropMpduIfRetryLimitReached(psdu))
1233 {
1234 GetWifiRemoteStationManager()->ReportFinalRtsFailed(droppedMpdu->GetHeader());
1235 }
1236 }
1237
1238 // Make the sequence numbers of the MPDUs available again if the MPDUs have never
1239 // been transmitted, both in case the MPDUs have been discarded and in case the
1240 // MPDUs have to be transmitted (because a new sequence number is assigned to
1241 // MPDUs that have never been transmitted and are selected for transmission)
1243 }
1244
1245 TransmissionFailed(!updateCw);
1246}
1247
1248bool
1250{
1251 return true;
1252}
1253
1254bool
1256{
1257 return true;
1258}
1259
1260void
1262{
1263 NS_LOG_FUNCTION(this << *psdu);
1264
1265 NS_ASSERT_MSG(psdu->GetNMpdus() == 1, "A-MPDUs should be handled by the HT FEM override");
1266 auto mpdu = *psdu->begin();
1267
1268 // the MPDU should be still in the DCF queue, unless it expired.
1269 // If the MPDU has never been transmitted and is not in-flight, it will be assigned
1270 // a sequence number again the next time we try to transmit it. Therefore, we need to
1271 // make its sequence number available again
1272 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
1273 {
1274 mpdu->UnassignSeqNo();
1275 m_txMiddle->SetSequenceNumberFor(&mpdu->GetOriginal()->GetHeader());
1276 }
1277}
1278
1279void
1281{
1282 NS_LOG_FUNCTION(this);
1283
1284 // For internal collisions, the frame retry counts associated with the MSDUs, A-MSDUs, or MMPDUs
1285 // involved in the internal collision shall be incremented. (Sec. 10.23.2.12.1 of 802.11-2020)
1286 // We do not prepare the PSDU that the AC losing the internal collision would have
1287 // sent. As an approximation, we consider the frame peeked from the queues of the AC.
1288 Ptr<QosTxop> qosTxop = (txop->IsQosTxop() ? StaticCast<QosTxop>(txop) : nullptr);
1289
1290 if (auto mpdu =
1291 (qosTxop ? qosTxop->PeekNextMpdu(m_linkId) : txop->GetWifiMacQueue()->Peek(m_linkId));
1292 mpdu && !mpdu->GetHeader().GetAddr1().IsGroup())
1293 {
1294 if (mpdu->GetHeader().HasData())
1295 {
1296 GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1297 }
1298
1300 {
1301 GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
1302 }
1303 }
1304
1305 txop->UpdateFailedCw(m_linkId);
1306 txop->Txop::NotifyChannelReleased(m_linkId);
1307}
1308
1309void
1311{
1312 NS_LOG_DEBUG("Switching channel. Cancelling MAC pending events");
1314 if (m_txTimer.IsRunning())
1315 {
1316 // we were transmitting something before channel switching. Since we will
1317 // not be able to receive the response, have the timer expire now, so that
1318 // we perform the actions required in case of missing response
1319 m_txTimer.Reschedule(Seconds(0));
1320 }
1322}
1323
1324void
1326{
1327 NS_LOG_DEBUG("Device in sleep mode. Cancelling MAC pending events");
1328 Reset();
1329}
1330
1331void
1333{
1334 NS_LOG_DEBUG("Device is switched off. Cancelling MAC pending events");
1335 Reset();
1336}
1337
1338void
1343
1344void
1346 RxSignalInfo rxSignalInfo,
1347 const WifiTxVector& txVector,
1348 const std::vector<bool>& perMpduStatus)
1349{
1351 this << psdu << rxSignalInfo << txVector << perMpduStatus.size()
1352 << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](bool v) { return v; }));
1353
1354 if (!perMpduStatus.empty())
1355 {
1356 // for A-MPDUs, we get here only once
1357 PreProcessFrame(psdu, txVector);
1358 }
1359
1360 Mac48Address addr1 = psdu->GetAddr1();
1361
1362 if (addr1.IsGroup() || addr1 == m_self)
1363 {
1364 // receive broadcast frames or frames addressed to us only
1365 if (psdu->GetNMpdus() == 1)
1366 {
1367 // if perMpduStatus is not empty (i.e., this MPDU is not included in an A-MPDU)
1368 // then it must contain a single value which must be true (i.e., the MPDU
1369 // has been correctly received)
1370 NS_ASSERT(perMpduStatus.empty() || (perMpduStatus.size() == 1 && perMpduStatus[0]));
1371 // Ack and CTS do not carry Addr2
1372 if (const auto& hdr = psdu->GetHeader(0); !hdr.IsAck() && !hdr.IsCts())
1373 {
1374 GetWifiRemoteStationManager()->ReportRxOk(psdu->GetAddr2(), rxSignalInfo, txVector);
1375 }
1376 ReceiveMpdu(*(psdu->begin()), rxSignalInfo, txVector, perMpduStatus.empty());
1377 }
1378 else
1379 {
1380 EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1381 }
1382 }
1383 else if (m_promisc)
1384 {
1385 for (const auto& mpdu : *PeekPointer(psdu))
1386 {
1387 if (!mpdu->GetHeader().IsCtl())
1388 {
1389 m_rxMiddle->Receive(mpdu, m_linkId);
1390 }
1391 }
1392 }
1393
1394 if (!perMpduStatus.empty())
1395 {
1396 // for A-MPDUs, we get here only once
1397 PostProcessFrame(psdu, txVector);
1398 }
1399
1400 // if the received frame is an Ack in response to a PS-Poll that we sent, we
1401 // need to take the actions required to conclude a frame exchange
1402 if (m_staMac && (psdu->GetHeader(0).IsAck() || psdu->GetAddr2() == m_bssid) &&
1403 addr1 == m_self && m_txTimer.IsRunning() &&
1405 {
1406 m_staMac->NotifyReceivedFrameAfterPsPoll(*(psdu->begin()), m_linkId);
1407
1408 if (psdu->GetHeader(0).IsAck())
1409 {
1412 }
1413 }
1414}
1415
1416void
1418{
1419 NS_LOG_FUNCTION(this);
1420 NS_ASSERT(m_staMac && m_txTimer.IsRunning() &&
1422
1423 m_txTimer.Cancel();
1424 m_channelAccessManager->NotifyAckTimeoutResetNow();
1425
1427 m_dcf->ResetCw(m_linkId);
1428
1430 NS_ASSERT(m_mpdu->GetHeader().IsPsPoll());
1432 m_mpdu = nullptr;
1433}
1434
1435void
1437{
1438 NS_LOG_FUNCTION(this << psdu << txVector);
1439}
1440
1441void
1443{
1444 NS_LOG_FUNCTION(this << psdu << txVector);
1445
1446 UpdateNav(psdu->GetHeader(0), txVector);
1447}
1448
1449void
1451 const WifiTxVector& txVector,
1452 const Time& surplus)
1453{
1454 NS_LOG_FUNCTION(this << hdr << txVector << surplus.As(Time::US));
1455
1456 if (!hdr.HasNav())
1457 {
1458 return;
1459 }
1460
1461 Time duration = hdr.GetDuration();
1462 NS_LOG_DEBUG("Duration/ID=" << duration);
1463 duration += surplus;
1464
1465 if (hdr.GetAddr1() == m_self)
1466 {
1467 // When the received frame's RA is equal to the STA's own MAC address, the STA
1468 // shall not update its NAV (IEEE 802.11-2016, sec. 10.3.2.4)
1469 return;
1470 }
1471
1472 // For all other received frames the STA shall update its NAV when the received
1473 // Duration is greater than the STA's current NAV value (IEEE 802.11-2016 sec. 10.3.2.4)
1474 Time navEnd = Simulator::Now() + duration;
1475 if (navEnd > m_navEnd)
1476 {
1477 m_navEnd = navEnd;
1478 NS_LOG_DEBUG("Updated NAV=" << m_navEnd);
1479
1480 // A STA that used information from an RTS frame as the most recent basis to update
1481 // its NAV setting is permitted to reset its NAV if no PHY-RXSTART.indication
1482 // primitive is received from the PHY during a NAVTimeout period starting when the
1483 // MAC receives a PHY-RXEND.indication primitive corresponding to the detection of
1484 // the RTS frame. NAVTimeout period is equal to:
1485 // (2 x aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 x aSlotTime)
1486 // The “CTS_Time” shall be calculated using the length of the CTS frame and the data
1487 // rate at which the RTS frame used for the most recent NAV update was received
1488 // (IEEE 802.11-2016 sec. 10.3.2.4)
1489 if (hdr.IsRts())
1490 {
1491 auto addr2 = hdr.GetAddr2();
1492 WifiTxVector ctsTxVector =
1493 GetWifiRemoteStationManager()->GetCtsTxVector(addr2, txVector.GetMode());
1494 Time navResetDelay =
1495 2 * m_phy->GetSifs() +
1496 WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1497 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
1498 m_navResetEvent.Cancel();
1501 }
1502 }
1503 NS_LOG_DEBUG("Current NAV=" << m_navEnd);
1504
1505 m_channelAccessManager->NotifyNavStartNow(duration);
1506}
1507
1508void
1515
1516void
1518{
1519 // The TXNAV timer is a single timer, shared by the EDCAFs within a STA, that is initialized
1520 // with the duration from the Duration/ID field in the frame most recently successfully
1521 // transmitted by the TXOP holder, except for PS-Poll frames. The TXNAV timer begins counting
1522 // down from the end of the transmission of the PPDU containing that frame.
1523 // (Sec.10.23.2.2 IEEE 802.11-2020)
1524 if (!mpdu->GetHeader().IsPsPoll())
1525 {
1526 const auto txNav = Simulator::Now() + txDuration + mpdu->GetHeader().GetDuration();
1527 NS_LOG_DEBUG("Setting TXNAV to " << txNav.As(Time::S));
1528 m_txNav = Max(m_txNav, txNav);
1529 }
1530}
1531
1532void
1538
1539bool
1544
1545void
1547 RxSignalInfo rxSignalInfo,
1548 const WifiTxVector& txVector,
1549 bool inAmpdu)
1550{
1551 NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1552 // The received MPDU is either broadcast or addressed to this station
1553 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1554
1555 double rxSnr = rxSignalInfo.snr;
1556 const WifiMacHeader& hdr = mpdu->GetHeader();
1557
1558 if (hdr.IsCtl())
1559 {
1560 if (hdr.IsRts())
1561 {
1562 NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
1563
1564 // A non-VHT STA that is addressed by an RTS frame behaves as follows:
1565 // - If the NAV indicates idle, the STA shall respond with a CTS frame after a SIFS
1566 // - Otherwise, the STA shall not respond with a CTS frame
1567 // (IEEE 802.11-2016 sec. 10.3.2.7)
1568 if (VirtualCsMediumIdle())
1569 {
1570 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
1573 this,
1574 hdr,
1575 txVector,
1576 rxSnr);
1577 }
1578 else
1579 {
1580 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
1581 }
1582 }
1583 else if (hdr.IsCts() && m_txTimer.IsRunning() &&
1584 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_mpdu)
1585 {
1586 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1587 NS_ASSERT(hdr.GetAddr1() == m_self);
1588
1589 const auto sender = GetIndividuallyAddressedRecipient(m_mac, m_mpdu->GetHeader());
1590 NS_LOG_DEBUG("Received CTS from=" << sender);
1591
1592 SnrTag tag;
1593 mpdu->GetPacket()->PeekPacketTag(tag);
1594 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1595 GetWifiRemoteStationManager()->ReportRtsOk(m_mpdu->GetHeader(),
1596 rxSnr,
1597 txVector.GetMode(),
1598 tag.Get());
1599
1600 m_txTimer.Cancel();
1601 m_channelAccessManager->NotifyCtsTimeoutResetNow();
1603 }
1604 else if (hdr.IsAck() && m_mpdu && m_txTimer.IsRunning() &&
1606 {
1607 NS_ASSERT(hdr.GetAddr1() == m_self);
1608 SnrTag tag;
1609 mpdu->GetPacket()->PeekPacketTag(tag);
1610 ReceivedNormalAck(m_mpdu, m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get());
1611 m_mpdu = nullptr;
1612 }
1613 else if (hdr.IsPsPoll())
1614 {
1615 NS_ABORT_MSG_IF(inAmpdu, "Received PS-Poll as part of an A-MPDU");
1616 NS_ABORT_MSG_IF(hdr.GetAddr1().IsGroup(), "Received group addressed PS-Poll");
1617
1618 if (!m_apMac)
1619 {
1620 NS_LOG_WARN("Ignoring PS-Poll addressed to us, as we are not an AP");
1621 return;
1622 }
1623
1624 auto sender = hdr.GetAddr2();
1625
1626 if (!GetWifiRemoteStationManager()->IsInPsMode(sender))
1627 {
1628 NS_LOG_WARN("Ignoring PS-Poll as the sender is not in PowerSave mode");
1629 return;
1630 }
1631
1632 NS_LOG_DEBUG("Check in a SIFS if we have a buffered unit to send to the sender");
1633 Simulator::Schedule(m_phy->GetSifs(), [=, this]() {
1634 if (!SendBufferedUnit(sender))
1635 {
1636 NS_LOG_DEBUG(
1637 "No frame to send to the sender of the PS-Poll; send a Normal Ack");
1638 SendNormalAck(hdr, txVector, rxSnr);
1639 }
1640 });
1641 }
1642 }
1643 else if (hdr.IsMgt())
1644 {
1645 NS_ABORT_MSG_IF(inAmpdu, "Received management frame as part of an A-MPDU");
1646
1647 if (hdr.IsBeacon() || hdr.IsProbeResp())
1648 {
1649 // Apply SNR tag for beacon quality measurements
1650 SnrTag tag;
1651 tag.Set(rxSnr);
1652 Ptr<Packet> packet = mpdu->GetPacket()->Copy();
1653 packet->AddPacketTag(tag);
1654 mpdu = Create<WifiMpdu>(packet, hdr);
1655 }
1656
1657 if (hdr.GetAddr1() == m_self)
1658 {
1659 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1660 << ", schedule ACK");
1661 Simulator::Schedule(m_phy->GetSifs(),
1662 &FrameExchangeManager::SendNormalAck,
1663 this,
1664 hdr,
1665 txVector,
1666 rxSnr);
1667 }
1668
1669 m_rxMiddle->Receive(mpdu, m_linkId);
1670 }
1671 else if (hdr.IsData() && !hdr.IsQosData())
1672 {
1673 if (hdr.GetAddr1() == m_self)
1674 {
1675 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1676 << ", schedule ACK");
1677 Simulator::Schedule(m_phy->GetSifs(),
1678 &FrameExchangeManager::SendNormalAck,
1679 this,
1680 hdr,
1681 txVector,
1682 rxSnr);
1683 }
1684
1685 m_rxMiddle->Receive(mpdu, m_linkId);
1686 }
1687}
1688
1689void
1691 const WifiTxVector& txVector,
1692 const WifiTxVector& ackTxVector,
1693 const RxSignalInfo& rxInfo,
1694 double snr)
1695{
1696 Mac48Address sender = mpdu->GetHeader().GetAddr1();
1697 NS_LOG_DEBUG("Received ACK from=" << sender);
1698 m_txTimer.GotResponseFrom(sender);
1699
1701
1702 // When fragmentation is used, only update manager when the last fragment is acknowledged
1703 if (!mpdu->GetHeader().IsMoreFragments())
1704 {
1705 GetWifiRemoteStationManager()->ReportRxOk(sender, rxInfo, ackTxVector);
1706 GetWifiRemoteStationManager()->ReportDataOk(mpdu,
1707 rxInfo.snr,
1708 ackTxVector.GetMode(),
1709 snr,
1710 txVector);
1711 }
1712 // cancel the timer
1713 m_txTimer.Cancel();
1714 m_channelAccessManager->NotifyAckTimeoutResetNow();
1715
1716 // The CW shall be reset to aCWmin after every successful attempt to transmit
1717 // a frame containing all or part of an MSDU or MMPDU (sec. 10.3.3 of 802.11-2016)
1718 // m_dcf is null if we were given the right to transmit a frame (e.g., we received a PS-Poll
1719 // frame), we transmitted a frame and we are now receiving the Ack; in such a case, we shall
1720 // not take usual actions, such as updating the CW.
1721 if (m_dcf)
1722 {
1723 m_dcf->ResetCw(m_linkId);
1724 }
1725 else
1726 {
1727 m_sentFrameTo.clear();
1728 }
1729
1730 if (mpdu->GetHeader().IsMoreFragments())
1731 {
1732 // replace the current fragment with the next one
1733 m_dcf->GetWifiMacQueue()->Replace(mpdu, GetNextFragment());
1734 m_moreFragments = true;
1735 }
1736 else
1737 {
1738 // the MPDU has been acknowledged, we can now dequeue it if it is stored in a queue
1739 DequeueMpdu(mpdu);
1740 }
1741
1742 if (m_dcf)
1743 {
1745 }
1746}
1747
1748void
1750{
1751 NS_LOG_FUNCTION(this << *mpdu);
1752
1753 // inform the MAC that the transmission was successful
1754 if (!m_ackedMpduCallback.IsNull())
1755 {
1756 m_ackedMpduCallback(mpdu);
1757 }
1758}
1759
1760void
1762 const RxSignalInfo& rxSignalInfo,
1763 const WifiTxVector& txVector,
1764 const std::vector<bool>& perMpduStatus)
1765{
1766 NS_ASSERT_MSG(false, "A non-QoS station should not receive an A-MPDU");
1767}
1768
1769void
1771{
1772 NS_ASSERT_MSG(false, "A non-QoS station should not use GCR-UR");
1773}
1774
1775} // namespace ns3
#define Max(a, b)
uint32_t v
AttributeValue implementation for Boolean.
Definition boolean.h:26
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.
void NotifyOffNow()
This method is typically invoked by the PhyListener to notify the MAC layer that the device has been ...
virtual void NotifyLastGcrUrTx(Ptr< const WifiMpdu > mpdu)
Notify the last (re)transmission of a groupcast MPDU using the GCR-UR service.
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
void SetTxNav(Ptr< const WifiMpdu > mpdu, const Time &txDuration)
Set the TXNAV upon sending an MPDU.
Callback< void, WifiMacDropReason, Ptr< const WifiMpdu > > DroppedMpdu
typedef for a callback to invoke when an MPDU is dropped.
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
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 bool GetReportRtsFailed() const
virtual void Reset()
Reset this frame exchange manager.
Callback< void, Ptr< const WifiMpdu > > AckedMpdu
typedef for a callback to invoke when an MPDU is successfully acknowledged.
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.
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 bool SendBufferedUnit(Mac48Address sender)
Send a buffered unit to the given sender, if any.
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.
void DoCtsTimeout(const WifiPsduMap &psduMap)
Take required actions when the CTS timer fired after sending an (MU-)RTS to protect the given PSDU ma...
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.
virtual void SendCtsAfterRts(const WifiMacHeader &rtsHdr, const WifiTxVector &rtsTxVector, double rtsSnr)
Send CTS after receiving RTS.
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.
void ReceiveFrameAfterPsPoll()
Take actions required when a frame is received from the associated AP after sending a PS-Poll frame.
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 PrepareFrameToSend(Ptr< WifiMpdu > peekedItem)
Set the sequence number, determine the transmission parameters and transmit the given MPDU,...
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 UpdateNav(const WifiMacHeader &hdr, const WifiTxVector &txVector, const Time &surplus=Time{0})
Update the NAV, if needed, based on the Duration/ID of the given MAC header and the given surplus.
virtual void SetMacTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set the MAC TX Middle to use.
virtual void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
virtual void SetProtectionManager(Ptr< WifiProtectionManager > protectionManager)
Set the Protection Manager to use.
Mac48Address GetBssid() const
Get the Basic Service Set Identification.
Ptr< StaWifiMac > m_staMac
STA MAC layer pointer (null if not a STA).
void DoDispose() override
Destructor implementation.
WifiTxParameters m_txParams
the TX parameters for the current frame
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
EventId m_navResetEvent
the event to reset the NAV after an RTS
const WifiTxTimer & GetWifiTxTimer() const
Get a const reference to the WifiTxTimer object.
virtual bool GetUpdateCwOnCtsTimeout() const
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
Object()
Caller graph was not generated because of its size.
Definition object.cc:93
virtual void DoDispose()
Destructor implementation.
Definition object.cc:430
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
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:95
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:408
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:341
@ US
microsecond
Definition nstime.h:108
@ MS
millisecond
Definition nstime.h:107
@ S
second
Definition nstime.h:106
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
Definition nstime.h:332
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
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.
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 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.
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.
void SetDuration(Time duration)
Set the Duration/ID field with the given duration (Time object).
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.
bool IsPsPoll() const
Return true if the header is a PS-POLL header.
uint8_t GetFragmentNumber() const
Return the fragment number of the header.
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:711
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1574
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1567
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.
This class is used to handle the timer that a station starts when transmitting a frame that solicits ...
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... > 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:690
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
Definition callback.h:734
#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:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:253
#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:454
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1324
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
@ 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:463
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Definition wifi-utils.cc:98
static constexpr uint16_t WIFI_MAC_FCS_LENGTH
The length in octets of the IEEE 802.11 MAC FCS field.
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
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
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:612
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
Definition wifi-utils.cc:51
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU).
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
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:84
double snr
SNR in linear scale.
Definition wifi-types.h:85
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.