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