A Discrete-Event Network Simulator
API
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  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Stefano Avallone <stavallo@unina.it>
18  */
19 
20 #include "frame-exchange-manager.h"
21 
22 #include "snr-tag.h"
23 #include "sta-wifi-mac.h"
24 #include "wifi-mac-queue.h"
25 #include "wifi-mac-trailer.h"
26 #include "wifi-utils.h"
27 
28 #include "ns3/abort.h"
29 #include "ns3/log.h"
30 
31 #undef NS_LOG_APPEND_CONTEXT
32 #define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
33 
34 // Time (in nanoseconds) to be added to the PSDU duration to yield the duration
35 // of the timer that is started when the PHY indicates the start of the reception
36 // of a frame and we are waiting for a response.
37 #define PSDU_DURATION_SAFEGUARD 400
38 
39 namespace ns3
40 {
41 
42 NS_LOG_COMPONENT_DEFINE("FrameExchangeManager");
43 
44 NS_OBJECT_ENSURE_REGISTERED(FrameExchangeManager);
45 
46 TypeId
48 {
49  static TypeId tid = TypeId("ns3::FrameExchangeManager")
50  .SetParent<Object>()
51  .AddConstructor<FrameExchangeManager>()
52  .SetGroupName("Wifi");
53  return tid;
54 }
55 
57  : m_navEnd(Seconds(0)),
58  m_linkId(0),
59  m_allowedWidth(0),
60  m_promisc(false),
61  m_moreFragments(false)
62 {
63  NS_LOG_FUNCTION(this);
64 }
65 
67 {
69 }
70 
71 void
73 {
74  NS_LOG_FUNCTION(this);
75  m_txTimer.Cancel();
77  {
79  }
81  m_mpdu = nullptr;
82  m_txParams.Clear();
83  m_dcf = nullptr;
84 }
85 
86 void
88 {
89  NS_LOG_FUNCTION(this);
90  Reset();
91  m_fragmentedPacket = nullptr;
92  m_mac = nullptr;
93  m_txMiddle = nullptr;
94  m_rxMiddle = nullptr;
95  m_channelAccessManager = nullptr;
96  m_protectionManager = nullptr;
97  m_ackManager = nullptr;
98  ResetPhy();
100 }
101 
102 void
104 {
105  NS_LOG_FUNCTION(this << protectionManager);
106  m_protectionManager = protectionManager;
107 }
108 
111 {
112  return m_protectionManager;
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION(this << ackManager);
119  m_ackManager = ackManager;
120 }
121 
124 {
125  return m_ackManager;
126 }
127 
128 void
130 {
131  NS_LOG_FUNCTION(this << +linkId);
132  m_linkId = linkId;
133 }
134 
135 void
137 {
138  NS_LOG_FUNCTION(this << mac);
139  m_mac = mac;
140 }
141 
142 void
144 {
145  NS_LOG_FUNCTION(this << txMiddle);
146  m_txMiddle = txMiddle;
147 }
148 
149 void
151 {
152  NS_LOG_FUNCTION(this << rxMiddle);
153  m_rxMiddle = rxMiddle;
154 }
155 
156 void
158 {
159  NS_LOG_FUNCTION(this << channelAccessManager);
160  m_channelAccessManager = channelAccessManager;
161 }
162 
165 {
167 }
168 
169 void
171 {
172  NS_LOG_FUNCTION(this << phy);
173  m_phy = phy;
174  m_phy->TraceConnectWithoutContext("PhyRxPayloadBegin",
177 }
178 
179 void
181 {
182  NS_LOG_FUNCTION(this);
183  if (m_phy)
184  {
186  "PhyRxPayloadBegin",
188  if (m_phy->GetState())
189  {
192  RxSignalInfo,
193  WifiTxVector,
194  std::vector<bool>>());
195  }
196  m_phy = nullptr;
197  }
198 }
199 
200 void
202 {
203  NS_LOG_FUNCTION(this << address);
204  // For APs, the BSSID is the MAC address. For STAs, the BSSID will be overwritten
205  // when receiving Beacon frames or Probe Response frames
206  SetBssid(address);
207  m_self = address;
208 }
209 
212 {
213  return m_self;
214 }
215 
216 void
218 {
219  NS_LOG_FUNCTION(this << bssid);
220  m_bssid = bssid;
221 }
222 
225 {
226  return m_bssid;
227 }
228 
229 void
231 {
232  NS_LOG_FUNCTION(this << &callback);
233  m_droppedMpduCallback = callback;
234 }
235 
236 void
238 {
239  NS_LOG_FUNCTION(this << &callback);
240  m_ackedMpduCallback = callback;
241 }
242 
243 void
245 {
246  m_promisc = true;
247 }
248 
249 bool
251 {
252  return m_promisc;
253 }
254 
255 const WifiTxTimer&
257 {
258  return m_txTimer;
259 }
260 
261 void
263 {
265  {
267  }
268 }
269 
270 void
272 {
273  NS_LOG_FUNCTION(this << "PSDU reception started for " << psduDuration.As(Time::US)
274  << " (txVector: " << txVector << ")");
275 
277  "The TX timer and the NAV reset event cannot be both running");
278 
279  // No need to reschedule timeouts if PSDU duration is null. In this case,
280  // PHY-RXEND immediately follows PHY-RXSTART (e.g. when PPDU has been filtered)
281  // and CCA will take over
282  if (m_txTimer.IsRunning() && psduDuration.IsStrictlyPositive())
283  {
284  // we are waiting for a response and something arrived
285  NS_LOG_DEBUG("Rescheduling timeout event");
287  // PHY has switched to RX, so we can reset the ack timeout
289  }
290 
292  {
294  }
295 }
296 
297 bool
299 {
300  NS_LOG_FUNCTION(this << dcf << allowedWidth);
301 
302  NS_ASSERT(!m_mpdu);
303  if (m_txTimer.IsRunning())
304  {
305  m_txTimer.Cancel();
306  }
307  m_dcf = dcf;
308  m_allowedWidth = allowedWidth;
309 
310  Ptr<WifiMacQueue> queue = dcf->GetWifiMacQueue();
311 
312  // Even though channel access is requested when the queue is not empty, at
313  // the time channel access is granted the lifetime of the packet might be
314  // expired and the queue might be empty.
315  queue->WipeAllExpiredMpdus();
316 
317  Ptr<WifiMpdu> mpdu = queue->Peek(m_linkId);
318 
319  if (!mpdu)
320  {
321  NS_LOG_DEBUG("Queue empty");
323  m_dcf = nullptr;
324  return false;
325  }
326 
328 
329  NS_ASSERT(mpdu->GetHeader().IsData() || mpdu->GetHeader().IsMgt());
330 
331  // assign a sequence number if this is not a fragment nor a retransmission
332  if (!mpdu->IsFragment() && !mpdu->GetHeader().IsRetry())
333  {
334  uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
335  mpdu->AssignSeqNo(sequence);
336  }
337 
338  NS_LOG_DEBUG("MPDU payload size=" << mpdu->GetPacketSize()
339  << ", to=" << mpdu->GetHeader().GetAddr1()
340  << ", seq=" << mpdu->GetHeader().GetSequenceControl());
341 
342  // check if the MSDU needs to be fragmented
343  mpdu = GetFirstFragmentIfNeeded(mpdu);
344 
347  WifiTxParameters txParams;
348  txParams.m_txVector =
349  GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
350  txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
351  txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
352  txParams.AddMpdu(mpdu);
353  UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
354 
355  SendMpduWithProtection(mpdu, txParams);
356 
357  return true;
358 }
359 
362 {
363  NS_LOG_FUNCTION(this << *mpdu);
364 
365  if (mpdu->IsFragment())
366  {
367  // a fragment cannot be further fragmented
369  }
370  else if (GetWifiRemoteStationManager()->NeedFragmentation(mpdu))
371  {
372  NS_LOG_DEBUG("Fragmenting the MSDU");
373  m_fragmentedPacket = mpdu->GetPacket()->Copy();
374  // create the first fragment
376  0,
377  GetWifiRemoteStationManager()->GetFragmentSize(mpdu, 0));
378  // enqueue the first fragment
379  Ptr<WifiMpdu> item = Create<WifiMpdu>(fragment, mpdu->GetHeader());
380  item->GetHeader().SetMoreFragments();
381  m_mac->GetTxopQueue(mpdu->GetQueueAc())->Replace(mpdu, item);
382  return item;
383  }
384  return mpdu;
385 }
386 
387 void
389 {
390  NS_LOG_FUNCTION(this << *mpdu << &txParams);
391 
392  m_mpdu = mpdu;
393  m_txParams = std::move(txParams);
394 
395  // If protection is required, the MPDU must be stored in some queue because
396  // it is not put back in a queue if the RTS/CTS exchange fails
398  m_mpdu->GetHeader().IsCtl() || m_mpdu->IsQueued());
399 
400  // Make sure that the acknowledgment time has been computed, so that SendRts()
401  // and SendCtsToSelf() can reuse this value.
403 
404  if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
405  {
407  }
408 
409  // Set QoS Ack policy if this is a QoS data frame
411 
412  if (m_mpdu->IsQueued())
413  {
414  m_mpdu->SetInFlight(m_linkId);
415  }
416 
418 }
419 
420 void
422 {
423  NS_LOG_FUNCTION(this << &txParams);
424 
425  switch (txParams.m_protection->method)
426  {
428  SendRts(txParams);
429  break;
431  SendCtsToSelf(txParams);
432  break;
435  break;
436  default:
437  NS_ABORT_MSG("Unknown protection type: " << txParams.m_protection.get());
438  }
439 }
440 
441 void
443 {
444  NS_LOG_FUNCTION(this);
446  m_sentRtsTo.clear();
447  NS_ASSERT(m_mpdu);
448  SendMpdu();
449 }
450 
451 const std::set<Mac48Address>&
453 {
454  return m_protectedStas;
455 }
456 
457 void
459 {
460  NS_LOG_FUNCTION(this);
461 
464  m_phy->GetPhyBand());
465 
467 
469  {
470  if (!m_mpdu->GetHeader().IsQosData() ||
471  m_mpdu->GetHeader().GetQosAckPolicy() == WifiMacHeader::NO_ACK)
472  {
473  // No acknowledgment, hence dequeue the MPDU if it is stored in a queue
475  }
476 
477  Simulator::Schedule(txDuration, [=, this]() {
479  m_mpdu = nullptr;
480  });
481  }
483  {
484  m_mpdu->GetHeader().SetDuration(
485  GetFrameDurationId(m_mpdu->GetHeader(),
487  m_txParams,
489 
490  // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
491  // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
492  // aRxPHYStartDelay equals the time to transmit the PHY header.
493  auto normalAcknowledgment = static_cast<WifiNormalAck*>(m_txParams.m_acknowledgment.get());
494 
495  Time timeout =
496  txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
497  m_phy->CalculatePhyPreambleAndHeaderDuration(normalAcknowledgment->ackTxVector);
500  timeout,
501  {m_mpdu->GetHeader().GetAddr1()},
503  this,
504  m_mpdu,
507  }
508  else
509  {
510  NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
511  << m_txParams.m_acknowledgment.get() << ")");
512  }
513 
514  // transmit the MPDU
516 }
517 
518 void
520 {
521  NS_LOG_FUNCTION(this << *mpdu << txVector);
522 
523  auto psdu = Create<WifiPsdu>(mpdu, false);
524  FinalizeMacHeader(psdu);
526  m_phy->Send(psdu, txVector);
527 }
528 
529 void
531 {
532  NS_LOG_FUNCTION(this << psdu);
533 
534  if (m_mac->GetTypeOfStation() != STA)
535  {
536  return;
537  }
538 
539  auto pmMode = StaticCast<StaWifiMac>(m_mac)->GetPmMode(m_linkId);
540 
541  for (const auto& mpdu : *PeekPointer(psdu))
542  {
543  switch (pmMode)
544  {
545  case WIFI_PM_ACTIVE:
547  mpdu->GetHeader().SetNoPowerManagement();
548  break;
549  case WIFI_PM_POWERSAVE:
551  mpdu->GetHeader().SetPowerManagement();
552  break;
553  default:
554  NS_ABORT_MSG("Unknown PM mode: " << +pmMode);
555  }
556  }
557 }
558 
559 void
561 {
562  NS_LOG_DEBUG(this << *mpdu);
563 
564  if (mpdu->IsQueued())
565  {
566  m_mac->GetTxopQueue(mpdu->GetQueueAc())->DequeueIfQueued({mpdu});
567  }
568 }
569 
570 uint32_t
572 {
573  return mpdu->GetSize();
574 }
575 
576 void
578 {
579  NS_LOG_FUNCTION(this << protection);
580  NS_ASSERT(protection);
581 
582  if (protection->method == WifiProtection::NONE)
583  {
584  protection->protectionTime = Seconds(0);
585  }
586  else if (protection->method == WifiProtection::RTS_CTS)
587  {
588  auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(protection);
589  rtsCtsProtection->protectionTime = m_phy->CalculateTxDuration(GetRtsSize(),
590  rtsCtsProtection->rtsTxVector,
591  m_phy->GetPhyBand()) +
593  rtsCtsProtection->ctsTxVector,
594  m_phy->GetPhyBand()) +
595  2 * m_phy->GetSifs();
596  }
597  else if (protection->method == WifiProtection::CTS_TO_SELF)
598  {
599  auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(protection);
600  ctsToSelfProtection->protectionTime =
602  ctsToSelfProtection->ctsTxVector,
603  m_phy->GetPhyBand()) +
604  m_phy->GetSifs();
605  }
606 }
607 
608 void
610 {
611  NS_LOG_FUNCTION(this << acknowledgment);
612  NS_ASSERT(acknowledgment);
613 
614  if (acknowledgment->method == WifiAcknowledgment::NONE)
615  {
616  acknowledgment->acknowledgmentTime = Seconds(0);
617  }
618  else if (acknowledgment->method == WifiAcknowledgment::NORMAL_ACK)
619  {
620  auto normalAcknowledgment = static_cast<WifiNormalAck*>(acknowledgment);
621  normalAcknowledgment->acknowledgmentTime =
623  normalAcknowledgment->ackTxVector,
624  m_phy->GetPhyBand());
625  }
626 }
627 
628 Time
629 FrameExchangeManager::GetTxDuration(uint32_t ppduPayloadSize,
630  Mac48Address receiver,
631  const WifiTxParameters& txParams) const
632 {
633  return m_phy->CalculateTxDuration(ppduPayloadSize, txParams.m_txVector, m_phy->GetPhyBand());
634 }
635 
636 void
638 {
639  txParams.m_txDuration = GetTxDuration(txParams.GetSize(receiver), receiver, txParams);
640 }
641 
642 Time
644  uint32_t size,
645  const WifiTxParameters& txParams,
646  Ptr<Packet> fragmentedPacket) const
647 {
648  NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
649 
650  NS_ASSERT(txParams.m_acknowledgment &&
651  txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
652  Time durationId = txParams.m_acknowledgment->acknowledgmentTime;
653 
654  // if the current frame is a fragment followed by another fragment, we have to
655  // update the Duration/ID to cover the next fragment and the corresponding Ack
656  if (header.IsMoreFragments())
657  {
658  uint32_t payloadSize = size - header.GetSize() - WIFI_MAC_FCS_LENGTH;
659  uint32_t nextFragmentOffset = (header.GetFragmentNumber() + 1) * payloadSize;
660  uint32_t nextFragmentSize =
661  std::min(fragmentedPacket->GetSize() - nextFragmentOffset, payloadSize);
662  WifiTxVector ackTxVector =
663  GetWifiRemoteStationManager()->GetAckTxVector(header.GetAddr1(), txParams.m_txVector);
664 
665  durationId +=
666  2 * m_phy->GetSifs() +
667  m_phy->CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand()) +
668  m_phy->CalculateTxDuration(nextFragmentSize, txParams.m_txVector, m_phy->GetPhyBand());
669  }
670  return durationId;
671 }
672 
673 Time
675  Time txDuration,
676  Time response) const
677 {
678  NS_LOG_FUNCTION(this << rtsTxVector << txDuration << response);
679 
680  WifiTxVector ctsTxVector;
681  ctsTxVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_self, rtsTxVector.GetMode());
682 
683  return m_phy->GetSifs() +
684  m_phy->CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) /* CTS */
685  + m_phy->GetSifs() + txDuration + response;
686 }
687 
688 void
690 {
691  NS_LOG_FUNCTION(this << &txParams);
692 
693  NS_ASSERT(txParams.GetPsduInfoMap().size() == 1);
694  Mac48Address receiver = txParams.GetPsduInfoMap().begin()->first;
695 
696  WifiMacHeader rts;
698  rts.SetDsNotFrom();
699  rts.SetDsNotTo();
700  rts.SetNoRetry();
701  rts.SetNoMoreFragments();
702  rts.SetAddr1(receiver);
703  rts.SetAddr2(m_self);
704 
705  NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
706  auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
707 
708  NS_ASSERT(txParams.m_txDuration != Time::Min());
709  rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
710  txParams.m_txDuration,
711  txParams.m_acknowledgment->acknowledgmentTime));
712  Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(Create<Packet>(), rts);
713 
714  // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with
715  // a value of aSIFSTime + aSlotTime + aRxPHYStartDelay (IEEE 802.11-2016 sec. 10.3.2.7).
716  // aRxPHYStartDelay equals the time to transmit the PHY header.
718  rtsCtsProtection->rtsTxVector,
719  m_phy->GetPhyBand()) +
720  m_phy->GetSifs() + m_phy->GetSlot() +
721  m_phy->CalculatePhyPreambleAndHeaderDuration(rtsCtsProtection->ctsTxVector);
724  timeout,
725  {receiver},
727  this,
728  mpdu,
729  rtsCtsProtection->rtsTxVector);
731  NS_ASSERT(m_sentRtsTo.empty());
732  m_sentRtsTo = {receiver};
733 
734  ForwardMpduDown(mpdu, rtsCtsProtection->rtsTxVector);
735 }
736 
737 void
739  WifiTxVector& ctsTxVector,
740  double rtsSnr)
741 {
742  NS_LOG_FUNCTION(this << rtsHdr << ctsTxVector << rtsSnr);
743 
744  WifiMacHeader cts;
746  cts.SetDsNotFrom();
747  cts.SetDsNotTo();
748  cts.SetNoMoreFragments();
749  cts.SetNoRetry();
750  cts.SetAddr1(rtsHdr.GetAddr2());
751  Time duration = rtsHdr.GetDuration() - m_phy->GetSifs() -
752  m_phy->CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand());
753  // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
754  if (duration.IsStrictlyNegative())
755  {
756  duration = Seconds(0);
757  }
758  cts.SetDuration(duration);
759 
760  Ptr<Packet> packet = Create<Packet>();
761 
762  SnrTag tag;
763  tag.Set(rtsSnr);
764  packet->AddPacketTag(tag);
765 
766  // CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
767  ForwardMpduDown(Create<WifiMpdu>(packet, cts), ctsTxVector);
768 }
769 
770 void
772  WifiMode rtsTxMode,
773  double rtsSnr)
774 {
775  NS_LOG_FUNCTION(this << rtsHdr << rtsTxMode << rtsSnr);
776 
777  WifiTxVector ctsTxVector =
778  GetWifiRemoteStationManager()->GetCtsTxVector(rtsHdr.GetAddr2(), rtsTxMode);
779  DoSendCtsAfterRts(rtsHdr, ctsTxVector, rtsSnr);
780 }
781 
782 Time
784  Time txDuration,
785  Time response) const
786 {
787  NS_LOG_FUNCTION(this << ctsTxVector << txDuration << response);
788 
789  return m_phy->GetSifs() + txDuration + response;
790 }
791 
792 void
794 {
795  NS_LOG_FUNCTION(this << &txParams);
796 
797  WifiMacHeader cts;
799  cts.SetDsNotFrom();
800  cts.SetDsNotTo();
801  cts.SetNoMoreFragments();
802  cts.SetNoRetry();
803  cts.SetAddr1(m_self);
804 
805  NS_ASSERT(txParams.m_protection &&
806  txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
807  auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
808 
809  NS_ASSERT(txParams.m_txDuration != Time::Min());
810  cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
811  txParams.m_txDuration,
812  txParams.m_acknowledgment->acknowledgmentTime));
813 
814  ForwardMpduDown(Create<WifiMpdu>(Create<Packet>(), cts), ctsToSelfProtection->ctsTxVector);
815 
816  Time ctsDuration = m_phy->CalculateTxDuration(GetCtsSize(),
817  ctsToSelfProtection->ctsTxVector,
818  m_phy->GetPhyBand());
819  Simulator::Schedule(ctsDuration + m_phy->GetSifs(),
821  this);
822 }
823 
824 void
826  const WifiTxVector& dataTxVector,
827  double dataSnr)
828 {
829  NS_LOG_FUNCTION(this << hdr << dataTxVector << dataSnr);
830 
831  WifiTxVector ackTxVector =
832  GetWifiRemoteStationManager()->GetAckTxVector(hdr.GetAddr2(), dataTxVector);
833  WifiMacHeader ack;
835  ack.SetDsNotFrom();
836  ack.SetDsNotTo();
837  ack.SetNoRetry();
838  ack.SetNoMoreFragments();
839  ack.SetAddr1(hdr.GetAddr2());
840  // 802.11-2016, Section 9.2.5.7: Duration/ID is received duration value
841  // minus the time to transmit the Ack frame and its SIFS interval
842  Time duration = hdr.GetDuration() - m_phy->GetSifs() -
843  m_phy->CalculateTxDuration(GetAckSize(), ackTxVector, m_phy->GetPhyBand());
844  // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
845  if (duration.IsStrictlyNegative())
846  {
847  duration = Seconds(0);
848  }
849  ack.SetDuration(duration);
850 
851  Ptr<Packet> packet = Create<Packet>();
852 
853  SnrTag tag;
854  tag.Set(dataSnr);
855  packet->AddPacketTag(tag);
856 
857  ForwardMpduDown(Create<WifiMpdu>(packet, ack), ackTxVector);
858 }
859 
862 {
863  NS_LOG_FUNCTION(this);
864  NS_ASSERT(m_mpdu->GetHeader().IsMoreFragments());
865 
866  WifiMacHeader& hdr = m_mpdu->GetHeader();
867  hdr.SetFragmentNumber(hdr.GetFragmentNumber() + 1);
868 
869  uint32_t startOffset = hdr.GetFragmentNumber() * m_mpdu->GetPacketSize();
870  uint32_t size = m_fragmentedPacket->GetSize() - startOffset;
871 
872  if (size > m_mpdu->GetPacketSize())
873  {
874  // this is not the last fragment
875  size = m_mpdu->GetPacketSize();
876  hdr.SetMoreFragments();
877  }
878  else
879  {
880  hdr.SetNoMoreFragments();
881  }
882 
883  return Create<WifiMpdu>(m_fragmentedPacket->CreateFragment(startOffset, size), hdr);
884 }
885 
886 void
888 {
889  NS_LOG_FUNCTION(this);
890 
891  // Upon a transmission success, a non-QoS station transmits the next fragment,
892  // if any, or releases the channel, otherwise
893  if (m_moreFragments)
894  {
895  NS_LOG_DEBUG("Schedule transmission of next fragment in a SIFS");
898  this,
899  m_dcf,
901  m_moreFragments = false;
902  }
903  else
904  {
906  m_dcf = nullptr;
907  }
908 }
909 
910 void
912 {
913  NS_LOG_FUNCTION(this);
914  // A non-QoS station always releases the channel upon a transmission failure
916  m_dcf = nullptr;
917 }
918 
919 void
921 {
922  NS_LOG_FUNCTION(this << txop);
924  m_protectedStas.clear();
925 }
926 
927 void
929 {
930  NS_LOG_FUNCTION(this << *mpdu << txVector);
931 
932  GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
933 
934  if (!GetWifiRemoteStationManager()->NeedRetransmission(mpdu))
935  {
936  NS_LOG_DEBUG("Missed Ack, discard MPDU");
937  NotifyPacketDiscarded(mpdu);
938  // Dequeue the MPDU if it is stored in a queue
939  DequeueMpdu(mpdu);
940  GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
942  }
943  else
944  {
945  NS_LOG_DEBUG("Missed Ack, retransmit MPDU");
946  if (mpdu->IsQueued()) // the MPDU may have been removed due to lifetime expiration
947  {
948  mpdu = m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu);
949  mpdu->ResetInFlight(m_linkId);
950  }
951  mpdu->GetHeader().SetRetry();
954  }
955 
956  m_mpdu = nullptr;
958 }
959 
960 void
962 {
963  NS_LOG_FUNCTION(this << *mpdu);
964 }
965 
966 void
968 {
969  NS_LOG_FUNCTION(this << *rts << txVector);
970 
971  DoCtsTimeout(Create<WifiPsdu>(m_mpdu, true));
972  m_mpdu = nullptr;
973 }
974 
975 void
977 {
978  NS_LOG_FUNCTION(this << *psdu);
979 
980  m_sentRtsTo.clear();
981  for (const auto& mpdu : *PeekPointer(psdu))
982  {
983  if (mpdu->IsQueued())
984  {
985  mpdu->ResetInFlight(m_linkId);
986  }
987  }
988 
989  GetWifiRemoteStationManager()->ReportRtsFailed(psdu->GetHeader(0));
990 
991  if (!GetWifiRemoteStationManager()->NeedRetransmission(*psdu->begin()))
992  {
993  NS_LOG_DEBUG("Missed CTS, discard MPDU(s)");
994  GetWifiRemoteStationManager()->ReportFinalRtsFailed(psdu->GetHeader(0));
995  for (const auto& mpdu : *PeekPointer(psdu))
996  {
997  // Dequeue the MPDU if it is stored in a queue
998  DequeueMpdu(mpdu);
999  NotifyPacketDiscarded(mpdu);
1000  }
1002  }
1003  else
1004  {
1005  NS_LOG_DEBUG("Missed CTS, retransmit MPDU(s)");
1007  }
1008  // Make the sequence numbers of the MPDUs available again if the MPDUs have never
1009  // been transmitted, both in case the MPDUs have been discarded and in case the
1010  // MPDUs have to be transmitted (because a new sequence number is assigned to
1011  // MPDUs that have never been transmitted and are selected for transmission)
1012  ReleaseSequenceNumbers(psdu);
1013 
1015 }
1016 
1017 void
1019 {
1020  NS_LOG_FUNCTION(this << *psdu);
1021 
1022  NS_ASSERT_MSG(psdu->GetNMpdus() == 1, "A-MPDUs should be handled by the HT FEM override");
1023  auto mpdu = *psdu->begin();
1024 
1025  // the MPDU should be still in the DCF queue, unless it expired.
1026  // If the MPDU has never been transmitted and is not in-flight, it will be assigned
1027  // a sequence number again the next time we try to transmit it. Therefore, we need to
1028  // make its sequence number available again
1029  if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
1030  {
1031  mpdu->UnassignSeqNo();
1032  m_txMiddle->SetSequenceNumberFor(&mpdu->GetOriginal()->GetHeader());
1033  }
1034 }
1035 
1036 void
1038 {
1039  NS_LOG_FUNCTION(this);
1040 
1041  // For internal collisions occurring with the EDCA access method, the appropriate
1042  // retry counters (short retry counter for MSDU, A-MSDU, or MMPDU and QSRC[AC] or
1043  // long retry counter for MSDU, A-MSDU, or MMPDU and QLRC[AC]) are incremented
1044  // (Sec. 10.22.2.11.1 of 802.11-2016).
1045  // We do not prepare the PSDU that the AC losing the internal collision would have
1046  // sent. As an approximation, we consider the frame peeked from the queues of the AC.
1047  Ptr<QosTxop> qosTxop = (txop->IsQosTxop() ? StaticCast<QosTxop>(txop) : nullptr);
1048 
1049  auto mpdu =
1050  (qosTxop ? qosTxop->PeekNextMpdu(m_linkId) : txop->GetWifiMacQueue()->Peek(m_linkId));
1051 
1052  if (mpdu)
1053  {
1054  if (mpdu->GetHeader().HasData() && !mpdu->GetHeader().GetAddr1().IsGroup())
1055  {
1056  GetWifiRemoteStationManager()->ReportDataFailed(mpdu);
1057  }
1058 
1059  if (!mpdu->GetHeader().GetAddr1().IsGroup() &&
1060  !GetWifiRemoteStationManager()->NeedRetransmission(mpdu))
1061  {
1062  NS_LOG_DEBUG("reset DCF");
1063  GetWifiRemoteStationManager()->ReportFinalDataFailed(mpdu);
1064  DequeueMpdu(mpdu);
1065  NotifyPacketDiscarded(mpdu);
1066  txop->ResetCw(m_linkId);
1067  }
1068  else
1069  {
1070  NS_LOG_DEBUG("Update CW");
1071  txop->UpdateFailedCw(m_linkId);
1072  }
1073  }
1074 
1075  txop->Txop::NotifyChannelReleased(m_linkId);
1076 }
1077 
1078 void
1080 {
1081  NS_LOG_DEBUG("Switching channel. Cancelling MAC pending events");
1083  if (m_txTimer.IsRunning())
1084  {
1085  // we were transmitting something before channel switching. Since we will
1086  // not be able to receive the response, have the timer expire now, so that
1087  // we perform the actions required in case of missing response
1089  }
1091 }
1092 
1093 void
1095 {
1096  NS_LOG_DEBUG("Device in sleep mode. Cancelling MAC pending events");
1097  Reset();
1098 }
1099 
1100 void
1102 {
1103  NS_LOG_DEBUG("Device is switched off. Cancelling MAC pending events");
1104  Reset();
1105 }
1106 
1107 void
1109  RxSignalInfo rxSignalInfo,
1110  WifiTxVector txVector,
1111  std::vector<bool> perMpduStatus)
1112 {
1114  this << psdu << rxSignalInfo << txVector << perMpduStatus.size()
1115  << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](bool v) { return v; }));
1116 
1117  if (!perMpduStatus.empty())
1118  {
1119  // for A-MPDUs, we get here only once
1120  PreProcessFrame(psdu, txVector);
1121  }
1122 
1123  Mac48Address addr1 = psdu->GetAddr1();
1124 
1125  if (addr1.IsGroup() || addr1 == m_self)
1126  {
1127  // receive broadcast frames or frames addressed to us only
1128  if (psdu->GetNMpdus() == 1)
1129  {
1130  // if perMpduStatus is not empty (i.e., this MPDU is not included in an A-MPDU)
1131  // then it must contain a single value which must be true (i.e., the MPDU
1132  // has been correctly received)
1133  NS_ASSERT(perMpduStatus.empty() || (perMpduStatus.size() == 1 && perMpduStatus[0]));
1134  // Ack and CTS do not carry Addr2
1135  if (!psdu->GetHeader(0).IsAck() && !psdu->GetHeader(0).IsCts())
1136  {
1137  GetWifiRemoteStationManager()->ReportRxOk(psdu->GetHeader(0).GetAddr2(),
1138  rxSignalInfo,
1139  txVector);
1140  }
1141  ReceiveMpdu(*(psdu->begin()), rxSignalInfo, txVector, perMpduStatus.empty());
1142  }
1143  else
1144  {
1145  EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1146  }
1147  }
1148  else if (m_promisc)
1149  {
1150  for (const auto& mpdu : *PeekPointer(psdu))
1151  {
1152  if (!mpdu->GetHeader().IsCtl())
1153  {
1154  m_rxMiddle->Receive(mpdu, m_linkId);
1155  }
1156  }
1157  }
1158 
1159  if (!perMpduStatus.empty())
1160  {
1161  // for A-MPDUs, we get here only once
1162  PostProcessFrame(psdu, txVector);
1163  }
1164 }
1165 
1166 void
1168 {
1169  NS_LOG_FUNCTION(this << psdu << txVector);
1170 }
1171 
1172 void
1174 {
1175  NS_LOG_FUNCTION(this << psdu << txVector);
1176 
1177  UpdateNav(psdu, txVector);
1178 }
1179 
1180 void
1182 {
1183  NS_LOG_FUNCTION(this << psdu << txVector);
1184 
1185  if (!psdu->HasNav())
1186  {
1187  return;
1188  }
1189 
1190  Time duration = psdu->GetDuration();
1191  NS_LOG_DEBUG("Duration/ID=" << duration);
1192 
1193  if (psdu->GetAddr1() == m_self)
1194  {
1195  // When the received frame’s RA is equal to the STA’s own MAC address, the STA
1196  // shall not update its NAV (IEEE 802.11-2016, sec. 10.3.2.4)
1197  return;
1198  }
1199 
1200  // For all other received frames the STA shall update its NAV when the received
1201  // Duration is greater than the STA’s current NAV value (IEEE 802.11-2016 sec. 10.3.2.4)
1202  Time navEnd = Simulator::Now() + duration;
1203  if (navEnd > m_navEnd)
1204  {
1205  m_navEnd = navEnd;
1206  NS_LOG_DEBUG("Updated NAV=" << m_navEnd);
1207 
1208  // A STA that used information from an RTS frame as the most recent basis to update
1209  // its NAV setting is permitted to reset its NAV if no PHY-RXSTART.indication
1210  // primitive is received from the PHY during a NAVTimeout period starting when the
1211  // MAC receives a PHY-RXEND.indication primitive corresponding to the detection of
1212  // the RTS frame. NAVTimeout period is equal to:
1213  // (2 x aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 x aSlotTime)
1214  // The “CTS_Time” shall be calculated using the length of the CTS frame and the data
1215  // rate at which the RTS frame used for the most recent NAV update was received
1216  // (IEEE 802.11-2016 sec. 10.3.2.4)
1217  if (psdu->GetHeader(0).IsRts())
1218  {
1219  WifiTxVector ctsTxVector =
1220  GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode());
1221  Time navResetDelay =
1222  2 * m_phy->GetSifs() +
1225  m_navResetEvent =
1227  }
1228  }
1229  NS_LOG_DEBUG("Current NAV=" << m_navEnd);
1230 
1232 }
1233 
1234 void
1236 {
1237  NS_LOG_FUNCTION(this);
1240 }
1241 
1242 bool
1244 {
1245  return m_navEnd <= Simulator::Now();
1246 }
1247 
1248 void
1250  RxSignalInfo rxSignalInfo,
1251  const WifiTxVector& txVector,
1252  bool inAmpdu)
1253 {
1254  NS_LOG_FUNCTION(this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1255  // The received MPDU is either broadcast or addressed to this station
1256  NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1257 
1258  double rxSnr = rxSignalInfo.snr;
1259  const WifiMacHeader& hdr = mpdu->GetHeader();
1260 
1261  if (hdr.IsCtl())
1262  {
1263  if (hdr.IsRts())
1264  {
1265  NS_ABORT_MSG_IF(inAmpdu, "Received RTS as part of an A-MPDU");
1266 
1267  // A non-VHT STA that is addressed by an RTS frame behaves as follows:
1268  // - If the NAV indicates idle, the STA shall respond with a CTS frame after a SIFS
1269  // - Otherwise, the STA shall not respond with a CTS frame
1270  // (IEEE 802.11-2016 sec. 10.3.2.7)
1271  if (VirtualCsMediumIdle())
1272  {
1273  NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", schedule CTS");
1276  this,
1277  hdr,
1278  txVector.GetMode(),
1279  rxSnr);
1280  }
1281  else
1282  {
1283  NS_LOG_DEBUG("Received RTS from=" << hdr.GetAddr2() << ", cannot schedule CTS");
1284  }
1285  }
1286  else if (hdr.IsCts() && m_txTimer.IsRunning() &&
1288  {
1289  NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1290  NS_ASSERT(hdr.GetAddr1() == m_self);
1291 
1292  Mac48Address sender = m_mpdu->GetHeader().GetAddr1();
1293  NS_LOG_DEBUG("Received CTS from=" << sender);
1294 
1295  SnrTag tag;
1296  mpdu->GetPacket()->PeekPacketTag(tag);
1297  GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1298  GetWifiRemoteStationManager()->ReportRtsOk(m_mpdu->GetHeader(),
1299  rxSnr,
1300  txVector.GetMode(),
1301  tag.Get());
1302 
1303  m_txTimer.Cancel();
1306  }
1307  else if (hdr.IsAck() && m_mpdu && m_txTimer.IsRunning() &&
1309  {
1310  NS_ASSERT(hdr.GetAddr1() == m_self);
1311  SnrTag tag;
1312  mpdu->GetPacket()->PeekPacketTag(tag);
1313  ReceivedNormalAck(m_mpdu, m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get());
1314  m_mpdu = nullptr;
1315  }
1316  }
1317  else if (hdr.IsMgt())
1318  {
1319  NS_ABORT_MSG_IF(inAmpdu, "Received management frame as part of an A-MPDU");
1320 
1321  if (hdr.IsBeacon() || hdr.IsProbeResp())
1322  {
1323  // Apply SNR tag for beacon quality measurements
1324  SnrTag tag;
1325  tag.Set(rxSnr);
1326  Ptr<Packet> packet = mpdu->GetPacket()->Copy();
1327  packet->AddPacketTag(tag);
1328  mpdu = Create<WifiMpdu>(packet, hdr);
1329  }
1330 
1331  if (hdr.GetAddr1() == m_self)
1332  {
1333  NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1334  << ", schedule ACK");
1337  this,
1338  hdr,
1339  txVector,
1340  rxSnr);
1341  }
1342 
1343  m_rxMiddle->Receive(mpdu, m_linkId);
1344  }
1345  else if (hdr.IsData() && !hdr.IsQosData())
1346  {
1347  if (hdr.GetAddr1() == m_self)
1348  {
1349  NS_LOG_DEBUG("Received " << hdr.GetTypeString() << " from=" << hdr.GetAddr2()
1350  << ", schedule ACK");
1353  this,
1354  hdr,
1355  txVector,
1356  rxSnr);
1357  }
1358 
1359  m_rxMiddle->Receive(mpdu, m_linkId);
1360  }
1361 }
1362 
1363 void
1365  const WifiTxVector& txVector,
1366  const WifiTxVector& ackTxVector,
1367  const RxSignalInfo& rxInfo,
1368  double snr)
1369 {
1370  Mac48Address sender = mpdu->GetHeader().GetAddr1();
1371  NS_LOG_DEBUG("Received ACK from=" << sender);
1372 
1374 
1375  // When fragmentation is used, only update manager when the last fragment is acknowledged
1376  if (!mpdu->GetHeader().IsMoreFragments())
1377  {
1378  GetWifiRemoteStationManager()->ReportRxOk(sender, rxInfo, ackTxVector);
1379  GetWifiRemoteStationManager()->ReportDataOk(mpdu,
1380  rxInfo.snr,
1381  ackTxVector.GetMode(),
1382  snr,
1383  txVector);
1384  }
1385  // cancel the timer
1386  m_txTimer.Cancel();
1388 
1389  // The CW shall be reset to aCWmin after every successful attempt to transmit
1390  // a frame containing all or part of an MSDU or MMPDU (sec. 10.3.3 of 802.11-2016)
1392 
1393  if (mpdu->GetHeader().IsMoreFragments())
1394  {
1395  // replace the current fragment with the next one
1396  m_dcf->GetWifiMacQueue()->Replace(mpdu, GetNextFragment());
1397  m_moreFragments = true;
1398  }
1399  else
1400  {
1401  // the MPDU has been acknowledged, we can now dequeue it if it is stored in a queue
1402  DequeueMpdu(mpdu);
1403  }
1404 
1406 }
1407 
1408 void
1410 {
1411  NS_LOG_FUNCTION(this << *mpdu);
1412 
1413  // inform the MAC that the transmission was successful
1414  if (!m_ackedMpduCallback.IsNull())
1415  {
1416  m_ackedMpduCallback(mpdu);
1417  }
1418 }
1419 
1420 void
1422  const RxSignalInfo& rxSignalInfo,
1423  const WifiTxVector& txVector,
1424  const std::vector<bool>& perMpduStatus)
1425 {
1426  NS_ASSERT_MSG(false, "A non-QoS station should not receive an A-MPDU");
1427 }
1428 
1429 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
bool IsNull() const
Check for null implementation.
Definition: callback.h:569
void NotifyAckTimeoutResetNow()
Notify that ack timer has reset.
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void NotifyCtsTimeoutStartNow(Time duration)
Notify that CTS timer has started for the given duration.
void NotifyCtsTimeoutResetNow()
Notify that CTS timer has reset.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
Ptr< WifiMpdu > m_mpdu
the MPDU being transmitted
virtual void SetAckManager(Ptr< WifiAckManager > ackManager)
Set the Acknowledgment Manager to use.
void NotifyOffNow()
This method is typically invoked by the PhyListener to notify the MAC layer that the device has been ...
virtual void NotifyInternalCollision(Ptr< Txop > txop)
Notify that an internal collision has occurred for the given Txop.
static TypeId GetTypeId()
Get the type ID.
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
DroppedMpdu m_droppedMpduCallback
the dropped MPDU callback
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the MAC layer to use.
virtual void ResetPhy()
Remove WifiPhy associated with this FrameExchangeManager.
virtual void UpdateNav(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Update the NAV, if needed, based on the Duration/ID of the given psdu.
void SendMpduWithProtection(Ptr< WifiMpdu > mpdu, WifiTxParameters &txParams)
Send an MPDU with the given TX parameters (with the specified protection).
Ptr< WifiAckManager > m_ackManager
Acknowledgment manager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
void UpdateTxDuration(Mac48Address receiver, WifiTxParameters &txParams) const
Update the TX duration field of the given TX parameters after that the PSDU addressed to the given re...
virtual void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
void SendNormalAck(const WifiMacHeader &hdr, const WifiTxVector &dataTxVector, double dataSnr)
Send Normal Ack.
Ptr< Packet > m_fragmentedPacket
the MSDU being fragmented
virtual void SetDroppedMpduCallback(DroppedMpdu callback)
Set the callback to invoke when an MPDU is dropped.
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
virtual void TransmissionFailed()
Take necessary actions upon a transmission failure.
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
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...
WifiTxTimer m_txTimer
the timer set upon frame transmission
void SendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiMode rtsTxMode, double rtsSnr)
Send CTS after receiving RTS.
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const
Retransmit an MPDU that was not acknowledged.
Mac48Address GetAddress() const
Get the MAC address.
Ptr< WifiProtectionManager > m_protectionManager
Protection manager.
virtual void ProtectionCompleted()
Transmit prepared frame upon successful protection mechanism.
virtual void ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector)
Forward an MPDU down to the PHY layer.
virtual void SetLinkId(uint8_t linkId)
Set the ID of the link this Frame Exchange Manager is associated with.
virtual bool VirtualCsMediumIdle() const
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
virtual void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu)
Notify other components that an MPDU was acknowledged.
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
virtual void NormalAckTimeout(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector)
Called when the Ack timeout expires.
virtual void NotifySwitchingStartNow(Time duration)
virtual void SetBssid(Mac48Address bssid)
Set the Basic Service Set Identification.
void SendCtsToSelf(const WifiTxParameters &txParams)
Send CTS for a CTS-to-self mechanism.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
virtual void CalculateProtectionTime(WifiProtection *protection) const
Calculate the time required to protect a frame according to the given protection method.
virtual void SetAddress(Mac48Address address)
Set the MAC address.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
virtual void DequeueMpdu(Ptr< const WifiMpdu > mpdu)
Dequeue the given MPDU from the queue in which it is stored.
virtual void NavResetTimeout()
Reset the NAV upon expiration of the NAV reset timer.
const std::set< Mac48Address > & GetProtectedStas() const
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
bool IsPromisc() const
Check if the device is operating in promiscuous mode.
void SendMpdu()
Send the current MPDU, which can be acknowledged by a Normal Ack.
virtual void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
This method is called when the reception of an A-MPDU including multiple MPDUs is completed.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
virtual void TransmissionSucceeded()
Take necessary actions upon a transmission success.
Ptr< Txop > m_dcf
the DCF/EDCAF that gained channel access
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< WifiMpdu > GetFirstFragmentIfNeeded(Ptr< WifiMpdu > mpdu)
Fragment the given MPDU if needed.
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...
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.
void Receive(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, 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...
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual void SetWifiPhy(const Ptr< WifiPhy > phy)
Set the PHY layer to use.
AckedMpdu m_ackedMpduCallback
the acknowledged MPDU callback
virtual void FinalizeMacHeader(Ptr< const WifiPsdu > psdu)
Finalize the MAC header of the MPDUs in the given PSDU before transmission.
virtual void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
virtual uint32_t GetPsduSize(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector) const
Get the size in bytes of the given MPDU, which is to be transmitted with the given TXVECTOR.
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
virtual void ReceivedNormalAck(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector, const WifiTxVector &ackTxVector, const RxSignalInfo &rxInfo, double snr)
Perform the actions needed when a Normal Ack is received.
bool m_promisc
Flag if the device is operating in promiscuous mode.
void NotifySleepNow()
This method is typically invoked by the PhyListener to notify the MAC layer that the device has been ...
virtual void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu)
This method handles the reception of an MPDU (possibly included in an A-MPDU)
virtual void SetChannelAccessManager(const Ptr< ChannelAccessManager > channelAccessManager)
Set the channel access manager to use.
bool m_moreFragments
true if a fragment has to be sent after a SIFS
void SetPromisc()
Enable promiscuous mode.
Time m_navEnd
NAV expiration time.
virtual void SetMacTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set the MAC TX Middle to use.
virtual void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
virtual void SetProtectionManager(Ptr< WifiProtectionManager > protectionManager)
Set the Protection Manager to use.
Mac48Address GetBssid() const
Get the Basic Service Set Identification.
void DoDispose() override
Destructor implementation.
WifiTxParameters m_txParams
the TX parameters for the current frame
virtual bool StartTransmission(Ptr< Txop > dcf, uint16_t allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
EventId m_navResetEvent
the event to reset the NAV after an RTS
const WifiTxTimer & GetWifiTxTimer() const
Get a const reference to the WifiTxTimer object.
virtual Time GetTxDuration(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams) const
Get the updated TX duration of the frame associated with the given TX parameters if the size of the P...
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:315
bool TraceDisconnectWithoutContext(std::string name, const CallbackBase &cb)
Disconnect from a TraceSource a Callback previously connected without a context.
Definition: object-base.cc:343
A base class which provides memory management and object aggregation.
Definition: object.h:89
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:960
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Create a new packet which contains a fragment of the original packet.
Definition: packet.cc:238
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition: qos-txop.cc:378
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
void Set(double snr)
Set the SNR to the given value.
Definition: snr-tag.cc:84
double Get() const
Return the SNR value.
Definition: snr-tag.cc:90
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:287
@ US
microsecond
Definition: nstime.h:118
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
Definition: nstime.h:342
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:312
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:231
virtual void NotifyChannelReleased(uint8_t linkId)
Called by the FrameExchangeManager to notify the completion of the transmissions.
Definition: txop.cc:624
void ResetCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission success or...
Definition: txop.cc:303
virtual bool IsQosTxop() const
Check for QoS TXOP.
Definition: txop.cc:687
virtual void NotifyChannelAccessed(uint8_t linkId, Time txopDuration=Seconds(0))
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
Definition: txop.cc:617
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
static void SetQosAckPolicy(Ptr< WifiMpdu > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
Implements the IEEE 802.11 MAC header.
bool IsAck() const
Return true if the header is an Ack header.
bool IsCts() const
Return true if the header is a CTS header.
bool IsBeacon() const
Return true if the header is a Beacon header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsMoreFragments() const
Return if the More Fragment bit is set.
void SetNoMoreFragments()
Un-set the More Fragment bit in the Frame Control Field.
bool IsMgt() const
Return true if the Type is Management.
bool IsCtl() const
Return true if the Type is Control.
Time GetDuration() const
Return the duration from the Duration/ID field (Time object).
virtual uint32_t GetSize() const
Return the size of the WifiMacHeader in octets.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsProbeResp() const
Return true if the header is a Probe Response header.
void SetMoreFragments()
Set the More Fragment bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
virtual const char * GetTypeString() const
Return a string corresponds to the header type.
void SetDuration(Time duration)
Set the Duration/ID field with the given duration (Time object).
bool IsData() const
Return true if the Type is DATA.
bool IsRts() const
Return true if the header is a RTS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
uint8_t GetFragmentNumber() const
Return the fragment number of the header.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
void SetFragmentNumber(uint8_t frag)
Set the fragment number of the header.
void SetNoRetry()
Un-set the Retry bit in the Frame Control field.
virtual void NotifyChannelSwitching(uint8_t linkId)
Notify that channel on the given link has been switched.
Definition: wifi-mac.cc:582
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:422
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition: wifi-mac.cc:545
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:906
represent a single transmission mode
Definition: wifi-mode.h:51
void Send(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
This function is a wrapper for the Send variant that accepts a WifiConstPsduMap as first argument.
Definition: wifi-phy.cc:1720
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:793
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:781
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1507
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition: wifi-phy.cc:443
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1021
void SetReceiveOkCallback(RxOkCallback callback)
Definition: wifi-phy.cc:449
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1500
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:279
Time GetDuration() const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
Definition: wifi-psdu.cc:153
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:333
Mac48Address GetAddr2() const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:128
bool HasNav() const
Definition: wifi-psdu.cc:143
Mac48Address GetAddr1() const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:113
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:327
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
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
Time m_txDuration
TX duration of the frame.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMpdu > mpdu)
Record that an MPDU is being added to the current frame.
void Clear()
Reset the TX parameters.
This class is used to handle the timer that a station starts when transmitting a frame that solicits ...
Definition: wifi-tx-timer.h:49
bool IsRunning() const
Return true if the timer is running.
void Cancel()
Cancel the timer.
void Set(Reason reason, const Time &delay, const std::set< Mac48Address > &from, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
Reason GetReason() const
Get the reason why the timer was started.
void Reschedule(const Time &delay)
Reschedule the timer to time out the given amount of time from the moment this function is called.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
uint16_t 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:66
#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:86
Callback< R, Args... > MakeNullCallback()
Definition: callback.h:747
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:46
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
@ STA
Definition: wifi-mac.h:65
@ WIFI_MAC_DROP_REACHED_RETRY_LIMIT
Definition: wifi-mac.h:80
@ WIFI_PM_SWITCHING_TO_ACTIVE
Definition: sta-wifi-mac.h:94
@ WIFI_PM_POWERSAVE
Definition: sta-wifi-mac.h:93
@ WIFI_PM_SWITCHING_TO_PS
Definition: sta-wifi-mac.h:92
@ WIFI_PM_ACTIVE
Definition: sta-wifi-mac.h:91
address
Definition: first.py:47
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const uint16_t WIFI_MAC_FCS_LENGTH
The length in octets of the IEEE 802.11 MAC FCS field.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Definition: wifi-utils.cc:103
@ WIFI_MAC_CTL_RTS
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_CTL_ACK
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
Definition: wifi-utils.cc:58
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
Definition: wifi-utils.cc:111
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:449
mac
Definition: third.py:92
phy
Definition: third.py:89
ns3::Time timeout
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
double snr
SNR in linear scale.
Definition: phy-entity.h:70
WifiAcknowledgment is an abstract base struct.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
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.
Time protectionTime
time required by the protection method
const Method method
protection method
WifiRtsCtsProtection specifies that RTS/CTS protection method is used.