A Discrete-Event Network Simulator
API
ht-frame-exchange-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Stefano Avallone <stavallo@unina.it>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/abort.h"
24 #include "ns3/wifi-mac-queue.h"
25 #include "ns3/mgt-headers.h"
26 #include "ns3/recipient-block-ack-agreement.h"
27 #include "ns3/wifi-utils.h"
28 #include "ns3/snr-tag.h"
29 #include "ns3/ctrl-headers.h"
30 
31 #undef NS_LOG_APPEND_CONTEXT
32 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
33 
34 namespace ns3 {
35 
36 NS_LOG_COMPONENT_DEFINE ("HtFrameExchangeManager");
37 
38 NS_OBJECT_ENSURE_REGISTERED (HtFrameExchangeManager);
39 
40 TypeId
42 {
43  static TypeId tid = TypeId ("ns3::HtFrameExchangeManager")
45  .AddConstructor<HtFrameExchangeManager> ()
46  .SetGroupName ("Wifi")
47  ;
48  return tid;
49 }
50 
52 {
53  NS_LOG_FUNCTION (this);
54  m_msduAggregator = CreateObject<MsduAggregator> ();
55  m_mpduAggregator = CreateObject<MpduAggregator> ();
56 }
57 
59 {
61 }
62 
63 void
65 {
66  NS_LOG_FUNCTION (this);
67  m_agreements.clear ();
68  m_msduAggregator = 0;
69  m_mpduAggregator = 0;
70  m_psdu = 0;
71  m_txParams.Clear ();
73 }
74 
75 void
77 {
78  m_msduAggregator->SetWifiMac (mac);
79  m_mpduAggregator->SetWifiMac (mac);
81 }
82 
85 {
86  return m_msduAggregator;
87 }
88 
91 {
92  return m_mpduAggregator;
93 }
94 
97 {
98  return m_mac->GetQosTxop (tid)->GetBaManager ();
99 }
100 
101 bool
103 {
104  Ptr<QosTxop> qosTxop = m_mac->GetQosTxop (tid);
105  bool establish;
106 
107  if (!m_mac->GetWifiRemoteStationManager ()->GetHtSupported (recipient))
108  {
109  establish = false;
110  }
111  else if (qosTxop->GetBaManager ()->ExistsAgreement (recipient, tid)
112  && !qosTxop->GetBaManager ()->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::RESET))
113  {
114  establish = false;
115  }
116  else
117  {
118  uint32_t packets = qosTxop->GetWifiMacQueue ()->GetNPacketsByTidAndAddress (tid, recipient);
119  establish = ((qosTxop->GetBlockAckThreshold () > 0 && packets >= qosTxop->GetBlockAckThreshold ())
120  || (m_mpduAggregator->GetMaxAmpduSize (recipient, tid, WIFI_MOD_CLASS_HT) > 0 && packets > 1)
121  || m_mac->GetWifiRemoteStationManager ()->GetVhtSupported ());
122  }
123 
124  NS_LOG_FUNCTION (this << recipient << +tid << establish);
125  return establish;
126 }
127 
128 void
129 HtFrameExchangeManager::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startingSeq,
130  uint16_t timeout, bool immediateBAck)
131 {
132  NS_LOG_FUNCTION (this << dest << +tid << startingSeq << timeout << immediateBAck);
133  NS_LOG_DEBUG ("Send ADDBA request to " << dest);
134 
135  WifiMacHeader hdr;
137  hdr.SetAddr1 (dest);
138  hdr.SetAddr2 (m_self);
139  hdr.SetAddr3 (m_bssid);
140  hdr.SetDsNotTo ();
141  hdr.SetDsNotFrom ();
142 
143  WifiActionHeader actionHdr;
146  actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
147 
148  Ptr<Packet> packet = Create<Packet> ();
149  // Setting ADDBARequest header
150  MgtAddBaRequestHeader reqHdr;
151  reqHdr.SetAmsduSupport (true);
152  if (immediateBAck)
153  {
154  reqHdr.SetImmediateBlockAck ();
155  }
156  else
157  {
158  reqHdr.SetDelayedBlockAck ();
159  }
160  reqHdr.SetTid (tid);
161  /* For now we don't use buffer size field in the ADDBA request frame. The recipient
162  * will choose how many packets it can receive under block ack.
163  */
164  reqHdr.SetBufferSize (0);
165  reqHdr.SetTimeout (timeout);
166  // set the starting sequence number for the BA agreement
167  reqHdr.SetStartingSequence (startingSeq);
168 
169  GetBaManager (tid)->CreateAgreement (&reqHdr, dest);
170 
171  packet->AddHeader (reqHdr);
172  packet->AddHeader (actionHdr);
173 
174  Ptr<WifiMacQueueItem> mpdu = Create<WifiMacQueueItem> (packet, hdr);
175 
176  // get the sequence number for the ADDBA Request management frame
177  uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor (&mpdu->GetHeader ());
178  mpdu->GetHeader ().SetSequenceNumber (sequence);
179 
180  WifiTxParameters txParams;
181  txParams.m_txVector = m_mac->GetWifiRemoteStationManager ()->GetDataTxVector (mpdu->GetHeader ());
182  txParams.m_protection = std::unique_ptr<WifiProtection> (new WifiNoProtection);
183  txParams.m_acknowledgment = GetAckManager ()->TryAddMpdu (mpdu, txParams);
184 
185  SendMpduWithProtection (mpdu, txParams);
186 }
187 
188 void
190  Mac48Address originator)
191 {
192  NS_LOG_FUNCTION (this << originator);
193  WifiMacHeader hdr;
195  hdr.SetAddr1 (originator);
196  hdr.SetAddr2 (m_self);
197  hdr.SetAddr3 (m_bssid);
198  hdr.SetDsNotFrom ();
199  hdr.SetDsNotTo ();
200 
201  MgtAddBaResponseHeader respHdr;
202  StatusCode code;
203  code.SetSuccess ();
204  respHdr.SetStatusCode (code);
205  //Here a control about queues type?
206  respHdr.SetAmsduSupport (reqHdr->IsAmsduSupported ());
207 
208  if (reqHdr->IsImmediateBlockAck ())
209  {
210  respHdr.SetImmediateBlockAck ();
211  }
212  else
213  {
214  respHdr.SetDelayedBlockAck ();
215  }
216  respHdr.SetTid (reqHdr->GetTid ());
217 
218  respHdr.SetBufferSize (GetSupportedBaBufferSize () - 1);
219  respHdr.SetTimeout (reqHdr->GetTimeout ());
220 
221  WifiActionHeader actionHdr;
224  actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
225 
226  Ptr<Packet> packet = Create<Packet> ();
227  packet->AddHeader (respHdr);
228  packet->AddHeader (actionHdr);
229 
230  CreateBlockAckAgreement (&respHdr, originator, reqHdr->GetStartingSequence ());
231 
232  //It is unclear which queue this frame should go into. For now we
233  //bung it into the queue corresponding to the TID for which we are
234  //establishing an agreement, and push it to the head.
235  m_mac->GetQosTxop (reqHdr->GetTid ())->PushFront (packet, hdr);
236 }
237 
238 uint16_t
240 {
241  return 64;
242 }
243 
244 void
245 HtFrameExchangeManager::SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator)
246 {
247  NS_LOG_FUNCTION (this << addr << +tid << byOriginator);
248  WifiMacHeader hdr;
250  hdr.SetAddr1 (addr);
251  hdr.SetAddr2 (m_self);
252  hdr.SetAddr3 (m_bssid);
253  hdr.SetDsNotTo ();
254  hdr.SetDsNotFrom ();
255 
256  MgtDelBaHeader delbaHdr;
257  delbaHdr.SetTid (tid);
258  if (byOriginator)
259  {
260  delbaHdr.SetByOriginator ();
261  GetBaManager (tid)->DestroyAgreement (addr, tid);
262  }
263  else
264  {
265  delbaHdr.SetByRecipient ();
266  DestroyBlockAckAgreement (addr, tid);
267  }
268 
269  WifiActionHeader actionHdr;
272  actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
273 
274  Ptr<Packet> packet = Create<Packet> ();
275  packet->AddHeader (delbaHdr);
276  packet->AddHeader (actionHdr);
277 
278  m_mac->GetQosTxop (tid)->GetWifiMacQueue ()->PushFront (Create<WifiMacQueueItem> (packet, hdr));
279 }
280 
281 void
283  uint16_t startingSeq)
284 {
285  NS_LOG_FUNCTION (this << *respHdr << originator << startingSeq);
286  uint8_t tid = respHdr->GetTid ();
287 
288  RecipientBlockAckAgreement agreement (originator, respHdr->IsAmsduSupported (), tid,
289  respHdr->GetBufferSize () + 1, respHdr->GetTimeout (),
290  startingSeq,
291  m_mac->GetWifiRemoteStationManager ()->GetHtSupported ()
292  && m_mac->GetWifiRemoteStationManager ()->GetHtSupported (originator));
293  agreement.SetMacRxMiddle (m_rxMiddle);
294  if (respHdr->IsImmediateBlockAck ())
295  {
296  agreement.SetImmediateBlockAck ();
297  }
298  else
299  {
300  agreement.SetDelayedBlockAck ();
301  }
302 
303  if (respHdr->GetTimeout () != 0)
304  {
305  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
306 
307  agreement.m_inactivityEvent = Simulator::Schedule (timeout, &HtFrameExchangeManager::SendDelbaFrame,
308  this, originator, tid, false);
309  }
310 
311  m_agreements.insert ({{originator, tid}, agreement});
312  GetBaManager (tid)->SetBlockAckInactivityCallback (MakeCallback (&HtFrameExchangeManager::SendDelbaFrame, this));
313 }
314 
315 void
317 {
318  NS_LOG_FUNCTION (this << originator << +tid);
319 
320  auto agreementIt = m_agreements.find ({originator, tid});
321  if (agreementIt != m_agreements.end ())
322  {
323  // forward up the buffered MPDUs before destroying the agreement
324  agreementIt->second.Flush ();
325  m_agreements.erase (agreementIt);
326  }
327 }
328 
329 bool
330 HtFrameExchangeManager::StartFrameExchange (Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
331 {
332  NS_LOG_FUNCTION (this << edca << availableTime << initialFrame);
333 
334  // First, check if there is a BAR to be transmitted
335  if (SendMpduFromBaManager (edca, availableTime, initialFrame))
336  {
337  return true;
338  }
339 
340  Ptr<const WifiMacQueueItem> peekedItem = edca->PeekNextMpdu ();
341 
342  // Even though channel access is requested when the queue is not empty, at
343  // the time channel access is granted the lifetime of the packet might be
344  // expired and the queue might be empty.
345  if (peekedItem == 0)
346  {
347  NS_LOG_DEBUG ("No frames available for transmission");
348  return false;
349  }
350 
351  const WifiMacHeader& hdr = peekedItem->GetHeader ();
352  // setup a Block Ack agreement if needed
353  if (hdr.IsQosData () && !hdr.GetAddr1 ().IsGroup ()
354  && NeedSetupBlockAck (hdr.GetAddr1 (), hdr.GetQosTid ()))
355  {
356  // if the peeked MPDU has been already transmitted, use its sequence number
357  // as the starting sequence number for the BA agreement, otherwise use the
358  // next available sequence number
359  uint16_t startingSeq = (hdr.IsRetry () ? hdr.GetSequenceNumber ()
360  : m_txMiddle->GetNextSeqNumberByTidAndAddress (hdr.GetQosTid (),
361  hdr.GetAddr1 ()));
362  SendAddBaRequest (hdr.GetAddr1 (), hdr.GetQosTid (), startingSeq,
363  edca->GetBlockAckInactivityTimeout (), true);
364  return true;
365  }
366 
367  // Use SendDataFrame if we can try aggregation
368  if (hdr.IsQosData () && !hdr.GetAddr1 ().IsGroup () && !peekedItem->IsFragment ()
369  && !m_mac->GetWifiRemoteStationManager ()->NeedFragmentation (peekedItem))
370  {
371  return SendDataFrame (peekedItem, availableTime, initialFrame);
372  }
373 
374  // Use the QoS FEM to transmit the frame in all the other cases, i.e.:
375  // - the frame is not a QoS data frame
376  // - the frame is a broadcast QoS data frame
377  // - the frame is a fragment
378  // - the frame must be fragmented
379  return QosFrameExchangeManager::StartFrameExchange (edca, availableTime, initialFrame);
380 }
381 
382 bool
383 HtFrameExchangeManager::SendMpduFromBaManager (Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
384 {
385  NS_LOG_FUNCTION (this << edca << availableTime << initialFrame);
386 
387  // First, check if there is a BAR to be transmitted
388  Ptr<const WifiMacQueueItem> peekedItem = edca->GetBaManager ()->GetBar (false);
389 
390  if (peekedItem == 0)
391  {
392  NS_LOG_DEBUG ("Block Ack Manager returned no frame to send");
393  return false;
394  }
395 
396  NS_ASSERT (peekedItem->GetHeader ().IsBlockAckReq ());
397 
398  // Prepare the TX parameters. Note that the default ack manager expects the
399  // data TxVector in the m_txVector field to compute the BlockAck TxVector.
400  // The m_txVector field of the TX parameters is set to the BlockAckReq TxVector
401  // a few lines below.
402  WifiTxParameters txParams;
403  txParams.m_txVector = m_mac->GetWifiRemoteStationManager ()->GetDataTxVector (peekedItem->GetHeader ());
404  txParams.m_protection = std::unique_ptr<WifiProtection> (new WifiNoProtection);
405  txParams.m_acknowledgment = GetAckManager ()->TryAddMpdu (peekedItem, txParams);
406 
407  NS_ABORT_IF (txParams.m_acknowledgment->method != WifiAcknowledgment::BLOCK_ACK);
408 
409  WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*> (txParams.m_acknowledgment.get ());
410  CalculateAcknowledgmentTime (blockAcknowledgment);
411  // the BlockAckReq frame is sent using the same TXVECTOR as the BlockAck frame
412  txParams.m_txVector = blockAcknowledgment->blockAckTxVector;
413 
414  Time barTxDuration = m_phy->CalculateTxDuration (peekedItem->GetSize (),
415  blockAcknowledgment->blockAckTxVector,
416  m_phy->GetPhyBand ());
417 
418  // if the available time is limited and we are not transmitting the initial
419  // frame of the TXOP, we have to check that this frame and its response fit
420  // within the given time limits
421  if (availableTime != Time::Min () && !initialFrame
422  && barTxDuration + m_phy->GetSifs () + blockAcknowledgment->acknowledgmentTime > availableTime)
423  {
424  NS_LOG_DEBUG ("Not enough time to send the BAR frame returned by the Block Ack Manager");
425  return false;
426  }
427 
428  // we can transmit the BlockAckReq frame
429  Ptr<const WifiMacQueueItem> mpdu = edca->GetBaManager ()->GetBar ();
430  SendPsduWithProtection (Create<WifiPsdu> (mpdu, false), txParams);
431  return true;
432 }
433 
434 bool
436  Time availableTime, bool initialFrame)
437 {
438  NS_ASSERT (peekedItem != 0 && peekedItem->GetHeader ().IsQosData ()
439  && !peekedItem->GetHeader ().GetAddr1 ().IsBroadcast ()
440  && !peekedItem->IsFragment ());
441  NS_LOG_FUNCTION (this << *peekedItem << availableTime << initialFrame);
442 
443  Ptr<QosTxop> edca = m_mac->GetQosTxop (peekedItem->GetHeader ().GetQosTid ());
444  WifiTxParameters txParams;
445  txParams.m_txVector = m_mac->GetWifiRemoteStationManager ()->GetDataTxVector (peekedItem->GetHeader ());
447  Ptr<WifiMacQueueItem> mpdu = edca->GetNextMpdu (peekedItem, txParams, availableTime, initialFrame, queueIt);
448 
449  if (mpdu == nullptr)
450  {
451  NS_LOG_DEBUG ("Not enough time to transmit a frame");
452  return false;
453  }
454 
455  // try A-MPDU aggregation
456  std::vector<Ptr<WifiMacQueueItem>> mpduList = m_mpduAggregator->GetNextAmpdu (mpdu, txParams,
457  availableTime, queueIt);
458  NS_ASSERT (txParams.m_acknowledgment);
459 
460  if (mpduList.size () > 1)
461  {
462  // A-MPDU aggregation succeeded
463  SendPsduWithProtection (Create<WifiPsdu> (std::move (mpduList)), txParams);
464  }
465  else if (txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
466  {
467  // a QoS data frame using the Block Ack policy can be followed by a BlockAckReq
468  // frame and a BlockAck frame. Such a sequence is handled by the HT FEM
469  SendPsduWithProtection (Create<WifiPsdu> (mpdu, false), txParams);
470  }
471  else
472  {
473  // transmission can be handled by the base FEM
474  SendMpduWithProtection (mpdu, txParams);
475  }
476 
477  return true;
478 }
479 
480 void
482 {
483  NS_LOG_FUNCTION (this << acknowledgment);
484  NS_ASSERT (acknowledgment != nullptr);
485 
486  if (acknowledgment->method == WifiAcknowledgment::BLOCK_ACK)
487  {
488  WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*> (acknowledgment);
489  Time baTxDuration = m_phy->CalculateTxDuration (GetBlockAckSize (blockAcknowledgment->baType),
490  blockAcknowledgment->blockAckTxVector,
491  m_phy->GetPhyBand ());
492  blockAcknowledgment->acknowledgmentTime = m_phy->GetSifs () + baTxDuration;
493  }
494  else if (acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
495  {
496  WifiBarBlockAck* barBlockAcknowledgment = static_cast<WifiBarBlockAck*> (acknowledgment);
497  Time barTxDuration = m_phy->CalculateTxDuration (GetBlockAckRequestSize (barBlockAcknowledgment->barType),
498  barBlockAcknowledgment->blockAckReqTxVector,
499  m_phy->GetPhyBand ());
500  Time baTxDuration = m_phy->CalculateTxDuration (GetBlockAckSize (barBlockAcknowledgment->baType),
501  barBlockAcknowledgment->blockAckTxVector,
502  m_phy->GetPhyBand ());
503  barBlockAcknowledgment->acknowledgmentTime = 2 * m_phy->GetSifs () + barTxDuration + baTxDuration;
504  }
505  else
506  {
508  }
509 }
510 
511 void
513 {
514  ForwardPsduDown (GetWifiPsdu (mpdu, txVector), txVector);
515 }
516 
519 {
520  return Create<WifiPsdu> (mpdu, false);
521 }
522 
523 void
525 {
526  NS_LOG_FUNCTION (this << *mpdu);
527 
528  if (mpdu->GetHeader ().IsQosData ())
529  {
530  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
531  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
532 
533  if (edca->GetBaAgreementEstablished (mpdu->GetHeader ().GetAddr1 (), tid))
534  {
535  // notify the BA manager that the MPDU was acknowledged
536  edca->GetBaManager ()->NotifyGotAck (mpdu);
537  }
538  }
539  else if (mpdu->GetHeader ().IsAction ())
540  {
541  WifiActionHeader actionHdr;
542  Ptr<Packet> p = mpdu->GetPacket ()->Copy ();
543  p->RemoveHeader (actionHdr);
544  if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK)
545  {
547  {
548  MgtDelBaHeader delBa;
549  p->PeekHeader (delBa);
550  if (delBa.IsByOriginator ())
551  {
552  GetBaManager (delBa.GetTid ())->DestroyAgreement (mpdu->GetHeader ().GetAddr1 (),
553  delBa.GetTid ());
554  }
555  else
556  {
557  DestroyBlockAckAgreement (mpdu->GetHeader ().GetAddr1 (), delBa.GetTid ());
558  }
559  }
561  {
562  // Setup ADDBA response timeout
563  MgtAddBaRequestHeader addBa;
564  p->PeekHeader (addBa);
565  Ptr<QosTxop> edca = m_mac->GetQosTxop (addBa.GetTid ());
568  mpdu->GetHeader ().GetAddr1 (), addBa.GetTid ());
569  }
570  }
571  }
573 }
574 
575 void
577 {
578  NS_LOG_DEBUG (this);
579 
580  if (m_edca != 0 && m_edca->GetTxopLimit ().IsZero () && m_edca->GetBaManager ()->GetBar (false) != 0)
581  {
582  // A TXOP limit of 0 indicates that the TXOP holder may transmit or cause to
583  // be transmitted (as responses) the following within the current TXOP:
584  // f) Any number of BlockAckReq frames
585  // (Sec. 10.22.2.8 of 802.11-2016)
586  NS_LOG_DEBUG ("Schedule a transmission from Block Ack Manager in a SIFS");
588 
589  // TXOP limit is null, hence the txopDuration parameter is unused
590  Simulator::Schedule (m_phy->GetSifs (), fp, this, m_edca, Seconds (0));
591  }
592  else
593  {
595  }
596 }
597 
598 void
600 {
601  NS_LOG_FUNCTION (this << *mpdu);
602 
603  if (mpdu->GetHeader ().IsQosData ())
604  {
605  GetBaManager (mpdu->GetHeader ().GetQosTid ())->NotifyDiscardedMpdu (mpdu);
606  }
607  else if (mpdu->GetHeader ().IsAction ())
608  {
609  WifiActionHeader actionHdr;
610  mpdu->GetPacket ()->PeekHeader (actionHdr);
611  if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK)
612  {
613  uint8_t tid = GetTid (mpdu->GetPacket (), mpdu->GetHeader ());
614  if (GetBaManager (tid)->ExistsAgreementInState (mpdu->GetHeader ().GetAddr1 (), tid,
616  {
617  NS_LOG_DEBUG ("No ACK after ADDBA request");
618  GetBaManager (tid)->NotifyAgreementNoReply (mpdu->GetHeader ().GetAddr1 (), tid);
619  Ptr<QosTxop> qosTxop = m_mac->GetQosTxop (tid);
621  mpdu->GetHeader ().GetAddr1 (), tid);
622  }
623  }
624  }
626 }
627 
628 void
630 {
631  NS_LOG_FUNCTION (this << *mpdu);
632 
633  if (mpdu->GetHeader ().IsQosData ())
634  {
635  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
636  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
637 
638  if (edca->GetBaAgreementEstablished (mpdu->GetHeader ().GetAddr1 (), tid))
639  {
640  // notify the BA manager that the MPDU was not acknowledged
641  edca->GetBaManager ()->NotifyMissedAck (mpdu);
642  return;
643  }
644  }
646 }
647 
648 void
650 {
651  NS_LOG_FUNCTION (this << *mpdu);
652 
653  // the MPDU should be still in the queue, unless it expired.
654  const WifiMacHeader& hdr = mpdu->GetHeader ();
655  if (hdr.IsQosData ())
656  {
657  uint8_t tid = hdr.GetQosTid ();
658  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
659 
660  if (edca->GetBaAgreementEstablished (hdr.GetAddr1 (), tid)
661  && !hdr.IsRetry ())
662  {
663  // The MPDU has never been transmitted, so we can make its sequence
664  // number available again if it is lower than the sequence number
665  // maintained by the MAC TX middle
666  uint16_t currentNextSeq = m_txMiddle->PeekNextSequenceNumberFor (&hdr);
667  uint16_t startingSeq = edca->GetBaStartingSequence (hdr.GetAddr1 (), tid);
668 
669  if (BlockAckAgreement::GetDistance (hdr.GetSequenceNumber (), startingSeq)
670  < BlockAckAgreement::GetDistance (currentNextSeq, startingSeq))
671  {
672  m_txMiddle->SetSequenceNumberFor (&hdr);
673  }
674 
675  return;
676  }
677  }
679 }
680 
681 Time
683 {
684  NS_LOG_FUNCTION (this << txDuration << &txParams);
685 
686  NS_ASSERT (m_edca != 0);
687 
688  if (m_edca->GetTxopLimit ().IsZero ())
689  {
690  NS_ASSERT (txParams.m_acknowledgment && txParams.m_acknowledgment->acknowledgmentTime != Time::Min ());
691  return txParams.m_acknowledgment->acknowledgmentTime;
692  }
693 
694  // under multiple protection settings, if the TXOP limit is not null, Duration/ID
695  // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
696  // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
697  // of 802.11-2016)
698  return std::max (m_edca->GetRemainingTxop () - txDuration, Seconds (0));
699 }
700 
701 void
703 {
704  NS_LOG_FUNCTION (this << psdu << &txParams);
705 
706  m_psdu = psdu;
707  m_txParams = std::move (txParams);
708 
709 #ifdef NS3_BUILD_PROFILE_DEBUG
710  // If protection is required, the MPDUs must be stored in some queue because
711  // they are not put back in a queue if the RTS/CTS exchange fails
713  {
714  for (const auto& mpdu : *PeekPointer (m_psdu))
715  {
716  NS_ASSERT (mpdu->GetHeader ().IsCtl () || mpdu->IsQueued ());
717  }
718  }
719 #endif
720 
721  // Make sure that the acknowledgment time has been computed, so that SendRts()
722  // and SendCtsToSelf() can reuse this value.
724 
725  if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min ())
726  {
728  }
729 
730  // Set QoS Ack policy
732 
734  {
736  }
738  {
740  }
741  else if (m_txParams.m_protection->method == WifiProtection::NONE)
742  {
743  SendPsdu ();
744  }
745  else
746  {
747  NS_ABORT_MSG ("Unknown protection type");
748  }
749 }
750 
751 void
753 {
754  NS_LOG_FUNCTION (this << *rts << txVector);
755 
756  if (m_psdu == 0)
757  {
758  // A CTS Timeout occurred when protecting a single MPDU is handled by the
759  // parent classes
760  QosFrameExchangeManager::CtsTimeout (rts, txVector);
761  return;
762  }
763 
764  NS_ASSERT (m_psdu->GetNMpdus () > 1);
765  m_mac->GetWifiRemoteStationManager ()->ReportRtsFailed (m_psdu->GetHeader (0));
766 
767  if (!m_mac->GetWifiRemoteStationManager ()->NeedRetransmission (*m_psdu->begin ()))
768  {
769  NS_LOG_DEBUG ("Missed CTS, discard MPDUs");
770  m_mac->GetWifiRemoteStationManager ()->ReportFinalRtsFailed (m_psdu->GetHeader (0));
771  // Dequeue the MPDUs if they are stored in a queue
773  for (const auto& mpdu : *PeekPointer (m_psdu))
774  {
775  NotifyPacketDiscarded (mpdu);
776  }
777  m_edca->ResetCw ();
778  }
779  else
780  {
781  NS_LOG_DEBUG ("Missed CTS, retransmit MPDUs");
782  for (const auto& mpdu : *PeekPointer (m_psdu))
783  {
785  }
787  }
788  m_psdu = 0;
790 }
791 
792 void
794 {
795  NS_LOG_FUNCTION (this);
796 
798 
800 
802  {
804  }
806  {
808 
809  // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
810  // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
811  // aRxPHYStartDelay equals the time to transmit the PHY header.
812  WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*> (m_txParams.m_acknowledgment.get ());
813 
814  Time timeout = txDuration
815  + m_phy->GetSifs ()
816  + m_phy->GetSlot ()
820  this, m_psdu, m_txParams.m_txVector);
821  m_channelAccessManager->NotifyAckTimeoutStartNow (timeout);
822  }
824  {
826 
827  // schedule the transmission of a BAR in a SIFS
828  std::set<uint8_t> tids = m_psdu->GetTids ();
829  NS_ABORT_MSG_IF (tids.size () > 1, "Acknowledgment method incompatible with a Multi-TID A-MPDU");
830  uint8_t tid = *tids.begin ();
831 
832  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
833  edca->ScheduleBar (edca->PrepareBlockAckRequest (m_psdu->GetAddr1 (), tid));
834 
836  }
837  else
838  {
839  NS_ABORT_MSG ("Unable to handle the selected acknowledgment method ("
840  << m_txParams.m_acknowledgment.get () << ")");
841  }
842 
843  // transmit the PSDU
844  if (m_psdu->GetNMpdus () > 1)
845  {
847  }
848  else
849  {
851  }
852 
854  {
855  // we are done in case the A-MPDU does not require acknowledgment
856  m_psdu = 0;
857  }
858 }
859 
860 void
862 {
863  NS_LOG_FUNCTION (this << psdu);
864 
865  for (const auto& mpdu : *PeekPointer (psdu))
866  {
867  if (mpdu->GetHeader ().IsQosData ())
868  {
869  Ptr<QosTxop> edca = m_mac->GetQosTxop (mpdu->GetHeader ().GetQosTid ());
870 
871  if (mpdu->GetHeader ().IsQosEosp ())
872  {
873  edca->SetQosQueueSize (mpdu);
874  }
875  if (mpdu->GetHeader ().HasData ())
876  {
877  edca->CompleteMpduTx (mpdu);
878  }
879  }
880  }
881 }
882 
883 void
885 {
886  DequeuePsdu (Create<const WifiPsdu> (mpdu, true));
887 }
888 
889 void
891 {
892  NS_LOG_DEBUG (this << psdu);
893 
894  for (const auto& mpdu : *PeekPointer (psdu))
895  {
896  if (mpdu->GetQueueIteratorPairs ().size () > 1)
897  {
898  // this MPDU contains an A-MSDU
899  for (const auto& queueIt : mpdu->GetQueueIteratorPairs ())
900  {
901  NS_ASSERT (*queueIt.it != mpdu);
902  queueIt.queue->Dequeue (queueIt.it);
903  }
904  }
905  else if (mpdu->IsQueued ())
906  {
907  WifiMacQueueItem::QueueIteratorPair queueIt = mpdu->GetQueueIteratorPairs ().front ();
908  NS_ASSERT (*queueIt.it == mpdu);
909  queueIt.queue->Dequeue (queueIt.it);
910  }
911  }
912 }
913 
914 void
916 {
917  NS_LOG_FUNCTION (this << psdu << txVector);
918 
919  NS_LOG_DEBUG ("Transmitting a PSDU: " << *psdu << " TXVECTOR: " << txVector);
920  NotifyTxToEdca (psdu);
921 
922  if (psdu->IsAggregate ())
923  {
924  txVector.SetAggregation (true);
925  }
926 
927  // The PSDU is about to be transmitted, we can now dequeue the MPDUs
928  DequeuePsdu (psdu);
929 
930  m_phy->Send (psdu, txVector);
931 }
932 
933 bool
935  const WifiTxParameters& txParams,
936  Time ppduDurationLimit) const
937 {
938  NS_ASSERT (mpdu != 0);
939  NS_LOG_FUNCTION (this << *mpdu << &txParams << ppduDurationLimit);
940 
941  Mac48Address receiver = mpdu->GetHeader ().GetAddr1 ();
942  uint32_t ampduSize = txParams.GetSizeIfAddMpdu (mpdu);
943 
944  if (txParams.GetSize (receiver) > 0)
945  {
946  // we are attempting to perform A-MPDU aggregation, hence we have to check
947  // that we meet the limit on the max A-MPDU size
948  uint8_t tid;
949  const WifiTxParameters::PsduInfo* info;
950 
951  if (mpdu->GetHeader ().IsQosData ())
952  {
953  tid = mpdu->GetHeader ().GetQosTid ();
954  }
955  else if ((info = txParams.GetPsduInfo (receiver)) && !info->seqNumbers.empty ())
956  {
957  tid = info->seqNumbers.begin ()->first;
958  }
959  else
960  {
961  NS_ABORT_MSG ("Cannot aggregate a non-QoS data frame to an A-MPDU that does"
962  " not contain any QoS data frame");
963  }
964 
965  WifiModulationClass modulation = txParams.m_txVector.GetModulationClass ();
966 
967  if (!IsWithinAmpduSizeLimit (ampduSize, receiver, tid, modulation))
968  {
969  return false;
970  }
971  }
972 
973  return IsWithinSizeAndTimeLimits (ampduSize, receiver, txParams, ppduDurationLimit);
974 }
975 
976 bool
977 HtFrameExchangeManager::IsWithinAmpduSizeLimit (uint32_t ampduSize, Mac48Address receiver, uint8_t tid,
978  WifiModulationClass modulation) const
979 {
980  NS_LOG_FUNCTION (this << ampduSize << receiver << +tid << modulation);
981 
982  uint32_t maxAmpduSize = m_mpduAggregator->GetMaxAmpduSize (receiver, tid, modulation);
983 
984  if (maxAmpduSize == 0)
985  {
986  NS_LOG_DEBUG ("A-MPDU aggregation disabled");
987  return false;
988  }
989 
990  if (ampduSize > maxAmpduSize)
991  {
992  NS_LOG_DEBUG ("the frame does not meet the constraint on max A-MPDU size ("
993  << maxAmpduSize << ")");
994  return false;
995  }
996  return true;
997 }
998 
999 bool
1001  Time availableTime) const
1002 {
1003  NS_ASSERT (msdu != 0 && msdu->GetHeader ().IsQosData ());
1004  NS_LOG_FUNCTION (this << *msdu << &txParams << availableTime);
1005 
1006  // check if aggregating the given MSDU requires a different protection method
1007  NS_ASSERT (txParams.m_protection);
1008  Time protectionTime = txParams.m_protection->protectionTime;
1009 
1010  std::unique_ptr<WifiProtection> protection;
1011  protection = GetProtectionManager ()->TryAggregateMsdu (msdu, txParams);
1012  bool protectionSwapped = false;
1013 
1014  if (protection)
1015  {
1016  // the protection method has changed, calculate the new protection time
1017  CalculateProtectionTime (protection.get ());
1018  protectionTime = protection->protectionTime;
1019  // swap unique pointers, so that the txParams that is passed to the next
1020  // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1021  txParams.m_protection.swap (protection);
1022  protectionSwapped = true;
1023  }
1024  NS_ASSERT (protectionTime != Time::Min ());
1025 
1026  // check if aggregating the given MSDU requires a different acknowledgment method
1027  NS_ASSERT (txParams.m_acknowledgment);
1028  Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
1029 
1030  std::unique_ptr<WifiAcknowledgment> acknowledgment;
1031  acknowledgment = GetAckManager ()->TryAggregateMsdu (msdu, txParams);
1032  bool acknowledgmentSwapped = false;
1033 
1034  if (acknowledgment)
1035  {
1036  // the acknowledgment method has changed, calculate the new acknowledgment time
1037  CalculateAcknowledgmentTime (acknowledgment.get ());
1038  acknowledgmentTime = acknowledgment->acknowledgmentTime;
1039  // swap unique pointers, so that the txParams that is passed to the next
1040  // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1041  txParams.m_acknowledgment.swap (acknowledgment);
1042  acknowledgmentSwapped = true;
1043  }
1044  NS_ASSERT (acknowledgmentTime != Time::Min ());
1045 
1046  Time ppduDurationLimit = Time::Min ();
1047  if (availableTime != Time::Min ())
1048  {
1049  ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
1050  }
1051 
1052  if (!IsWithinLimitsIfAggregateMsdu (msdu, txParams, ppduDurationLimit))
1053  {
1054  // adding MPDU failed, restore protection and acknowledgment methods
1055  // if they were swapped
1056  if (protectionSwapped)
1057  {
1058  txParams.m_protection.swap (protection);
1059  }
1060  if (acknowledgmentSwapped)
1061  {
1062  txParams.m_acknowledgment.swap (acknowledgment);
1063  }
1064  return false;
1065  }
1066 
1067  // the given MPDU can be added, hence update the txParams
1068  txParams.AggregateMsdu (msdu);
1069  UpdateTxDuration (msdu->GetHeader ().GetAddr1 (), txParams);
1070 
1071  return true;
1072 }
1073 
1074 bool
1076  const WifiTxParameters& txParams,
1077  Time ppduDurationLimit) const
1078 {
1079  NS_ASSERT (msdu != 0 && msdu->GetHeader ().IsQosData ());
1080  NS_LOG_FUNCTION (this << *msdu << &txParams << ppduDurationLimit);
1081 
1082  std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu (msdu);
1083  Mac48Address receiver = msdu->GetHeader ().GetAddr1 ();
1084  uint8_t tid = msdu->GetHeader ().GetQosTid ();
1085  WifiModulationClass modulation = txParams.m_txVector.GetModulationClass ();
1086 
1087  // Check that the limit on A-MSDU size is met
1088  uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize (receiver, tid, modulation);
1089 
1090  if (maxAmsduSize == 0)
1091  {
1092  NS_LOG_DEBUG ("A-MSDU aggregation disabled");
1093  return false;
1094  }
1095 
1096  if (ret.first > maxAmsduSize)
1097  {
1098  NS_LOG_DEBUG ("No other MSDU can be aggregated: maximum A-MSDU size ("
1099  << maxAmsduSize << ") reached ");
1100  return false;
1101  }
1102 
1103  const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo (msdu->GetHeader ().GetAddr1 ());
1104  NS_ASSERT (info != nullptr);
1105 
1106  if (info->ampduSize > 0)
1107  {
1108  // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
1109  // Check that the limit on A-MPDU size is met.
1110  if (!IsWithinAmpduSizeLimit (ret.second, receiver, tid, modulation))
1111  {
1112  return false;
1113  }
1114  }
1115 
1116  return IsWithinSizeAndTimeLimits (ret.second, receiver, txParams, ppduDurationLimit);
1117 }
1118 
1119 void
1121 {
1122  NS_LOG_FUNCTION (this << *psdu << txVector);
1123 
1124  m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psdu->begin ());
1125 
1126  bool resetCw;
1127  MissedBlockAck (psdu, txVector, resetCw);
1128 
1129  NS_ASSERT (m_edca != 0);
1130 
1131  if (resetCw)
1132  {
1133  m_edca->ResetCw ();
1134  }
1135  else
1136  {
1137  m_edca->UpdateFailedCw ();
1138  }
1139 
1140  m_psdu = 0;
1141  TransmissionFailed ();
1142 }
1143 
1144 void
1146 {
1147  NS_LOG_FUNCTION (this << psdu << txVector << resetCw);
1148 
1149  Mac48Address recipient = psdu->GetAddr1 ();
1150  bool isBar;
1151  uint8_t tid;
1152 
1153  if (psdu->GetNMpdus () == 1 && psdu->GetHeader (0).IsBlockAckReq ())
1154  {
1155  isBar = true;
1156  CtrlBAckRequestHeader baReqHdr;
1157  psdu->GetPayload (0)->PeekHeader (baReqHdr);
1158  tid = baReqHdr.GetTidInfo ();
1159  }
1160  else
1161  {
1162  isBar = false;
1163  m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (recipient, 0, psdu->GetNMpdus (),
1164  0, 0, txVector);
1165  std::set<uint8_t> tids = psdu->GetTids ();
1166  NS_ABORT_MSG_IF (tids.size () > 1, "Multi-TID A-MPDUs not handled here");
1167  NS_ASSERT (!tids.empty ());
1168  tid = *tids.begin ();
1169  }
1170 
1171  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
1172 
1173  if (edca->UseExplicitBarAfterMissedBlockAck () || isBar)
1174  {
1175  // we have to send a BlockAckReq, if needed
1176  if (GetBaManager (tid)->NeedBarRetransmission (tid, recipient))
1177  {
1178  NS_LOG_DEBUG ("Missed Block Ack, transmit a BlockAckReq");
1179  if (isBar)
1180  {
1181  psdu->GetHeader (0).SetRetry ();
1182  edca->ScheduleBar (*psdu->begin ());
1183  }
1184  else
1185  {
1186  // missed block ack after data frame with Implicit BAR Ack policy
1187  edca->ScheduleBar (edca->PrepareBlockAckRequest (recipient, tid));
1188  }
1189  resetCw = false;
1190  }
1191  else
1192  {
1193  NS_LOG_DEBUG ("Missed Block Ack, do not transmit a BlockAckReq");
1194  // if a BA agreement exists, we can get here if there is no outstanding
1195  // MPDU whose lifetime has not expired yet.
1196  m_mac->GetWifiRemoteStationManager ()->ReportFinalDataFailed (*psdu->begin ());
1197  if (GetBaManager (tid)->ExistsAgreementInState (recipient, tid,
1199  {
1200  // If there is any (expired) outstanding MPDU, request the BA manager to discard
1201  // it, which involves the scheduling of a BAR to advance the recipient's window
1202  if (GetBaManager (tid)->GetNBufferedPackets (recipient, tid) > 0)
1203  {
1204  GetBaManager (tid)->DiscardOutstandingMpdus (recipient, tid);
1205  }
1206  // otherwise, it means that we have not received a Block Ack in response to a
1207  // BlockAckRequest sent while no frame was outstanding, whose purpose was therefore
1208  // to advance the recipient's window. Schedule a BlockAckRequest with
1209  // skipIfNoDataQueued set to true, so that the BlockAckRequest is only sent
1210  // if there are data frames queued for this recipient.
1211  else
1212  {
1213  edca->ScheduleBar (edca->PrepareBlockAckRequest (recipient, tid), true);
1214  }
1215  }
1216  resetCw = true;
1217  }
1218  }
1219  else
1220  {
1221  // we have to retransmit the data frames, if needed
1222  if (!m_mac->GetWifiRemoteStationManager ()->NeedRetransmission (*psdu->begin ()))
1223  {
1224  NS_LOG_DEBUG ("Missed Block Ack, do not retransmit the data frames");
1225  m_mac->GetWifiRemoteStationManager ()->ReportFinalDataFailed (*psdu->begin ());
1226  for (const auto& mpdu : *PeekPointer (psdu))
1227  {
1229  }
1230  GetBaManager (tid)->DiscardOutstandingMpdus (recipient, tid);
1231  resetCw = true;
1232  }
1233  else
1234  {
1235  NS_LOG_DEBUG ("Missed Block Ack, retransmit data frames");
1236  GetBaManager (tid)->NotifyMissedBlockAck (recipient, tid);
1237  resetCw = false;
1238  }
1239  }
1240 }
1241 
1242 void
1244  WifiTxVector& blockAckTxVector, double rxSnr)
1245 {
1246  NS_LOG_FUNCTION (this << durationId << blockAckTxVector << rxSnr);
1247 
1248  WifiMacHeader hdr;
1250  hdr.SetAddr1 (agreement.GetPeer ());
1251  hdr.SetAddr2 (m_self);
1252  hdr.SetDsNotFrom ();
1253  hdr.SetDsNotTo ();
1254 
1255  CtrlBAckResponseHeader blockAck;
1256  blockAck.SetType (agreement.GetBlockAckType ());
1257  blockAck.SetTidInfo (agreement.GetTid ());
1258  agreement.FillBlockAckBitmap (&blockAck);
1259 
1260  Ptr<Packet> packet = Create<Packet> ();
1261  packet->AddHeader (blockAck);
1262  Ptr<WifiPsdu> psdu = GetWifiPsdu (Create<WifiMacQueueItem> (packet, hdr), blockAckTxVector);
1263 
1264  // 802.11-2016, Section 9.2.5.7: In a BlockAck frame transmitted in response
1265  // to a BlockAckReq frame or transmitted in response to a frame containing an
1266  // implicit block ack request, the Duration/ID field is set to the value obtained
1267  // from the Duration/ ID field of the frame that elicited the response minus the
1268  // time, in microseconds between the end of the PPDU carrying the frame that
1269  // elicited the response and the end of the PPDU carrying the BlockAck frame.
1270  Time baDurationId = durationId - m_phy->GetSifs ()
1271  - m_phy->CalculateTxDuration (psdu, blockAckTxVector, m_phy->GetPhyBand ());
1272  // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1273  if (baDurationId.IsStrictlyNegative ())
1274  {
1275  baDurationId = Seconds (0);
1276  }
1277  psdu->GetHeader (0).SetDuration (baDurationId);
1278 
1279  SnrTag tag;
1280  tag.Set (rxSnr);
1281  psdu->GetPayload (0)->AddPacketTag (tag);
1282 
1283  ForwardPsduDown (psdu, blockAckTxVector);
1284 }
1285 
1286 bool
1288 {
1289  return (m_agreements.find ({originator, tid}) != m_agreements.end ());
1290 }
1291 
1294 {
1295  auto it = m_agreements.find ({originator, tid});
1296  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
1297  return it->second.GetBlockAckType ();
1298 }
1299 
1300 void
1302  const WifiTxVector& txVector, bool inAmpdu)
1303 {
1304  // The received MPDU is either broadcast or addressed to this station
1305  NS_ASSERT (mpdu->GetHeader ().GetAddr1 ().IsGroup ()
1306  || mpdu->GetHeader ().GetAddr1 () == m_self);
1307 
1308  double rxSnr = rxSignalInfo.snr;
1309  const WifiMacHeader& hdr = mpdu->GetHeader ();
1310 
1311  if (hdr.IsCtl ())
1312  {
1314  && m_psdu != 0)
1315  {
1316  NS_ABORT_MSG_IF (inAmpdu, "Received CTS as part of an A-MPDU");
1317  NS_ASSERT (hdr.GetAddr1 () == m_self);
1318 
1319  Mac48Address sender = m_psdu->GetAddr1 ();
1320  NS_LOG_DEBUG ("Received CTS from=" << sender);
1321 
1322  SnrTag tag;
1323  mpdu->GetPacket ()->PeekPacketTag (tag);
1324  m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1325  m_mac->GetWifiRemoteStationManager ()->ReportRtsOk (m_psdu->GetHeader (0),
1326  rxSnr, txVector.GetMode (), tag.Get ());
1327 
1328  m_txTimer.Cancel ();
1329  m_channelAccessManager->NotifyCtsTimeoutResetNow ();
1331  }
1332  else if (hdr.IsBlockAck () && m_txTimer.IsRunning ()
1334  && hdr.GetAddr1 () == m_self)
1335  {
1336  Mac48Address sender = hdr.GetAddr2 ();
1337  NS_LOG_DEBUG ("Received BlockAck from=" << sender);
1338 
1339  SnrTag tag;
1340  mpdu->GetPacket ()->PeekPacketTag (tag);
1341 
1342  // notify the Block Ack Manager
1343  CtrlBAckResponseHeader blockAck;
1344  mpdu->GetPacket ()->PeekHeader (blockAck);
1345  uint8_t tid = blockAck.GetTidInfo ();
1346  GetBaManager (tid)->NotifyGotBlockAck (blockAck, hdr.GetAddr2 (), {tid}, rxSnr,
1347  tag.Get (), m_txParams.m_txVector);
1348 
1349  // cancel the timer
1350  m_txTimer.Cancel ();
1351  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1352 
1353  // Reset the CW
1354  m_edca->ResetCw ();
1355 
1356  m_psdu = 0;
1358  }
1359  else if (hdr.IsBlockAckReq ())
1360  {
1361  NS_ASSERT (hdr.GetAddr1 () == m_self);
1362  NS_ABORT_MSG_IF (inAmpdu, "BlockAckReq in A-MPDU is not supported");
1363 
1364  Mac48Address sender = hdr.GetAddr2 ();
1365  NS_LOG_DEBUG ("Received BlockAckReq from=" << sender);
1366 
1367  CtrlBAckRequestHeader blockAckReq;
1368  mpdu->GetPacket ()->PeekHeader (blockAckReq);
1369  NS_ABORT_MSG_IF (blockAckReq.IsMultiTid (), "Multi-TID BlockAckReq not supported");
1370  uint8_t tid = blockAckReq.GetTidInfo ();
1371 
1372  auto agreementIt = m_agreements.find ({sender, tid});
1373 
1374  if (agreementIt == m_agreements.end ())
1375  {
1376  NS_LOG_DEBUG ("There's not a valid agreement for this BlockAckReq");
1377  return;
1378  }
1379 
1380  agreementIt->second.NotifyReceivedBar (blockAckReq.GetStartingSequence ());
1381 
1382  NS_LOG_DEBUG ("Schedule Block Ack");
1384  agreementIt->second, hdr.GetDuration (),
1385  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (sender, txVector),
1386  rxSnr);
1387  }
1388  else
1389  {
1390  // the received control frame cannot be handled here
1391  QosFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1392  }
1393  return;
1394  }
1395 
1396  if (hdr.IsQosData () && hdr.HasData () && hdr.GetAddr1 () == m_self)
1397  {
1398  uint8_t tid = hdr.GetQosTid ();
1399 
1400  auto agreementIt = m_agreements.find ({hdr.GetAddr2 (), tid});
1401  if (agreementIt != m_agreements.end ())
1402  {
1403  // a Block Ack agreement has been established
1404  NS_LOG_DEBUG ("Received from=" << hdr.GetAddr2 ()
1405  << " (" << *mpdu << ")");
1406 
1407  agreementIt->second.NotifyReceivedMpdu (mpdu);
1408 
1409  if (!inAmpdu && hdr.GetQosAckPolicy () == WifiMacHeader::NORMAL_ACK)
1410  {
1411  NS_LOG_DEBUG ("Schedule Normal Ack");
1413  this, hdr, txVector, rxSnr);
1414  }
1415  return;
1416  }
1417  // We let the QosFrameExchangeManager handle QoS data frame not belonging
1418  // to a Block Ack agreement
1419  }
1420 
1421  QosFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1422 }
1423 
1424 void
1426  const WifiTxVector& txVector, const std::vector<bool>& perMpduStatus)
1427 {
1428  std::set<uint8_t> tids = psdu->GetTids ();
1429 
1430  // Multi-TID A-MPDUs are not supported yet
1431  if (tids.size () == 1)
1432  {
1433  uint8_t tid = *tids.begin ();
1434  WifiMacHeader::QosAckPolicy ackPolicy = psdu->GetAckPolicyForTid (tid);
1435  NS_ASSERT (psdu->GetNMpdus () > 1);
1436 
1437  if (ackPolicy == WifiMacHeader::NORMAL_ACK)
1438  {
1439  // Normal Ack or Implicit Block Ack Request
1440  NS_LOG_DEBUG ("Schedule Block Ack");
1441  auto agreementIt = m_agreements.find ({psdu->GetAddr2 (), tid});
1442  NS_ASSERT (agreementIt != m_agreements.end ());
1443 
1445  agreementIt->second, psdu->GetDuration (),
1446  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (psdu->GetAddr2 (), txVector),
1447  rxSignalInfo.snr);
1448  }
1449  }
1450 }
1451 
1452 } //namespace ns3
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802...
virtual Ptr< WifiPsdu > GetWifiPsdu(Ptr< WifiMacQueueItem > mpdu, const WifiTxVector &txVector) const
Get a PSDU containing the given MPDU.
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:280
void Set(double snr)
Set the SNR to the given value.
Definition: snr-tag.cc:83
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
Definition: qos-txop.cc:201
bool IsRetry(void) const
Return if the Retry bit is set.
void SetRetry(void)
Set the Retry bit in the Frame Control field.
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:557
Ptr< const WifiMacQueueItem > PeekNextMpdu(uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast())
Peek the next frame to transmit to the given receiver and of the given TID from the block ack manager...
Definition: qos-txop.cc:277
virtual bool IsWithinLimitsIfAggregateMsdu(Ptr< const WifiMacQueueItem > msdu, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check if the PSDU obtained by aggregating the given MSDU to the PSDU specified by the given TX parame...
uint16_t GetTimeout(void) const
Return the timeout.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void SendCtsToSelf(const WifiTxParameters &txParams)
Send CTS for a CTS-to-self mechanism.
void ResetBa(Mac48Address recipient, uint8_t tid)
Reset BA agreement after BA negotiation failed.
Definition: qos-txop.cc:738
WifiTxTimer m_txTimer
the timer set upon frame transmission
void ForwardMpduDown(Ptr< WifiMacQueueItem > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SendMpduWithProtection(Ptr< WifiMacQueueItem > mpdu, WifiTxParameters &txParams)
Send an MPDU with the given TX parameters (with the specified protection).
void SendPsduWithProtection(Ptr< WifiPsdu > psdu, WifiTxParameters &txParams)
Send a PSDU (A-MPDU or BlockAckReq frame) requesting a BlockAck frame or a BlockAckReq frame followed...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Definition: wifi-psdu.cc:156
void SendBlockAck(const RecipientBlockAckAgreement &agreement, Time durationId, WifiTxVector &blockAckTxVector, double rxSnr)
Create a BlockAck frame with header equal to blockAck and start its transmission. ...
Ptr< WifiProtectionManager > GetProtectionManager(void) const
Get the Protection Manager used by this node.
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method...
Ptr< WifiPhy > m_phy
the PHY layer on this station
void SetDuration(Time duration)
Set the Duration/ID field with the given duration (Time object).
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:274
bool IsCtl(void) const
Return true if the Type is Control.
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
Definition: mgt-headers.h:857
void CreateBlockAckAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address originator, uint16_t startingSeq)
virtual void MissedBlockAck(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector, bool &resetCw)
Take necessary actions when a BlockAck is missed, such as scheduling a BlockAckReq frame or the retra...
WifiPhyBand GetPhyBand(void) const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1124
std::unique_ptr< WifiProtection > m_protection
protection method
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
Maintains the scoreboard and the receive reordering buffer used by a recipient of a Block Ack agreeme...
void AggregateMsdu(Ptr< const WifiMacQueueItem > msdu)
Record that an MSDU is being aggregated to the last MPDU added to the frame that hase the same receiv...
void Clear(void)
Reset the TX parameters.
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:990
Time acknowledgmentTime
time required by the acknowledgment method
WifiAcknowledgment is an abstract base struct.
virtual bool NeedSetupBlockAck(Mac48Address recipient, uint8_t tid)
A Block Ack agreement needs to be established with the given recipient for the given TID if it does n...
WifiModulationClass GetModulationClass(void) const
Get the modulation class specified by this TXVECTOR.
virtual bool TryAggregateMsdu(Ptr< const WifiMacQueueItem > msdu, WifiTxParameters &txParams, Time availableTime) const
Check if aggregating an MSDU to the current MPDU (as specified by the given TX parameters) does not v...
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:411
Information needed to remove an MSDU from the queue.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
ConstIterator it
iterator pointing to the MSDU in the queue
virtual void CalculateProtectionTime(WifiProtection *protection) const
Calculate the time required to protect a frame according to the given protection method.
Ptr< BlockAckManager > GetBaManager(void)
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:155
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:813
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:173
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
uint16_t GetBufferSize(void) const
Return the buffer size.
CategoryValue GetCategory()
Return the category value.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
void SetDelayedBlockAck()
Enable delayed BlockAck.
ns3::Time timeout
virtual Time GetRemainingTxop(void) const
Return the remaining duration in the current TXOP.
Definition: qos-txop.cc:598
WifiTxVector blockAckReqTxVector
BlockAckReq TXVECTOR.
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
void SetStatusCode(StatusCode code)
Set the status code.
uint8_t GetBlockAckThreshold(void) const
Return the current threshold for block ack mechanism.
Definition: qos-txop.cc:700
uint16_t GetTimeout(void) const
Return the timeout.
bool UseExplicitBarAfterMissedBlockAck(void) const
Return true if an explicit BlockAckRequest is sent after a missed BlockAck.
Definition: qos-txop.cc:215
const Method method
acknowledgment method
virtual void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const
Calculate the time required to acknowledge a frame according to the given acknowledgment method...
virtual void CtsTimeout(Ptr< WifiMacQueueItem > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
void SetTimeout(uint16_t timeout)
Set timeout.
Ptr< WifiAckManager > GetAckManager(void) const
Get the Acknowledgment Manager used by this node.
double Get(void) const
Return the SNR value.
Definition: snr-tag.cc:89
BlockAckType baType
BlockAck type.
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
Ptr< RegularWifiMac > m_mac
the MAC layer on this station
Ptr< MsduAggregator > m_msduAggregator
A-MSDU aggregator.
void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
bool IsBlockAck(void) const
Return true if the header is a BlockAck header.
uint32_t GetSize(void) const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:260
bool StartTransmission(Ptr< Txop > edca) override
Request the FrameExchangeManager to start a frame exchange sequence.
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
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...
void DoDispose() override
Destructor implementation.
void SetTid(uint8_t tid)
Set Traffic ID (TID).
void DestroyBlockAckAgreement(Mac48Address originator, uint8_t tid)
Destroy a Block Ack agreement.
Ptr< WifiPsdu > m_psdu
the A-MPDU being transmitted
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1610
uint8_t GetTid(void) const
Return the Traffic ID (TID).
bool IsBlockAckReq(void) const
Return true if the header is a BlockAckRequest header.
bool IsByOriginator(void) const
Check if the initiator bit in the DELBA is set.
void UpdateFailedCw(void)
Update the value of the CW variable to take into account a transmission failure.
Definition: txop.cc:195
Time GetAddBaResponseTimeout(void) const
Get the timeout for ADDBA response.
Definition: qos-txop.cc:760
bool IsAction(void) const
Return true if the header is an Action header.
void SetWifiMac(const Ptr< RegularWifiMac > mac) override
Set the MAC layer to use.
void TransmissionSucceeded(void) override
Take necessary actions upon a transmission success.
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:66
void SetSuccess(void)
Set success bit to 0 (success).
Definition: status-code.cc:30
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
Mac48Address m_bssid
BSSID address (Mac48Address)
const WifiMacHeader & GetHeader(void) const
Get the header stored in this item.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
#define max(a, b)
Definition: 80211b.c:43
void Set(Reason reason, const Time &delay, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
bool IsZero(void) const
Exactly equivalent to t == 0.
Definition: nstime.h:301
QosFrameExchangeManager handles the frame exchange sequences for QoS stations.
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
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...
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
uint16_t GetBlockAckInactivityTimeout(void) const
Get the BlockAck inactivity timeout.
Definition: qos-txop.cc:707
Reason GetReason(void) const
Get the reason why the timer was started.
void SetImmediateBlockAck()
Enable immediate BlockAck.
mac
Definition: third.py:99
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present...
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
void DequeueMpdu(Ptr< WifiMacQueueItem > mpdu) override
Dequeue the given MPDU from the queue in which it is stored.
bool IsCts(void) const
Return true if the header is a CTS header.
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:290
Headers for BlockAck response.
Definition: ctrl-headers.h:201
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
Time GetDuration(void) const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
Definition: wifi-psdu.cc:141
Mac48Address GetAddr2(void) const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:126
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
Definition: wifi-utils.cc:182
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:266
virtual void NotifyPacketDiscarded(Ptr< const WifiMacQueueItem > mpdu)
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
Mac48Address GetPeer(void) const
Return the peer address.
Mac48Address m_self
the MAC address of this device
virtual bool IsWithinAmpduSizeLimit(uint32_t ampduSize, Mac48Address receiver, uint8_t tid, WifiModulationClass modulation) const
Check whether an A-MPDU of the given size meets the constraint on the maximum size for A-MPDUs sent t...
Mac48Address GetAddr2(void) const
Return the address in the Address 2 field.
virtual void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Called when the BlockAck timeout expires.
void SetByOriginator(void)
Set the initiator bit in the DELBA.
Ptr< const Packet > GetPacket(void) const
Get the packet stored in this item.
Status code for association response.
Definition: status-code.h:31
void SetByRecipient(void)
Un-set the initiator bit in the DELBA.
void TransmissionSucceeded(void) override
Take necessary actions upon a transmission success.
void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus) override
This method is called when the reception of an A-MPDU including multiple MPDUs is completed...
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
std::size_t GetNMpdus(void) const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:319
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
void SendPsdu(void)
Send the current PSDU, which can be acknowledged by a BlockAck frame or followed by a BlockAckReq fra...
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
void RetransmitMpduAfterMissedCts(Ptr< WifiMacQueueItem > mpdu) const override
Retransmit an MPDU that was not sent because a CTS was not received.
Ptr< WifiMacQueueItem > Dequeue(void) override
Dequeue the packet in the front of the queue.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
Time GetDuration(void) const
Return the duration from the Duration/ID field (Time object).
void SetBufferSize(uint16_t size)
Set buffer size.
void CompleteMpduTx(Ptr< WifiMacQueueItem > mpdu)
Stores an MPDU (part of an A-MPDU) in block ack agreement (i.e.
Definition: qos-txop.cc:674
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
void SetType(BlockAckType type)
Set the block ack type.
void RetransmitMpduAfterMissedAck(Ptr< WifiMacQueueItem > mpdu) const override
Retransmit an MPDU that was not acknowledged.
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
bool IsMultiTid(void) const
Check if the current Ack Policy has Multi-TID Block Ack.
std::set< uint8_t > GetTids(void) const
Get the set of TIDs of the QoS Data frames included in the PSDU.
Definition: wifi-psdu.cc:166
void Cancel(void)
Cancel the timer.
an EUI-48 address
Definition: mac48-address.h:43
bool IsRunning(void) const
Return true if the timer is running.
static void SetQosAckPolicy(Ptr< WifiMacQueueItem > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
void DoDispose() override
Destructor implementation.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
uint8_t GetTid(Ptr< const Packet > packet, const WifiMacHeader hdr)
This function is useful to get traffic id of different packet types.
Definition: qos-utils.cc:187
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
bool IsWithinLimitsIfAddMpdu(Ptr< const WifiMacQueueItem > mpdu, const WifiTxParameters &txParams, Time ppduDurationLimit) const override
Check if the PSDU obtained by aggregating the given MPDU to the PSDU specified by the given TX parame...
virtual Time GetPsduDurationId(Time txDuration, const WifiTxParameters &txParams) const
Compute how to set the Duration/ID field of PSDUs that do not include fragments.
WifiBlockAck specifies that acknowledgment via Block Ack is required.
information about the frame being prepared for a specific receiver
void SetTid(uint8_t tid)
Set Traffic ID (TID).
bool IsGroup(void) const
virtual uint16_t GetSupportedBaBufferSize(void) const
Get the maximum supported buffer size for a Block Ack agreement.
QosAckPolicy
Ack policy for QoS frames.
virtual void SetWifiMac(const Ptr< RegularWifiMac > mac)
Set the MAC layer to use.
void SendNormalAck(const WifiMacHeader &hdr, const WifiTxVector &dataTxVector, double dataSnr)
Send Normal Ack.
std::map< AgreementKey, RecipientBlockAckAgreement > m_agreements
agreements
WifiTxParameters m_txParams
the TX parameters for the current frame
virtual void NotifyTxToEdca(Ptr< const WifiPsdu > psdu) const
Notify the transmission of the given PSDU to the EDCAF associated with the AC the PSDU belongs to...
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
Ptr< BlockAckManager > GetBaManager(uint8_t tid) const
Get the Block Ack Manager handling the given TID.
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:77
Ptr< MpduAggregator > GetMpduAggregator(void) const
Returns the aggregator used to construct A-MPDU subframes.
WifiMacQueue * queue
pointer to the queue where the MSDU is enqueued
void SetQosQueueSize(Ptr< WifiMacQueueItem > mpdu)
Set the Queue Size subfield of the QoS Control field of the given QoS data frame. ...
Definition: qos-txop.cc:122
The different BlockAck variants.
void FillBlockAckBitmap(CtrlBAckResponseHeader *blockAckHeader, std::size_t index=0) const
Set the Starting Sequence Number subfield of the Block Ack Starting Sequence Control subfield of the ...
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:910
void ReceiveMpdu(Ptr< WifiMacQueueItem > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:956
Ptr< MsduAggregator > GetMsduAggregator(void) const
Returns the aggregator used to construct A-MSDU subframes.
BlockAckActionValue blockAck
block ack
Definition: mgt-headers.h:933
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
BlockAckType GetBlockAckType(void) const
Get the type of the Block Acks sent by the recipient of this agreement.
double snr
SNR in linear scale.
Definition: phy-entity.h:68
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1122
BlockAckType baType
BlockAck type.
bool IsStrictlyNegative(void) const
Exactly equivalent to t < 0.
Definition: nstime.h:325
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMacQueueItem > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
Implement the header for management frames of type Delete Block Ack.
Definition: mgt-headers.h:1243
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:161
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition: wifi-utils.cc:172
std::pair< uint32_t, uint32_t > GetSizeIfAggregateMsdu(Ptr< const WifiMacQueueItem > msdu) const
Get the size in bytes of the frame in case the given MSDU is aggregated.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
typedef for union of different ActionValues
Definition: mgt-headers.h:928
Ptr< const WifiMacQueueItem > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:179
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:150
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism...
void SendAddBaResponse(const MgtAddBaRequestHeader *reqHdr, Mac48Address originator)
This method can be called to accept a received ADDBA Request.
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:922
virtual bool SendDataFrame(Ptr< const WifiMacQueueItem > peekedItem, Time availableTime, bool initialFrame)
Given a non-broadcast QoS data frame, prepare the PSDU to transmit by attempting A-MSDU and A-MPDU ag...
std::vector< Ptr< WifiMacQueueItem > >::const_iterator begin(void) const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:325
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1604
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:1768
WifiNoProtection specifies that no protection method is used.
void NotifyReceivedNormalAck(Ptr< WifiMacQueueItem > mpdu) override
Notify other components that an MPDU was acknowledged.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
uint32_t ampduSize
the size in bytes of the A-MPDU if multiple MPDUs have been added, and zero otherwise ...
void ReceiveMpdu(Ptr< WifiMacQueueItem > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMacQueueItem > mpdu) const
Retransmit an MPDU that was not acknowledged.
BlockAckType GetBlockAckType(Mac48Address originator, uint8_t tid) const
Get the type of BlockAck frames sent to the given originator.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data...
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1305
void TransmissionFailed(void) override
Take necessary actions upon a transmission failure.
void SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator)
Sends DELBA frame to cancel a block ack agreement with STA addressed by addr for TID tid...
void NotifyPacketDiscarded(Ptr< const WifiMacQueueItem > mpdu) override
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
static std::size_t GetDistance(uint16_t seqNumber, uint16_t startingSeqNumber)
Get the distance between the given starting sequence number and the given sequence number...
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
virtual void NotifyReceivedNormalAck(Ptr< WifiMacQueueItem > mpdu)
Notify other components that an MPDU was acknowledged.
BlockAckReqType barType
BlockAckReq type.
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
virtual bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame)
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
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...
Mac48Address GetAddr1(void) const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:111
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:978
void SendAddBaRequest(Mac48Address recipient, uint8_t tid, uint16_t startingSeq, uint16_t timeout, bool immediateBAck)
Sends an ADDBA Request to establish a block ack agreement with STA addressed by recipient for TID tid...
Ptr< WifiMacQueueItem > GetNextMpdu(Ptr< const WifiMacQueueItem > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame, WifiMacQueueItem::QueueIteratorPair &queueIt)
Prepare the frame to transmit starting from the MPDU that has been previously peeked by calling PeekN...
Definition: qos-txop.cc:359
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Definition: wifi-psdu.cc:278
Time GetFailedAddBaTimeout(void) const
Get the timeout for failed BA agreement.
Definition: qos-txop.cc:773
ActionValue GetAction()
Return the action value.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
Headers for BlockAckRequest.
Definition: ctrl-headers.h:48
Ptr< MpduAggregator > m_mpduAggregator
A-MPDU aggregator.
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
void ResetCw(void)
Update the value of the CW variable to take into account a transmission success or a transmission abo...
Definition: txop.cc:187
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...
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
a unique identifier for an interface.
Definition: type-id.h:58
void DequeuePsdu(Ptr< const WifiPsdu > psdu)
Dequeue the MPDUs of the given PSDU from the queue in which they are stored.
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
HtFrameExchangeManager handles the frame exchange sequences for HT stations.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
void CtsTimeout(Ptr< WifiMacQueueItem > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
static TypeId GetTypeId(void)
Get the type ID.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
void AddBaResponseTimeout(Mac48Address recipient, uint8_t tid)
Callback when ADDBA response is not received after timeout.
Definition: qos-txop.cc:721
bool GetBaAgreementEstablished(Mac48Address originator, uint8_t tid) const
Return true if a Block Ack agreement has been established with the given originator for the given TID...
void SetTidInfo(uint8_t tid, std::size_t index=0)
For Block Ack variants other than Multi-STA Block Ack, set the TID_INFO subfield of the BA Control fi...
Introspection did not find any typical Config paths.
Definition: snr-tag.h:34
WifiMacHeader::QosAckPolicy GetAckPolicyForTid(uint8_t tid) const
Get the QoS Ack Policy of the QoS Data frames included in the PSDU that have the given TID...
Definition: wifi-psdu.cc:180
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Implements the IEEE 802.11 MAC header.
bool HasData(void) const
Return true if the header type is DATA and is not DATA_NULL.
QosAckPolicy GetQosAckPolicy(void) const
Return the QoS Ack policy in the QoS control field.
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
bool IsAggregate(void) const
Return true if the PSDU is an S-MPDU or A-MPDU.
Definition: wifi-psdu.cc:81
Time GetTxopLimit(void) const
Return the TXOP limit.
Definition: txop.cc:274
virtual void RetransmitMpduAfterMissedCts(Ptr< WifiMacQueueItem > mpdu) const
Retransmit an MPDU that was not sent because a CTS was not received.