A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
qos-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 "wifi-mac-queue.h"
13#include "wifi-mac-trailer.h"
14
15#include "ns3/abort.h"
16#include "ns3/log.h"
17
18#undef NS_LOG_APPEND_CONTEXT
19#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
20
21namespace ns3
22{
23
24NS_LOG_COMPONENT_DEFINE("QosFrameExchangeManager");
25
26NS_OBJECT_ENSURE_REGISTERED(QosFrameExchangeManager);
27
28TypeId
30{
31 static TypeId tid =
32 TypeId("ns3::QosFrameExchangeManager")
34 .AddConstructor<QosFrameExchangeManager>()
35 .SetGroupName("Wifi")
36 .AddAttribute("PifsRecovery",
37 "Perform a PIFS recovery as a response to transmission failure "
38 "within a TXOP",
39 BooleanValue(true),
42 .AddAttribute("SetQueueSize",
43 "Whether to set the Queue Size subfield of the QoS Control field "
44 "of QoS data frames sent by non-AP stations",
45 BooleanValue(false),
48 .AddAttribute("ProtectSingleExchange",
49 "Whether the Duration/ID field in frames establishing protection only "
50 "covers the immediate frame exchange instead of rest of the TXOP limit "
51 "when the latter is non-zero",
52 BooleanValue(false),
55 .AddAttribute(
56 "SingleExchangeProtectionSurplus",
57 "Additional time to protect beyond end of the immediate frame exchange in case of "
58 "non-zero TXOP limit when a single frame exchange is protected",
59 TimeValue(Time(0)),
62 return tid;
63}
64
66 : m_initialFrame(false)
67{
68 NS_LOG_FUNCTION(this);
69}
70
75
76void
85
86bool
88{
89 NS_LOG_FUNCTION(this);
91
92 WifiMacHeader cfEnd;
94 cfEnd.SetDsNotFrom();
95 cfEnd.SetDsNotTo();
96 cfEnd.SetNoRetry();
97 cfEnd.SetNoMoreFragments();
98 cfEnd.SetDuration(Seconds(0));
100 cfEnd.SetAddr2(m_self);
101
102 WifiTxVector cfEndTxVector =
103 GetWifiRemoteStationManager()->GetRtsTxVector(cfEnd.GetAddr1(), m_allowedWidth);
104
105 auto mpdu = Create<WifiMpdu>(Create<Packet>(), cfEnd);
106 auto txDuration =
107 WifiPhy::CalculateTxDuration(mpdu->GetSize(), cfEndTxVector, m_phy->GetPhyBand());
108
109 // Send the CF-End frame if the remaining TXNAV is long enough to transmit this frame
110 if (m_txNav > Simulator::Now() + txDuration)
111 {
112 NS_LOG_DEBUG("Send CF-End frame");
113 ForwardMpduDown(mpdu, cfEndTxVector);
114 Simulator::Schedule(txDuration,
116 this,
117 m_edca);
118 ResetTxNav();
119 return true;
120 }
121
123 m_edca = nullptr;
124 return false;
125}
126
127void
129{
130 NS_LOG_FUNCTION(this << forceCurrentCw);
133
134 // Release the channel if it has not been idle for the last PIFS interval
135 m_allowedWidth = std::min(
137 m_channelAccessManager->GetLargestIdlePrimaryChannel(m_phy->GetPifs(), Simulator::Now()));
138
139 if (m_allowedWidth == MHz_u{0})
140 {
141 // PIFS recovery failed, TXOP is terminated
143 if (!forceCurrentCw)
144 {
146 }
147 m_edca = nullptr;
148 }
149 else
150 {
151 // the txopDuration parameter is unused because we are not starting a new TXOP
153 }
154}
155
156void
158{
159 NS_LOG_FUNCTION(this);
162
163 NS_LOG_DEBUG("Cancel PIFS recovery being attempted by EDCAF " << m_edca);
166}
167
168bool
170{
171 NS_LOG_FUNCTION(this << edca << allowedWidth);
172
174 {
175 // Another AC (having AIFS=1 or lower, if the user changed the default settings)
176 // gained channel access while performing PIFS recovery. Abort PIFS recovery
178 }
179
180 // TODO This will become an assert once no Txop is installed on a QoS station
181 if (!edca->IsQosTxop())
182 {
183 m_edca = nullptr;
184 return FrameExchangeManager::StartTransmission(edca, allowedWidth);
185 }
186
187 m_allowedWidth = allowedWidth;
188 auto qosTxop = StaticCast<QosTxop>(edca);
189 return StartTransmission(qosTxop, qosTxop->GetTxopLimit(m_linkId));
190}
191
192bool
194{
195 NS_LOG_FUNCTION(this << edca << txopDuration);
196
198 {
199 // Another AC (having AIFS=1 or lower, if the user changed the default settings)
200 // gained channel access while performing PIFS recovery. Abort PIFS recovery
202 }
203
204 if (m_txTimer.IsRunning())
205 {
207 }
208 m_dcf = edca;
209 m_edca = edca;
210
211 // We check if this EDCAF invoked the backoff procedure (without terminating
212 // the TXOP) because the transmission of a non-initial frame of a TXOP failed
213 bool backingOff = (m_edcaBackingOff == m_edca);
214
215 if (backingOff)
216 {
221
222 // clear the member variable
223 m_edcaBackingOff = nullptr;
224 }
225
227 {
228 // TXOP limit is not null. We have to check if this EDCAF is starting a
229 // new TXOP. This includes the case when the transmission of a non-initial
230 // frame of a TXOP failed and backoff was invoked without terminating the
231 // TXOP. In such a case, we assume that a new TXOP is being started if it
232 // elapsed more than TXOPlimit since the start of the paused TXOP. Note
233 // that GetRemainingTxop returns 0 iff Now - TXOPstart >= TXOPlimit
235 (backingOff && m_edca->GetRemainingTxop(m_linkId).IsZero()))
236 {
237 // starting a new TXOP
238 m_edca->NotifyChannelAccessed(m_linkId, txopDuration);
239
240 if (StartFrameExchange(m_edca, txopDuration, true))
241 {
242 m_initialFrame = true;
243 return true;
244 }
245
246 // TXOP not even started, return false
247 NS_LOG_DEBUG("No frame transmitted");
249 m_edca = nullptr;
250 return false;
251 }
252
253 // We are continuing a TXOP, check if we can transmit another frame
255
257 {
258 NS_LOG_DEBUG("Not enough remaining TXOP time");
259 return SendCfEndIfNeeded();
260 }
261
262 return true;
263 }
264
265 // we get here if TXOP limit is null
266 m_initialFrame = true;
267
268 if (StartFrameExchange(m_edca, Time::Min(), true))
269 {
271 return true;
272 }
273
274 NS_LOG_DEBUG("No frame transmitted");
276 m_edca = nullptr;
277 return false;
278}
279
280bool
282 Time availableTime,
283 bool initialFrame)
284{
285 NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
286
287 Ptr<WifiMpdu> mpdu = edca->PeekNextMpdu(m_linkId);
288
289 // Even though channel access is requested when the queue is not empty, at
290 // the time channel access is granted the lifetime of the packet might be
291 // expired and the queue might be empty.
292 if (!mpdu)
293 {
294 NS_LOG_DEBUG("Queue empty");
295 return false;
296 }
297
298 mpdu = CreateAliasIfNeeded(mpdu);
299 WifiTxParameters txParams;
300 txParams.m_txVector =
301 GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
302
303 Ptr<WifiMpdu> item = edca->GetNextMpdu(m_linkId, mpdu, txParams, availableTime, initialFrame);
304
305 if (!item)
306 {
307 NS_LOG_DEBUG("Not enough time to transmit a frame");
308 return false;
309 }
310
311 NS_ASSERT_MSG(!item->GetHeader().IsQosData() || !item->GetHeader().IsQosAmsdu(),
312 "We should not get an A-MSDU here");
313
314 // check if the MSDU needs to be fragmented
315 item = GetFirstFragmentIfNeeded(item);
316
317 // update the protection method if the frame was fragmented
318 if (item->IsFragment() && item->GetSize() != mpdu->GetSize())
319 {
320 WifiTxParameters fragmentTxParams;
321 fragmentTxParams.m_txVector = txParams.m_txVector;
322 fragmentTxParams.AddMpdu(item);
323 UpdateTxDuration(item->GetHeader().GetAddr1(), fragmentTxParams);
324 txParams.m_protection = GetProtectionManager()->TryAddMpdu(item, fragmentTxParams);
325 NS_ASSERT(txParams.m_protection);
326 }
327
328 SendMpduWithProtection(item, txParams);
329
330 return true;
331}
332
335{
336 return mpdu;
337}
338
339bool
341 WifiTxParameters& txParams,
342 Time availableTime) const
343{
344 NS_ASSERT(mpdu);
345 NS_LOG_FUNCTION(this << *mpdu << &txParams << availableTime);
346
347 // tentatively add the given MPDU
348 auto prevTxDuration = txParams.m_txDuration;
349 txParams.AddMpdu(mpdu);
350 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
351
352 // check if adding the given MPDU requires a different protection method
353 std::optional<Time> protectionTime; // uninitialized
354 if (txParams.m_protection)
355 {
356 protectionTime = txParams.m_protection->protectionTime;
357 }
358
359 std::unique_ptr<WifiProtection> protection;
360 protection = GetProtectionManager()->TryAddMpdu(mpdu, txParams);
361 bool protectionSwapped = false;
362
363 if (protection)
364 {
365 // the protection method has changed, calculate the new protection time
366 CalculateProtectionTime(protection.get());
367 protectionTime = protection->protectionTime;
368 // swap unique pointers, so that the txParams that is passed to the next
369 // call to IsWithinLimitsIfAddMpdu is the most updated one
370 txParams.m_protection.swap(protection);
371 protectionSwapped = true;
372 }
373 NS_ASSERT(protectionTime.has_value());
374 NS_LOG_DEBUG("protection time=" << *protectionTime);
375
376 // check if adding the given MPDU requires a different acknowledgment method
377 std::optional<Time> acknowledgmentTime; // uninitialized
378 if (txParams.m_acknowledgment)
379 {
380 acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
381 }
382
383 std::unique_ptr<WifiAcknowledgment> acknowledgment;
384 acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
385 bool acknowledgmentSwapped = false;
386
387 if (acknowledgment)
388 {
389 // the acknowledgment method has changed, calculate the new acknowledgment time
390 CalculateAcknowledgmentTime(acknowledgment.get());
391 acknowledgmentTime = acknowledgment->acknowledgmentTime;
392 // swap unique pointers, so that the txParams that is passed to the next
393 // call to IsWithinLimitsIfAddMpdu is the most updated one
394 txParams.m_acknowledgment.swap(acknowledgment);
395 acknowledgmentSwapped = true;
396 }
397 NS_ASSERT(acknowledgmentTime.has_value());
398 NS_LOG_DEBUG("acknowledgment time=" << *acknowledgmentTime);
399
400 Time ppduDurationLimit = Time::Min();
401 if (availableTime != Time::Min())
402 {
403 ppduDurationLimit = availableTime - *protectionTime - *acknowledgmentTime;
404 }
405
406 if (!IsWithinLimitsIfAddMpdu(mpdu, txParams, ppduDurationLimit))
407 {
408 // adding MPDU failed, undo the addition of the MPDU and restore protection and
409 // acknowledgment methods if they were swapped
410 txParams.UndoAddMpdu();
411 txParams.m_txDuration = prevTxDuration;
412 if (protectionSwapped)
413 {
414 txParams.m_protection.swap(protection);
415 }
416 if (acknowledgmentSwapped)
417 {
418 txParams.m_acknowledgment.swap(acknowledgment);
419 }
420 return false;
421 }
422
423 return true;
424}
425
426bool
428 const WifiTxParameters& txParams,
429 Time ppduDurationLimit) const
430{
431 NS_ASSERT(mpdu);
432 NS_LOG_FUNCTION(this << *mpdu << &txParams << ppduDurationLimit);
433
434 // A QoS station only has to check that the MPDU transmission time does not
435 // exceed the given limit
436 return IsWithinSizeAndTimeLimits(mpdu->GetSize(),
437 mpdu->GetHeader().GetAddr1(),
438 txParams,
439 ppduDurationLimit);
440}
441
442bool
444 Mac48Address receiver,
445 const WifiTxParameters& txParams,
446 Time ppduDurationLimit) const
447{
448 NS_LOG_FUNCTION(this << ppduPayloadSize << receiver << &txParams << ppduDurationLimit);
449
450 if (ppduDurationLimit != Time::Min() && ppduDurationLimit.IsNegative())
451 {
452 NS_LOG_DEBUG("ppduDurationLimit is null or negative, time limit is trivially exceeded");
453 return false;
454 }
455
456 if (ppduPayloadSize > WifiPhy::GetMaxPsduSize(txParams.m_txVector.GetModulationClass()))
457 {
458 NS_LOG_DEBUG("the frame exceeds the max PSDU size");
459 return false;
460 }
461
462 // Get the maximum PPDU Duration based on the preamble type
463 Time maxPpduDuration = GetPpduMaxTime(txParams.m_txVector.GetPreambleType());
464
465 NS_ASSERT_MSG(txParams.m_txDuration, "TX duration not yet computed");
466 auto txTime = txParams.m_txDuration.value();
467 NS_LOG_DEBUG("PPDU duration: " << txTime.As(Time::MS));
468
469 if ((ppduDurationLimit.IsStrictlyPositive() && txTime > ppduDurationLimit) ||
470 (maxPpduDuration.IsStrictlyPositive() && txTime > maxPpduDuration))
471 {
473 "the frame does not meet the constraint on max PPDU duration or PPDU duration limit");
474 return false;
475 }
476
477 return true;
478}
479
480Time
482 uint32_t size,
483 const WifiTxParameters& txParams,
484 Ptr<Packet> fragmentedPacket) const
485{
486 NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
487
488 const auto singleDurationId =
489 FrameExchangeManager::GetFrameDurationId(header, size, txParams, fragmentedPacket);
490
491 // TODO This will be removed once no Txop is installed on a QoS station
492 if (!m_edca)
493 {
494 return singleDurationId;
495 }
496
498 {
499 return singleDurationId;
500 }
501
502 NS_ASSERT(txParams.m_acknowledgment &&
503 txParams.m_acknowledgment->acknowledgmentTime.has_value());
504
505 // under multiple protection settings, if the TXOP limit is not null, Duration/ID
506 // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
507 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
508 // of 802.11-2016)
509 auto duration =
510 std::max(m_edca->GetRemainingTxop(m_linkId) -
512 *txParams.m_acknowledgment->acknowledgmentTime);
513
515 {
516 duration = std::min(duration, singleDurationId + m_singleExchangeProtectionSurplus);
517 }
518
519 return duration;
520}
521
522Time
524 Time txDuration,
525 Time response) const
526{
527 NS_LOG_FUNCTION(this << rtsTxVector << txDuration << response);
528
529 const auto singleDurationId =
530 FrameExchangeManager::GetRtsDurationId(rtsTxVector, txDuration, response);
531
532 // TODO This will be removed once no Txop is installed on a QoS station
533 if (!m_edca)
534 {
535 return singleDurationId;
536 }
537
539 {
540 return singleDurationId;
541 }
542
543 // under multiple protection settings, if the TXOP limit is not null, Duration/ID
544 // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
545 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
546 // of 802.11-2016)
547 auto duration =
548 std::max(m_edca->GetRemainingTxop(m_linkId) -
550 Seconds(0));
551
553 {
554 duration = std::min(duration, singleDurationId + m_singleExchangeProtectionSurplus);
555 }
556
557 return duration;
558}
559
560Time
562 Time txDuration,
563 Time response) const
564{
565 NS_LOG_FUNCTION(this << ctsTxVector << txDuration << response);
566
567 const auto singleDurationId =
568 FrameExchangeManager::GetCtsToSelfDurationId(ctsTxVector, txDuration, response);
569
570 // TODO This will be removed once no Txop is installed on a QoS station
571 if (!m_edca)
572 {
573 return singleDurationId;
574 }
575
577 {
578 return singleDurationId;
579 }
580
581 // under multiple protection settings, if the TXOP limit is not null, Duration/ID
582 // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
583 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
584 // of 802.11-2016)
585 auto duration =
586 std::max(m_edca->GetRemainingTxop(m_linkId) -
588 Seconds(0));
589
591 {
592 duration = std::min(duration, singleDurationId + m_singleExchangeProtectionSurplus);
593 }
594
595 return duration;
596}
597
598void
600{
601 NS_LOG_FUNCTION(this << *mpdu << txVector);
602
603 WifiMacHeader& hdr = mpdu->GetHeader();
604
605 if (hdr.IsQosData() && m_mac->GetTypeOfStation() == STA &&
606 (m_setQosQueueSize || hdr.IsQosEosp()))
607 {
608 uint8_t tid = hdr.GetQosTid();
609 hdr.SetQosEosp();
610 hdr.SetQosQueueSize(
611 m_mac->GetQosTxop(tid)->GetQosQueueSize(tid,
612 mpdu->GetOriginal()->GetHeader().GetAddr1()));
613 }
615}
616
617void
619{
620 NS_LOG_DEBUG(this);
621
622 // TODO This will be removed once no Txop is installed on a QoS station
623 if (!m_edca)
624 {
626 return;
627 }
628
631 {
632 NS_LOG_DEBUG("Schedule another transmission in a SIFS");
635
636 // we are continuing a TXOP, hence the txopDuration parameter is unused
638
640 {
642 }
643 }
644 else
645 {
647 m_edca = nullptr;
648 }
649 m_initialFrame = false;
650 m_sentFrameTo.clear();
651}
652
653void
655{
656 NS_LOG_FUNCTION(this << forceCurrentCw);
657
658 // TODO This will be removed once no Txop is installed on a QoS station
659 if (!m_edca)
660 {
662 return;
663 }
664
665 if (m_initialFrame)
666 {
667 // The backoff procedure shall be invoked by an EDCAF when the transmission
668 // of an MPDU in the initial PPDU of a TXOP fails (Sec. 10.22.2.2 of 802.11-2016)
669 NS_LOG_DEBUG("TX of the initial frame of a TXOP failed: terminate TXOP");
670 if (!forceCurrentCw)
671 {
673 }
675 m_edca = nullptr;
676 }
677 else
678 {
679 // some STA(s) did not respond, they are no longer protected
680 for (const auto& address : m_txTimer.GetStasExpectedToRespond())
681 {
682 NS_LOG_DEBUG(address << " did not respond, hence it is no longer protected");
683 m_protectedStas.erase(address);
684 }
685
687 "Cannot transmit more than one frame if TXOP Limit is zero");
688
689 // A STA can perform a PIFS recovery or perform a backoff as a response to
690 // transmission failure within a TXOP. How it chooses between these two is
691 // implementation dependent. (Sec. 10.22.2.2 of 802.11-2016)
692 if (m_pifsRecovery)
693 {
694 // we can continue the TXOP if the carrier sense mechanism indicates that
695 // the medium is idle in a PIFS
696 NS_LOG_DEBUG("TX of a non-initial frame of a TXOP failed: perform PIFS recovery");
700 this,
701 forceCurrentCw);
702 }
703 else
704 {
705 // In order not to terminate (yet) the TXOP, we call the NotifyChannelReleased
706 // method of the Txop class, which only generates a new backoff value and
707 // requests channel access if needed,
708 NS_LOG_DEBUG("TX of a non-initial frame of a TXOP failed: invoke backoff");
709 m_edca->Txop::NotifyChannelReleased(m_linkId);
710 // CW and QSRC shall be updated in this case (see Section 10.23.2.2 of 802.11-2020)
711 if (!forceCurrentCw)
712 {
714 }
716 m_edca = nullptr;
717 }
718 }
719 m_initialFrame = false;
720 m_sentFrameTo.clear();
721 // reset TXNAV because transmission failed
722 ResetTxNav();
723}
724
725void
727 const WifiTxVector& txVector,
728 Time psduDuration)
729{
730 NS_LOG_FUNCTION(this << macHdr << txVector << psduDuration.As(Time::MS));
731 FrameExchangeManager::ReceivedMacHdr(macHdr, txVector, psduDuration);
732 SetTxopHolder(macHdr, txVector);
733}
734
735void
737{
738 NS_LOG_FUNCTION(this << psdu << txVector);
739
740 // APs store buffer size report of associated stations
741 if (m_mac->GetTypeOfStation() == AP && psdu->GetAddr1() == m_self)
742 {
743 for (const auto& mpdu : *PeekPointer(psdu))
744 {
745 const WifiMacHeader& hdr = mpdu->GetHeader();
746
747 if (hdr.IsQosData() && hdr.IsQosEosp())
748 {
749 NS_LOG_DEBUG("Station " << hdr.GetAddr2() << " reported a buffer status of "
750 << +hdr.GetQosQueueSize()
751 << " for tid=" << +hdr.GetQosTid());
752 m_apMac->SetBufferStatus(hdr.GetQosTid(),
753 mpdu->GetOriginal()->GetHeader().GetAddr2(),
754 hdr.GetQosQueueSize());
755 }
756 }
757 }
758
759 // before updating the NAV, check if the NAV counted down to zero. In such a
760 // case, clear the saved TXOP holder address.
762
764}
765
766void
768{
769 NS_LOG_FUNCTION(this << psdu << txVector);
770
771 SetTxopHolder(psdu->GetHeader(0), txVector);
773}
774
775void
777{
778 NS_LOG_FUNCTION(this << hdr << txVector);
779 if (auto txopHolder = FindTxopHolder(hdr, txVector))
780 {
781 m_txopHolder = *txopHolder;
782 }
783}
784
785std::optional<Mac48Address>
790
791std::optional<Mac48Address>
793{
794 NS_LOG_FUNCTION(this << hdr << txVector);
795
796 // A STA shall save the TXOP holder address for the BSS in which it is associated.
797 // The TXOP holder address is the MAC address from the Address 2 field of the frame
798 // that initiated a frame exchange sequence, except if this is a CTS frame, in which
799 // case the TXOP holder address is the Address 1 field. (Sec. 10.23.2.4 of 802.11-2020)
800 if ((hdr.IsQosData() || hdr.IsMgt() || hdr.IsRts() || hdr.IsBlockAckReq()) &&
801 (hdr.GetAddr1() == m_bssid || hdr.GetAddr2() == m_bssid))
802 {
803 return hdr.GetAddr2();
804 }
805 if (hdr.IsCts() && hdr.GetAddr1() == m_bssid)
806 {
807 return hdr.GetAddr1();
808 }
809 return std::nullopt;
810}
811
812void
821
822void
824 const WifiTxVector& txVector,
825 const Time& surplus)
826{
827 NS_LOG_FUNCTION(this << hdr << txVector << surplus.As(Time::US));
828 if (hdr.IsCfEnd())
829 {
830 NS_LOG_DEBUG("Received CF-End, resetting NAV");
832 return;
833 }
834
835 FrameExchangeManager::UpdateNav(hdr, txVector, surplus);
836}
837
838void
845
846void
848 RxSignalInfo rxSignalInfo,
849 const WifiTxVector& txVector,
850 bool inAmpdu)
851{
852 NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
853
854 // The received MPDU is either broadcast or addressed to this station
855 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
856
857 double rxSnr = rxSignalInfo.snr;
858 const WifiMacHeader& hdr = mpdu->GetHeader();
859
860 if (hdr.IsRts())
861 {
862 NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
863
864 // If a non-VHT STA receives an RTS frame with the RA address matching the
865 // MAC address of the STA and the MAC address in the TA field in the RTS
866 // frame matches the saved TXOP holder address, then the STA shall send the
867 // CTS frame after SIFS, without regard for, and without resetting, its NAV.
868 // (sec. 10.22.2.4 of 802.11-2016)
869 if (hdr.GetAddr2() == m_txopHolder || VirtualCsMediumIdle())
870 {
871 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
874 this,
875 hdr,
876 txVector,
877 rxSnr);
878 }
879 else
880 {
881 NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
882 }
883 return;
884 }
885
886 if (hdr.IsQosData())
887 {
889 {
890 NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
891 << ", schedule ACK");
894 this,
895 hdr,
896 txVector,
897 rxSnr);
898 }
899
900 // Forward up the frame
901 m_rxMiddle->Receive(mpdu, m_linkId);
902
903 // the received data frame has been processed
904 return;
905 }
906
907 return FrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
908}
909
910} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
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
FrameExchangeManager is a base class handling the basic frame exchange sequences for non-QoS stations...
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
bool m_protectedIfResponded
whether a STA is assumed to be protected if replied to a frame requiring acknowledgment
void SendMpduWithProtection(Ptr< WifiMpdu > mpdu, WifiTxParameters &txParams)
Send an MPDU with the given TX parameters (with the specified protection).
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.
void SendNormalAck(const WifiMacHeader &hdr, const WifiTxVector &dataTxVector, double dataSnr)
Send Normal Ack.
Mac48Address m_self
the MAC address of this device
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 ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector)
Forward an MPDU down to the PHY layer.
virtual bool VirtualCsMediumIdle() const
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
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.
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 NavResetTimeout()
Reset the NAV upon expiration of the NAV reset timer.
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
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.
std::set< Mac48Address > m_sentFrameTo
the STA(s) to which we sent a frame requesting a response
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...
Ptr< ApWifiMac > m_apMac
AP MAC layer pointer (null if not an AP)
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual void TransmissionFailed(bool forceCurrentCw=false)
Take necessary actions upon a transmission failure.
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...
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
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 bool StartTransmission(Ptr< Txop > dcf, MHz_u allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
MHz_u m_allowedWidth
the allowed width for the current transmission
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.
void DoDispose() override
Destructor implementation.
an EUI-48 address
static Mac48Address GetBroadcast()
Smart pointer class similar to boost::intrusive_ptr.
QosFrameExchangeManager handles the frame exchange sequences for QoS stations.
EventId m_pifsRecoveryEvent
event associated with an attempt of PIFS recovery
void ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
virtual void ClearTxopHolderIfNeeded()
Clear the TXOP holder if the NAV counted down to zero (includes the case of NAV reset).
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void ReceivedMacHdr(const WifiMacHeader &macHdr, const WifiTxVector &txVector, Time psduDuration) override
Store information about the MAC header of the MPDU being received.
virtual bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame)
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
Time GetFrameDurationId(const WifiMacHeader &header, uint32_t size, const WifiTxParameters &txParams, Ptr< Packet > fragmentedPacket) const override
Compute how to set the Duration/ID field of a frame being transmitted with the given TX parameters.
Time GetCtsToSelfDurationId(const WifiTxVector &ctsTxVector, Time txDuration, Time response) const override
Compute how to set the Duration/ID field of a CTS-to-self frame to send to protect a frame transmitte...
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
virtual bool IsWithinLimitsIfAddMpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check whether the given MPDU can be added to the frame being built (as described by the given TX para...
void PifsRecovery(bool forceCurrentCw)
Perform a PIFS recovery as a response to transmission failure within a TXOP.
std::optional< Mac48Address > m_txopHolder
MAC address of the TXOP holder.
void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
void TransmissionFailed(bool forceCurrentCw=false) override
Take necessary actions upon a transmission failure.
Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const override
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual std::optional< Mac48Address > FindTxopHolder(const WifiMacHeader &hdr, const WifiTxVector &txVector)
Determine the holder of the TXOP, if possible, based on the received frame.
virtual bool SendCfEndIfNeeded()
Send a CF-End frame to indicate the completion of the TXOP, provided that the remaining duration is l...
bool m_initialFrame
true if transmitting the initial frame of a TXOP
virtual Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
std::optional< Mac48Address > GetTxopHolder() const
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
static TypeId GetTypeId()
Get the type ID.
bool m_pifsRecovery
true if performing a PIFS recovery after failure
Ptr< Txop > m_edcaBackingOff
channel access function that invoked backoff during TXOP
void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
bool m_setQosQueueSize
whether to set the Queue Size subfield of the QoS Control field of QoS data frames
virtual bool IsWithinSizeAndTimeLimits(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check whether the transmission time of the frame being built (as described by the given TX parameters...
Time m_singleExchangeProtectionSurplus
additional time to protect beyond end of the immediate frame exchange in case of non-zero TXOP limit ...
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
void UpdateNav(const WifiMacHeader &hdr, const WifiTxVector &txVector, const Time &surplus=Time{0}) override
Update the NAV, if needed, based on the Duration/ID of the given MAC header and the given surplus.
void CancelPifsRecovery()
Cancel the PIFS recovery event and have the EDCAF attempting PIFS recovery release the channel.
bool TryAddMpdu(Ptr< const WifiMpdu > mpdu, WifiTxParameters &txParams, Time availableTime) const
Recompute the protection and acknowledgment methods to use if the given MPDU is added to the frame be...
bool StartTransmission(Ptr< Txop > edca, MHz_u allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
bool m_protectSingleExchange
true if the Duration/ID field in frames establishing protection only covers the immediate frame excha...
void DoDispose() override
Destructor implementation.
void SetTxopHolder(const WifiMacHeader &hdr, const WifiTxVector &txVector)
Set the TXOP holder, if needed, based on the received frame.
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition qos-txop.cc:665
virtual std::optional< Time > GetTxopStartTime(uint8_t linkId) const
Definition qos-txop.cc:620
void NotifyChannelAccessed(uint8_t linkId, Time txopDuration) override
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
Definition qos-txop.cc:609
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:403
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:340
bool IsNegative() const
Exactly equivalent to t <= 0.
Definition nstime.h:313
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:276
@ US
microsecond
Definition nstime.h:107
@ MS
millisecond
Definition nstime.h:106
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Time.
Definition nstime.h:1432
Time GetTxopLimit() const
Return the TXOP limit.
Definition txop.cc:609
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:385
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
bool IsBlockAckReq() const
Return true if the header is a BlockAckRequest header.
bool IsCts() const
Return true if the header is a CTS header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
void SetNoMoreFragments()
Un-set the More Fragment bit in the Frame Control Field.
bool IsMgt() const
Return true if the Type is Management.
bool IsCfEnd() const
Return true if the header is a CF-End header.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsQosEosp() const
Return if IsQosData() is true and the end of service period (EOSP) is set.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetQosQueueSize(uint8_t size)
Set the Queue Size subfield in the QoS control field.
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.
QosAckPolicy GetQosAckPolicy() const
Return the QoS Ack policy in the QoS control 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 IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetQosEosp()
Set the end of service period (EOSP) bit in the QoS control field.
uint8_t GetQosQueueSize() const
Get the Queue Size subfield in the QoS control field.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
void SetNoRetry()
Un-set the Retry bit in the Frame Control field.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition wifi-phy.cc:837
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
static uint32_t GetMaxPsduSize(WifiModulationClass modulation)
Get the maximum PSDU size in bytes for the given modulation class.
Definition wifi-phy.cc:1592
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1057
Time GetPifs() const
Return the PCF Interframe Space (PIFS) for this PHY.
Definition wifi-phy.cc:861
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
void UndoAddMpdu()
Undo the addition of the last MPDU added by calling AddMpdu().
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.
bool IsRunning() const
Return true if the timer is running.
void Cancel()
Cancel the timer.
const std::set< Mac48Address > & GetStasExpectedToRespond() const
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiPreamble GetPreambleType() const
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
#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
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
#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 Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
@ STA
Definition wifi-mac.h:59
@ AP
Definition wifi-mac.h:60
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetPpduMaxTime(WifiPreamble preamble)
Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for the PHY layers defining the aPPD...
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Definition wifi-utils.cc:98
@ WIFI_MAC_CTL_END
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:78
double snr
SNR in linear scale.
Definition wifi-types.h:79