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 "ns3/channel-access-manager.h"
31 #include "ns3/wifi-protection-manager.h"
32 #include "ns3/wifi-ack-manager.h"
33 
34 #undef NS_LOG_APPEND_CONTEXT
35 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
36 
37 namespace ns3 {
38 
39 NS_LOG_COMPONENT_DEFINE ("HtFrameExchangeManager");
40 
41 NS_OBJECT_ENSURE_REGISTERED (HtFrameExchangeManager);
42 
43 TypeId
45 {
46  static TypeId tid = TypeId ("ns3::HtFrameExchangeManager")
48  .AddConstructor<HtFrameExchangeManager> ()
49  .SetGroupName ("Wifi")
50  ;
51  return tid;
52 }
53 
55 {
56  NS_LOG_FUNCTION (this);
57  m_msduAggregator = CreateObject<MsduAggregator> ();
58  m_mpduAggregator = CreateObject<MpduAggregator> ();
59 }
60 
62 {
64 }
65 
66 void
68 {
69  NS_LOG_FUNCTION (this);
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
132  bool immediateBAck)
133 {
134  NS_LOG_FUNCTION (this << dest << +tid << 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 (m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, dest));
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  SendMpduWithProtection (mpdu, txParams);
188 }
189 
190 void
192  Mac48Address originator)
193 {
194  NS_LOG_FUNCTION (this << originator);
195  WifiMacHeader hdr;
197  hdr.SetAddr1 (originator);
198  hdr.SetAddr2 (m_self);
199  hdr.SetAddr3 (m_bssid);
200  hdr.SetDsNotFrom ();
201  hdr.SetDsNotTo ();
202 
203  MgtAddBaResponseHeader respHdr;
204  StatusCode code;
205  code.SetSuccess ();
206  respHdr.SetStatusCode (code);
207  //Here a control about queues type?
208  respHdr.SetAmsduSupport (reqHdr->IsAmsduSupported ());
209 
210  if (reqHdr->IsImmediateBlockAck ())
211  {
212  respHdr.SetImmediateBlockAck ();
213  }
214  else
215  {
216  respHdr.SetDelayedBlockAck ();
217  }
218  respHdr.SetTid (reqHdr->GetTid ());
219 
220  respHdr.SetBufferSize (GetSupportedBaBufferSize () - 1);
221  respHdr.SetTimeout (reqHdr->GetTimeout ());
222 
223  WifiActionHeader actionHdr;
226  actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
227 
228  Ptr<Packet> packet = Create<Packet> ();
229  packet->AddHeader (respHdr);
230  packet->AddHeader (actionHdr);
231 
232  CreateBlockAckAgreement (&respHdr, originator, reqHdr->GetStartingSequence ());
233 
234  //It is unclear which queue this frame should go into. For now we
235  //bung it into the queue corresponding to the TID for which we are
236  //establishing an agreement, and push it to the head.
237  m_mac->GetQosTxop (reqHdr->GetTid ())->PushFront (packet, hdr);
238 }
239 
240 uint16_t
242 {
243  return 64;
244 }
245 
246 void
247 HtFrameExchangeManager::SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator)
248 {
249  NS_LOG_FUNCTION (this << addr << +tid << byOriginator);
250  WifiMacHeader hdr;
252  hdr.SetAddr1 (addr);
253  hdr.SetAddr2 (m_self);
254  hdr.SetAddr3 (m_bssid);
255  hdr.SetDsNotTo ();
256  hdr.SetDsNotFrom ();
257 
258  MgtDelBaHeader delbaHdr;
259  delbaHdr.SetTid (tid);
260  if (byOriginator)
261  {
262  delbaHdr.SetByOriginator ();
263  GetBaManager (tid)->DestroyAgreement (addr, tid);
264  }
265  else
266  {
267  delbaHdr.SetByRecipient ();
268  DestroyBlockAckAgreement (addr, tid);
269  }
270 
271  WifiActionHeader actionHdr;
274  actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
275 
276  Ptr<Packet> packet = Create<Packet> ();
277  packet->AddHeader (delbaHdr);
278  packet->AddHeader (actionHdr);
279 
280  m_mac->GetQosTxop (tid)->GetWifiMacQueue ()->PushFront (Create<WifiMacQueueItem> (packet, hdr));
281 }
282 
283 void
285  uint16_t startingSeq)
286 {
287  NS_LOG_FUNCTION (this << *respHdr << originator << startingSeq);
288  uint8_t tid = respHdr->GetTid ();
289 
290  RecipientBlockAckAgreement agreement (originator, respHdr->IsAmsduSupported (), tid,
291  respHdr->GetBufferSize () + 1, respHdr->GetTimeout (),
292  startingSeq,
293  m_mac->GetWifiRemoteStationManager ()->GetHtSupported ()
294  && m_mac->GetWifiRemoteStationManager ()->GetHtSupported (originator));
295  agreement.SetMacRxMiddle (m_rxMiddle);
296  if (respHdr->IsImmediateBlockAck ())
297  {
298  agreement.SetImmediateBlockAck ();
299  }
300  else
301  {
302  agreement.SetDelayedBlockAck ();
303  }
304 
305  if (respHdr->GetTimeout () != 0)
306  {
307  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
308 
309  agreement.m_inactivityEvent = Simulator::Schedule (timeout, &HtFrameExchangeManager::SendDelbaFrame,
310  this, originator, tid, false);
311  }
312 
313  m_agreements.insert ({{originator, tid}, agreement});
314  GetBaManager (tid)->SetBlockAckInactivityCallback (MakeCallback (&HtFrameExchangeManager::SendDelbaFrame, this));
315 }
316 
317 void
319 {
320  NS_LOG_FUNCTION (this << originator << +tid);
321 
322  auto agreementIt = m_agreements.find ({originator, tid});
323  if (agreementIt != m_agreements.end ())
324  {
325  // forward up the buffered MPDUs before destroying the agreement
326  agreementIt->second.Flush ();
327  m_agreements.erase (agreementIt);
328  }
329 }
330 
331 bool
332 HtFrameExchangeManager::StartFrameExchange (Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
333 {
334  NS_LOG_FUNCTION (this << edca << availableTime << initialFrame);
335 
336  // First, check if there is a BAR to be transmitted
337  if (SendMpduFromBaManager (edca, availableTime, initialFrame))
338  {
339  return true;
340  }
341 
342  Ptr<const WifiMacQueueItem> peekedItem = edca->PeekNextMpdu ();
343 
344  // Even though channel access is requested when the queue is not empty, at
345  // the time channel access is granted the lifetime of the packet might be
346  // expired and the queue might be empty.
347  if (peekedItem == 0)
348  {
349  NS_LOG_DEBUG ("No frames available for transmission");
350  return false;
351  }
352 
353  const WifiMacHeader& hdr = peekedItem->GetHeader ();
354  // setup a Block Ack agreement if needed
355  if (hdr.IsQosData () && !hdr.GetAddr1 ().IsGroup ()
356  && NeedSetupBlockAck (hdr.GetAddr1 (), hdr.GetQosTid ()))
357  {
358  SendAddBaRequest (hdr.GetAddr1 (), hdr.GetQosTid (), edca->GetBlockAckInactivityTimeout (), true);
359  return true;
360  }
361 
362  // Use SendDataFrame if we can try aggregation
363  if (hdr.IsQosData () && !hdr.GetAddr1 ().IsGroup () && !peekedItem->IsFragment ()
364  && !m_mac->GetWifiRemoteStationManager ()->NeedFragmentation (peekedItem))
365  {
366  return SendDataFrame (peekedItem, availableTime, initialFrame);
367  }
368 
369  // Use the QoS FEM to transmit the frame in all the other cases, i.e.:
370  // - the frame is not a QoS data frame
371  // - the frame is a broadcast QoS data frame
372  // - the frame is a fragment
373  // - the frame must be fragmented
374  return QosFrameExchangeManager::StartFrameExchange (edca, availableTime, initialFrame);
375 }
376 
377 bool
378 HtFrameExchangeManager::SendMpduFromBaManager (Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
379 {
380  NS_LOG_FUNCTION (this << edca << availableTime << initialFrame);
381 
382  // First, check if there is a BAR to be transmitted
383  Ptr<const WifiMacQueueItem> peekedItem = edca->GetBaManager ()->GetBar (false);
384 
385  if (peekedItem == 0)
386  {
387  NS_LOG_DEBUG ("Block Ack Manager returned no frame to send");
388  return false;
389  }
390 
391  NS_ASSERT (peekedItem->GetHeader ().IsBlockAckReq ());
392 
393  // Prepare the TX parameters. Note that the default ack manager expects the
394  // data TxVector in the m_txVector field to compute the BlockAck TxVector.
395  // The m_txVector field of the TX parameters is set to the BlockAckReq TxVector
396  // a few lines below.
397  WifiTxParameters txParams;
398  txParams.m_txVector = m_mac->GetWifiRemoteStationManager ()->GetDataTxVector (peekedItem->GetHeader ());
399  txParams.m_protection = std::unique_ptr<WifiProtection> (new WifiNoProtection);
400  txParams.m_acknowledgment = GetAckManager ()->TryAddMpdu (peekedItem, txParams);
401 
402  NS_ABORT_IF (txParams.m_acknowledgment->method != WifiAcknowledgment::BLOCK_ACK);
403 
404  WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*> (txParams.m_acknowledgment.get ());
405  CalculateAcknowledgmentTime (blockAcknowledgment);
406  // the BlockAckReq frame is sent using the same TXVECTOR as the BlockAck frame
407  txParams.m_txVector = blockAcknowledgment->blockAckTxVector;
408 
409  Time barTxDuration = m_phy->CalculateTxDuration (peekedItem->GetSize (),
410  blockAcknowledgment->blockAckTxVector,
411  m_phy->GetPhyBand ());
412 
413  // if the available time is limited and we are not transmitting the initial
414  // frame of the TXOP, we have to check that this frame and its response fit
415  // within the given time limits
416  if (availableTime != Time::Min () && !initialFrame
417  && barTxDuration + m_phy->GetSifs () + blockAcknowledgment->acknowledgmentTime > availableTime)
418  {
419  NS_LOG_DEBUG ("Not enough time to send the BAR frame returned by the Block Ack Manager");
420  return false;
421  }
422 
423  // we can transmit the BlockAckReq frame
424  Ptr<const WifiMacQueueItem> mpdu = edca->GetBaManager ()->GetBar ();
425  SendPsduWithProtection (Create<WifiPsdu> (mpdu, false), txParams);
426  return true;
427 }
428 
429 bool
431  Time availableTime, bool initialFrame)
432 {
433  NS_ASSERT (peekedItem != 0 && peekedItem->GetHeader ().IsQosData ()
434  && !peekedItem->GetHeader ().GetAddr1 ().IsBroadcast ()
435  && !peekedItem->IsFragment ());
436  NS_LOG_FUNCTION (this << *peekedItem << availableTime << initialFrame);
437 
438  Ptr<QosTxop> edca = m_mac->GetQosTxop (peekedItem->GetHeader ().GetQosTid ());
439  WifiTxParameters txParams;
440  txParams.m_txVector = m_mac->GetWifiRemoteStationManager ()->GetDataTxVector (peekedItem->GetHeader ());
442  Ptr<WifiMacQueueItem> mpdu = edca->GetNextMpdu (peekedItem, txParams, availableTime, initialFrame, queueIt);
443 
444  if (mpdu == nullptr)
445  {
446  NS_LOG_DEBUG ("Not enough time to transmit a frame");
447  return false;
448  }
449 
450  // try A-MPDU aggregation
451  std::vector<Ptr<WifiMacQueueItem>> mpduList = m_mpduAggregator->GetNextAmpdu (mpdu, txParams,
452  availableTime, queueIt);
453  NS_ASSERT (txParams.m_acknowledgment);
454 
455  if (mpduList.size () > 1)
456  {
457  // A-MPDU aggregation succeeded
458  SendPsduWithProtection (Create<WifiPsdu> (std::move (mpduList)), txParams);
459  }
460  else if (txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
461  {
462  // a QoS data frame using the Block Ack policy can be followed by a BlockAckReq
463  // frame and a BlockAck frame. Such a sequence is handled by the HT FEM
464  SendPsduWithProtection (Create<WifiPsdu> (mpdu, false), txParams);
465  }
466  else
467  {
468  // transmission can be handled by the base FEM
469  SendMpduWithProtection (mpdu, txParams);
470  }
471 
472  return true;
473 }
474 
475 void
477 {
478  NS_LOG_FUNCTION (this << acknowledgment);
479  NS_ASSERT (acknowledgment != nullptr);
480 
481  if (acknowledgment->method == WifiAcknowledgment::BLOCK_ACK)
482  {
483  WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*> (acknowledgment);
484  Time baTxDuration = m_phy->CalculateTxDuration (GetBlockAckSize (blockAcknowledgment->baType),
485  blockAcknowledgment->blockAckTxVector,
486  m_phy->GetPhyBand ());
487  blockAcknowledgment->acknowledgmentTime = m_phy->GetSifs () + baTxDuration;
488  }
489  else if (acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
490  {
491  WifiBarBlockAck* barBlockAcknowledgment = static_cast<WifiBarBlockAck*> (acknowledgment);
492  Time barTxDuration = m_phy->CalculateTxDuration (GetBlockAckRequestSize (barBlockAcknowledgment->barType),
493  barBlockAcknowledgment->blockAckReqTxVector,
494  m_phy->GetPhyBand ());
495  Time baTxDuration = m_phy->CalculateTxDuration (GetBlockAckSize (barBlockAcknowledgment->baType),
496  barBlockAcknowledgment->blockAckTxVector,
497  m_phy->GetPhyBand ());
498  barBlockAcknowledgment->acknowledgmentTime = 2 * m_phy->GetSifs () + barTxDuration + baTxDuration;
499  }
500  else
501  {
503  }
504 }
505 
506 void
508 {
509  ForwardPsduDown (GetWifiPsdu (mpdu, txVector), txVector);
510 }
511 
514 {
515  return Create<WifiPsdu> (mpdu, false);
516 }
517 
518 void
520 {
521  NS_LOG_FUNCTION (this << *mpdu);
522 
523  if (mpdu->GetHeader ().IsQosData ())
524  {
525  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
526  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
527 
528  if (edca->GetBaAgreementEstablished (mpdu->GetHeader ().GetAddr1 (), tid))
529  {
530  // notify the BA manager that the MPDU was acknowledged
531  edca->GetBaManager ()->NotifyGotAck (mpdu);
532  }
533  }
534  else if (mpdu->GetHeader ().IsAction ())
535  {
536  WifiActionHeader actionHdr;
537  Ptr<Packet> p = mpdu->GetPacket ()->Copy ();
538  p->RemoveHeader (actionHdr);
539  if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK)
540  {
542  {
543  MgtDelBaHeader delBa;
544  p->PeekHeader (delBa);
545  if (delBa.IsByOriginator ())
546  {
547  GetBaManager (delBa.GetTid ())->DestroyAgreement (mpdu->GetHeader ().GetAddr1 (),
548  delBa.GetTid ());
549  }
550  else
551  {
552  DestroyBlockAckAgreement (mpdu->GetHeader ().GetAddr1 (), delBa.GetTid ());
553  }
554  }
556  {
557  // Setup ADDBA response timeout
558  MgtAddBaRequestHeader addBa;
559  p->PeekHeader (addBa);
560  Ptr<QosTxop> edca = m_mac->GetQosTxop (addBa.GetTid ());
563  mpdu->GetHeader ().GetAddr1 (), addBa.GetTid ());
564  }
565  }
566  }
568 }
569 
570 void
572 {
573  NS_LOG_DEBUG (this);
574 
575  if (m_edca != 0 && m_edca->GetTxopLimit ().IsZero () && m_edca->GetBaManager ()->GetBar (false) != 0)
576  {
577  // A TXOP limit of 0 indicates that the TXOP holder may transmit or cause to
578  // be transmitted (as responses) the following within the current TXOP:
579  // f) Any number of BlockAckReq frames
580  // (Sec. 10.22.2.8 of 802.11-2016)
581  NS_LOG_DEBUG ("Schedule a transmission from Block Ack Manager in a SIFS");
583 
584  // TXOP limit is null, hence the txopDuration parameter is unused
585  Simulator::Schedule (m_phy->GetSifs (), fp, this, m_edca, Seconds (0));
586  }
587  else
588  {
590  }
591 }
592 
593 void
595 {
596  NS_LOG_FUNCTION (this << *mpdu);
597 
598  if (mpdu->GetHeader ().IsQosData ())
599  {
600  GetBaManager (mpdu->GetHeader ().GetQosTid ())->NotifyDiscardedMpdu (mpdu);
601  }
602  else if (mpdu->GetHeader ().IsAction ())
603  {
604  WifiActionHeader actionHdr;
605  mpdu->GetPacket ()->PeekHeader (actionHdr);
606  if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK)
607  {
608  uint8_t tid = GetTid (mpdu->GetPacket (), mpdu->GetHeader ());
609  if (GetBaManager (tid)->ExistsAgreementInState (mpdu->GetHeader ().GetAddr1 (), tid,
611  {
612  NS_LOG_DEBUG ("No ACK after ADDBA request");
613  GetBaManager (tid)->NotifyAgreementNoReply (mpdu->GetHeader ().GetAddr1 (), tid);
614  Ptr<QosTxop> qosTxop = m_mac->GetQosTxop (tid);
616  mpdu->GetHeader ().GetAddr1 (), tid);
617  }
618  }
619  }
621 }
622 
623 void
625 {
626  NS_LOG_FUNCTION (this << *mpdu);
627 
628  if (mpdu->GetHeader ().IsQosData ())
629  {
630  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
631  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
632 
633  if (edca->GetBaAgreementEstablished (mpdu->GetHeader ().GetAddr1 (), tid))
634  {
635  // notify the BA manager that the MPDU was not acknowledged
636  edca->GetBaManager ()->NotifyMissedAck (mpdu);
637  return;
638  }
639  }
641 }
642 
643 void
645 {
646  NS_LOG_FUNCTION (this << *mpdu);
647 
648  // the MPDU should be still in the queue, unless it expired.
649  const WifiMacHeader& hdr = mpdu->GetHeader ();
650  if (hdr.IsQosData ())
651  {
652  uint8_t tid = hdr.GetQosTid ();
653  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
654 
655  if (edca->GetBaAgreementEstablished (hdr.GetAddr1 (), tid)
656  && !hdr.IsRetry ())
657  {
658  // The MPDU has never been transmitted, so we can make its sequence
659  // number available again if it is lower than the sequence number
660  // maintained by the MAC TX middle
661  uint16_t currentNextSeq = m_txMiddle->PeekNextSequenceNumberFor (&hdr);
662  uint16_t startingSeq = edca->GetBaStartingSequence (hdr.GetAddr1 (), tid);
663 
664  if (BlockAckAgreement::GetDistance (hdr.GetSequenceNumber (), startingSeq)
665  < BlockAckAgreement::GetDistance (currentNextSeq, startingSeq))
666  {
667  m_txMiddle->SetSequenceNumberFor (&hdr);
668  }
669 
670  return;
671  }
672  }
674 }
675 
676 Time
678 {
679  NS_LOG_FUNCTION (this << txDuration << &txParams);
680 
681  NS_ASSERT (m_edca != 0);
682 
683  if (m_edca->GetTxopLimit ().IsZero ())
684  {
685  NS_ASSERT (txParams.m_acknowledgment && txParams.m_acknowledgment->acknowledgmentTime != Time::Min ());
686  return txParams.m_acknowledgment->acknowledgmentTime;
687  }
688 
689  // under multiple protection settings, if the TXOP limit is not null, Duration/ID
690  // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
691  // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
692  // of 802.11-2016)
693  return std::max (m_edca->GetRemainingTxop () - txDuration, Seconds (0));
694 }
695 
696 void
698 {
699  NS_LOG_FUNCTION (this << psdu << &txParams);
700 
701  m_psdu = psdu;
702  m_txParams = std::move (txParams);
703 
704 #ifdef NS3_BUILD_PROFILE_DEBUG
705  // If protection is required, the MPDUs must be stored in some queue because
706  // they are not put back in a queue if the RTS/CTS exchange fails
708  {
709  for (const auto& mpdu : *PeekPointer (m_psdu))
710  {
711  NS_ASSERT (mpdu->GetHeader ().IsCtl () || mpdu->IsQueued ());
712  }
713  }
714 #endif
715 
716  // Make sure that the acknowledgment time has been computed, so that SendRts()
717  // and SendCtsToSelf() can reuse this value.
719 
720  if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min ())
721  {
723  }
724 
725  // Set QoS Ack policy
727 
729  {
731  }
733  {
735  }
736  else if (m_txParams.m_protection->method == WifiProtection::NONE)
737  {
738  SendPsdu ();
739  }
740  else
741  {
742  NS_ABORT_MSG ("Unknown protection type");
743  }
744 }
745 
746 void
748 {
749  NS_LOG_FUNCTION (this << *rts << txVector);
750 
751  if (m_psdu == 0)
752  {
753  // A CTS Timeout occurred when protecting a single MPDU is handled by the
754  // parent classes
755  QosFrameExchangeManager::CtsTimeout (rts, txVector);
756  return;
757  }
758 
759  NS_ASSERT (m_psdu->GetNMpdus () > 1);
760  m_mac->GetWifiRemoteStationManager ()->ReportRtsFailed (m_psdu->GetHeader (0));
761 
762  if (!m_mac->GetWifiRemoteStationManager ()->NeedRetransmission (*m_psdu->begin ()))
763  {
764  NS_LOG_DEBUG ("Missed CTS, discard MPDUs");
765  m_mac->GetWifiRemoteStationManager ()->ReportFinalRtsFailed (m_psdu->GetHeader (0));
766  // Dequeue the MPDUs if they are stored in a queue
768  for (const auto& mpdu : *PeekPointer (m_psdu))
769  {
770  NotifyPacketDiscarded (mpdu);
771  }
772  m_edca->ResetCw ();
773  }
774  else
775  {
776  NS_LOG_DEBUG ("Missed CTS, retransmit MPDUs");
777  for (const auto& mpdu : *PeekPointer (m_psdu))
778  {
780  }
782  }
783  m_psdu = 0;
785 }
786 
787 void
789 {
790  NS_LOG_FUNCTION (this);
791 
793 
795 
797  {
799  }
801  {
803 
804  // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
805  // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
806  // aRxPHYStartDelay equals the time to transmit the PHY header.
807  WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*> (m_txParams.m_acknowledgment.get ());
808 
809  Time timeout = txDuration
810  + m_phy->GetSifs ()
811  + m_phy->GetSlot ()
815  this, m_psdu, m_txParams.m_txVector);
816  m_channelAccessManager->NotifyAckTimeoutStartNow (timeout);
817  }
819  {
821 
822  // schedule the transmission of a BAR in a SIFS
823  std::set<uint8_t> tids = m_psdu->GetTids ();
824  NS_ABORT_MSG_IF (tids.size () > 1, "Acknowledgment method incompatible with a Multi-TID A-MPDU");
825  uint8_t tid = *tids.begin ();
826 
827  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
828  edca->ScheduleBar (edca->PrepareBlockAckRequest (m_psdu->GetAddr1 (), tid));
829 
831  }
832  else
833  {
834  NS_ABORT_MSG ("Unable to handle the selected acknowledgment method ("
835  << m_txParams.m_acknowledgment.get () << ")");
836  }
837 
838  // transmit the PSDU
839  if (m_psdu->GetNMpdus () > 1)
840  {
842  }
843  else
844  {
846  }
847 
849  {
850  // we are done in case the A-MPDU does not require acknowledgment
851  m_psdu = 0;
852  }
853 }
854 
855 void
857 {
858  NS_LOG_FUNCTION (this << psdu);
859 
860  for (const auto& mpdu : *PeekPointer (psdu))
861  {
862  if (mpdu->GetHeader ().IsQosData ())
863  {
864  Ptr<QosTxop> edca = m_mac->GetQosTxop (mpdu->GetHeader ().GetQosTid ());
865 
866  if (mpdu->GetHeader ().IsQosEosp ())
867  {
868  edca->SetQosQueueSize (mpdu);
869  }
870  if (mpdu->GetHeader ().HasData ())
871  {
872  edca->CompleteMpduTx (mpdu);
873  }
874  }
875  }
876 }
877 
878 void
880 {
881  DequeuePsdu (Create<const WifiPsdu> (mpdu, true));
882 }
883 
884 void
886 {
887  NS_LOG_DEBUG (this << psdu);
888 
889  for (const auto& mpdu : *PeekPointer (psdu))
890  {
891  if (mpdu->GetQueueIteratorPairs ().size () > 1)
892  {
893  // this MPDU contains an A-MSDU
894  for (const auto& queueIt : mpdu->GetQueueIteratorPairs ())
895  {
896  NS_ASSERT (*queueIt.it != mpdu);
897  queueIt.queue->Dequeue (queueIt.it);
898  }
899  }
900  else if (mpdu->IsQueued ())
901  {
902  WifiMacQueueItem::QueueIteratorPair queueIt = mpdu->GetQueueIteratorPairs ().front ();
903  NS_ASSERT (*queueIt.it == mpdu);
904  queueIt.queue->Dequeue (queueIt.it);
905  }
906  }
907 }
908 
909 void
911 {
912  NS_LOG_FUNCTION (this << psdu << txVector);
913 
914  NS_LOG_DEBUG ("Transmitting a PSDU: " << *psdu << " TXVECTOR: " << txVector);
915  NotifyTxToEdca (psdu);
916 
917  if (psdu->IsAggregate ())
918  {
919  txVector.SetAggregation (true);
920  }
921 
922  // The PSDU is about to be transmitted, we can now dequeue the MPDUs
923  DequeuePsdu (psdu);
924 
925  m_phy->Send (psdu, txVector);
926 }
927 
928 bool
930  const WifiTxParameters& txParams,
931  Time ppduDurationLimit) const
932 {
933  NS_ASSERT (mpdu != 0);
934  NS_LOG_FUNCTION (this << *mpdu << &txParams << ppduDurationLimit);
935 
936  Mac48Address receiver = mpdu->GetHeader ().GetAddr1 ();
937  uint32_t ampduSize = txParams.GetSizeIfAddMpdu (mpdu);
938 
939  if (txParams.GetSize (receiver) > 0)
940  {
941  // we are attempting to perform A-MPDU aggregation, hence we have to check
942  // that we meet the limit on the max A-MPDU size
943  uint8_t tid;
944  const WifiTxParameters::PsduInfo* info;
945 
946  if (mpdu->GetHeader ().IsQosData ())
947  {
948  tid = mpdu->GetHeader ().GetQosTid ();
949  }
950  else if ((info = txParams.GetPsduInfo (receiver)) && !info->seqNumbers.empty ())
951  {
952  tid = info->seqNumbers.begin ()->first;
953  }
954  else
955  {
956  NS_ABORT_MSG ("Cannot aggregate a non-QoS data frame to an A-MPDU that does"
957  " not contain any QoS data frame");
958  }
959 
960  WifiModulationClass modulation = txParams.m_txVector.GetModulationClass ();
961 
962  if (!IsWithinAmpduSizeLimit (ampduSize, receiver, tid, modulation))
963  {
964  return false;
965  }
966  }
967 
968  return IsWithinSizeAndTimeLimits (ampduSize, receiver, txParams, ppduDurationLimit);
969 }
970 
971 bool
972 HtFrameExchangeManager::IsWithinAmpduSizeLimit (uint32_t ampduSize, Mac48Address receiver, uint8_t tid,
973  WifiModulationClass modulation) const
974 {
975  NS_LOG_FUNCTION (this << ampduSize << receiver << +tid << modulation);
976 
977  uint32_t maxAmpduSize = m_mpduAggregator->GetMaxAmpduSize (receiver, tid, modulation);
978 
979  if (maxAmpduSize == 0)
980  {
981  NS_LOG_DEBUG ("A-MPDU aggregation disabled");
982  return false;
983  }
984 
985  if (ampduSize > maxAmpduSize)
986  {
987  NS_LOG_DEBUG ("the frame does not meet the constraint on max A-MPDU size ("
988  << maxAmpduSize << ")");
989  return false;
990  }
991  return true;
992 }
993 
994 bool
996  Time availableTime) const
997 {
998  NS_ASSERT (msdu != 0 && msdu->GetHeader ().IsQosData ());
999  NS_LOG_FUNCTION (this << *msdu << &txParams << availableTime);
1000 
1001  // check if aggregating the given MSDU requires a different protection method
1002  NS_ASSERT (txParams.m_protection);
1003  Time protectionTime = txParams.m_protection->protectionTime;
1004 
1005  std::unique_ptr<WifiProtection> protection;
1006  protection = GetProtectionManager ()->TryAggregateMsdu (msdu, txParams);
1007  bool protectionSwapped = false;
1008 
1009  if (protection)
1010  {
1011  // the protection method has changed, calculate the new protection time
1012  CalculateProtectionTime (protection.get ());
1013  protectionTime = protection->protectionTime;
1014  // swap unique pointers, so that the txParams that is passed to the next
1015  // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1016  txParams.m_protection.swap (protection);
1017  protectionSwapped = true;
1018  }
1019  NS_ASSERT (protectionTime != Time::Min ());
1020 
1021  // check if aggregating the given MSDU requires a different acknowledgment method
1022  NS_ASSERT (txParams.m_acknowledgment);
1023  Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
1024 
1025  std::unique_ptr<WifiAcknowledgment> acknowledgment;
1026  acknowledgment = GetAckManager ()->TryAggregateMsdu (msdu, txParams);
1027  bool acknowledgmentSwapped = false;
1028 
1029  if (acknowledgment)
1030  {
1031  // the acknowledgment method has changed, calculate the new acknowledgment time
1032  CalculateAcknowledgmentTime (acknowledgment.get ());
1033  acknowledgmentTime = acknowledgment->acknowledgmentTime;
1034  // swap unique pointers, so that the txParams that is passed to the next
1035  // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1036  txParams.m_acknowledgment.swap (acknowledgment);
1037  acknowledgmentSwapped = true;
1038  }
1039  NS_ASSERT (acknowledgmentTime != Time::Min ());
1040 
1041  Time ppduDurationLimit = Time::Min ();
1042  if (availableTime != Time::Min ())
1043  {
1044  ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
1045  }
1046 
1047  if (!IsWithinLimitsIfAggregateMsdu (msdu, txParams, ppduDurationLimit))
1048  {
1049  // adding MPDU failed, restore protection and acknowledgment methods
1050  // if they were swapped
1051  if (protectionSwapped)
1052  {
1053  txParams.m_protection.swap (protection);
1054  }
1055  if (acknowledgmentSwapped)
1056  {
1057  txParams.m_acknowledgment.swap (acknowledgment);
1058  }
1059  return false;
1060  }
1061 
1062  // the given MPDU can be added, hence update the txParams
1063  txParams.AggregateMsdu (msdu);
1064  UpdateTxDuration (msdu->GetHeader ().GetAddr1 (), txParams);
1065 
1066  return true;
1067 }
1068 
1069 bool
1071  const WifiTxParameters& txParams,
1072  Time ppduDurationLimit) const
1073 {
1074  NS_ASSERT (msdu != 0 && msdu->GetHeader ().IsQosData ());
1075  NS_LOG_FUNCTION (this << *msdu << &txParams << ppduDurationLimit);
1076 
1077  std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu (msdu);
1078  Mac48Address receiver = msdu->GetHeader ().GetAddr1 ();
1079  uint8_t tid = msdu->GetHeader ().GetQosTid ();
1080  WifiModulationClass modulation = txParams.m_txVector.GetModulationClass ();
1081 
1082  // Check that the limit on A-MSDU size is met
1083  uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize (receiver, tid, modulation);
1084 
1085  if (maxAmsduSize == 0)
1086  {
1087  NS_LOG_DEBUG ("A-MSDU aggregation disabled");
1088  return false;
1089  }
1090 
1091  if (ret.first > maxAmsduSize)
1092  {
1093  NS_LOG_DEBUG ("No other MSDU can be aggregated: maximum A-MSDU size ("
1094  << maxAmsduSize << ") reached ");
1095  return false;
1096  }
1097 
1098  const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo (msdu->GetHeader ().GetAddr1 ());
1099  NS_ASSERT (info != nullptr);
1100 
1101  if (info->ampduSize > 0)
1102  {
1103  // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
1104  // Check that the limit on A-MPDU size is met.
1105  if (!IsWithinAmpduSizeLimit (ret.second, receiver, tid, modulation))
1106  {
1107  return false;
1108  }
1109  }
1110 
1111  return IsWithinSizeAndTimeLimits (ret.second, receiver, txParams, ppduDurationLimit);
1112 }
1113 
1114 void
1116 {
1117  NS_LOG_FUNCTION (this << *psdu << txVector);
1118 
1119  m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psdu->begin ());
1120 
1121  bool resetCw;
1122  MissedBlockAck (psdu, txVector, resetCw);
1123 
1124  NS_ASSERT (m_edca != 0);
1125 
1126  if (resetCw)
1127  {
1128  m_edca->ResetCw ();
1129  }
1130  else
1131  {
1132  m_edca->UpdateFailedCw ();
1133  }
1134 
1135  m_psdu = 0;
1136  TransmissionFailed ();
1137 }
1138 
1139 void
1141 {
1142  NS_LOG_FUNCTION (this << psdu << txVector << resetCw);
1143 
1144  Mac48Address recipient = psdu->GetAddr1 ();
1145  bool isBar;
1146  uint8_t tid;
1147 
1148  if (psdu->GetNMpdus () == 1 && psdu->GetHeader (0).IsBlockAckReq ())
1149  {
1150  isBar = true;
1151  CtrlBAckRequestHeader baReqHdr;
1152  psdu->GetPayload (0)->PeekHeader (baReqHdr);
1153  tid = baReqHdr.GetTidInfo ();
1154  }
1155  else
1156  {
1157  isBar = false;
1158  m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (recipient, 0, psdu->GetNMpdus (),
1159  0, 0, txVector);
1160  std::set<uint8_t> tids = psdu->GetTids ();
1161  NS_ABORT_MSG_IF (tids.size () > 1, "Multi-TID A-MPDUs not handled here");
1162  NS_ASSERT (!tids.empty ());
1163  tid = *tids.begin ();
1164  }
1165 
1166  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
1167 
1168  if (edca->UseExplicitBarAfterMissedBlockAck () || isBar)
1169  {
1170  // we have to send a BlockAckReq, if needed
1171  if (GetBaManager (tid)->NeedBarRetransmission (tid, recipient))
1172  {
1173  NS_LOG_DEBUG ("Missed Block Ack, transmit a BlockAckReq");
1174  if (isBar)
1175  {
1176  psdu->GetHeader (0).SetRetry ();
1177  edca->ScheduleBar (*psdu->begin ());
1178  }
1179  else
1180  {
1181  // missed block ack after data frame with Implicit BAR Ack policy
1182  edca->ScheduleBar (edca->PrepareBlockAckRequest (recipient, tid));
1183  }
1184  resetCw = false;
1185  }
1186  else
1187  {
1188  NS_LOG_DEBUG ("Missed Block Ack, do not transmit a BlockAckReq");
1189  // if a BA agreement exists, we can get here if there is no outstanding
1190  // MPDU whose lifetime has not expired yet.
1191  m_mac->GetWifiRemoteStationManager ()->ReportFinalDataFailed (*psdu->begin ());
1192  if (GetBaManager (tid)->ExistsAgreementInState (recipient, tid,
1194  {
1195  // If there is any (expired) outstanding MPDU, request the BA manager to discard
1196  // it, which involves the scheduling of a BAR to advance the recipient's window
1197  if (GetBaManager (tid)->GetNBufferedPackets (recipient, tid) > 0)
1198  {
1199  GetBaManager (tid)->DiscardOutstandingMpdus (recipient, tid);
1200  }
1201  // otherwise, it means that we have not received a Block Ack in response to a
1202  // BlockAckRequest sent while no frame was outstanding, whose purpose was therefore
1203  // to advance the recipient's window. Schedule a BlockAckRequest with
1204  // skipIfNoDataQueued set to true, so that the BlockAckRequest is only sent
1205  // if there are data frames queued for this recipient.
1206  else
1207  {
1208  edca->ScheduleBar (edca->PrepareBlockAckRequest (recipient, tid), true);
1209  }
1210  }
1211  resetCw = true;
1212  }
1213  }
1214  else
1215  {
1216  // we have to retransmit the data frames, if needed
1217  if (!m_mac->GetWifiRemoteStationManager ()->NeedRetransmission (*psdu->begin ()))
1218  {
1219  NS_LOG_DEBUG ("Missed Block Ack, do not retransmit the data frames");
1220  m_mac->GetWifiRemoteStationManager ()->ReportFinalDataFailed (*psdu->begin ());
1221  for (const auto& mpdu : *PeekPointer (psdu))
1222  {
1224  }
1225  GetBaManager (tid)->DiscardOutstandingMpdus (recipient, tid);
1226  resetCw = true;
1227  }
1228  else
1229  {
1230  NS_LOG_DEBUG ("Missed Block Ack, retransmit data frames");
1231  GetBaManager (tid)->NotifyMissedBlockAck (recipient, tid);
1232  resetCw = false;
1233  }
1234  }
1235 }
1236 
1237 void
1239  WifiTxVector& blockAckTxVector, double rxSnr)
1240 {
1241  NS_LOG_FUNCTION (this << durationId << blockAckTxVector << rxSnr);
1242 
1243  WifiMacHeader hdr;
1245  hdr.SetAddr1 (agreement.GetPeer ());
1246  hdr.SetAddr2 (m_self);
1247  hdr.SetDsNotFrom ();
1248  hdr.SetDsNotTo ();
1249 
1250  CtrlBAckResponseHeader blockAck;
1251  blockAck.SetType (agreement.GetBlockAckType ());
1252  blockAck.SetTidInfo (agreement.GetTid ());
1253  agreement.FillBlockAckBitmap (&blockAck);
1254 
1255  Ptr<Packet> packet = Create<Packet> ();
1256  packet->AddHeader (blockAck);
1257  Ptr<WifiPsdu> psdu = GetWifiPsdu (Create<WifiMacQueueItem> (packet, hdr), blockAckTxVector);
1258 
1259  // 802.11-2016, Section 9.2.5.7: In a BlockAck frame transmitted in response
1260  // to a BlockAckReq frame or transmitted in response to a frame containing an
1261  // implicit block ack request, the Duration/ID field is set to the value obtained
1262  // from the Duration/ ID field of the frame that elicited the response minus the
1263  // time, in microseconds between the end of the PPDU carrying the frame that
1264  // elicited the response and the end of the PPDU carrying the BlockAck frame.
1265  Time baDurationId = durationId - m_phy->GetSifs ()
1266  - m_phy->CalculateTxDuration (psdu->GetSize (), blockAckTxVector, m_phy->GetPhyBand ());
1267  // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1268  if (baDurationId.IsStrictlyNegative ())
1269  {
1270  baDurationId = Seconds (0);
1271  }
1272  psdu->GetHeader (0).SetDuration (baDurationId);
1273 
1274  SnrTag tag;
1275  tag.Set (rxSnr);
1276  psdu->GetPayload (0)->AddPacketTag (tag);
1277 
1278  ForwardPsduDown (psdu, blockAckTxVector);
1279 }
1280 
1281 bool
1283 {
1284  return (m_agreements.find ({originator, tid}) != m_agreements.end ());
1285 }
1286 
1289 {
1290  auto it = m_agreements.find ({originator, tid});
1291  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
1292  return it->second.GetBlockAckType ();
1293 }
1294 
1295 void
1297  const WifiTxVector& txVector, bool inAmpdu)
1298 {
1299  // The received MPDU is either broadcast or addressed to this station
1300  NS_ASSERT (mpdu->GetHeader ().GetAddr1 ().IsGroup ()
1301  || mpdu->GetHeader ().GetAddr1 () == m_self);
1302 
1303  double rxSnr = rxSignalInfo.snr;
1304  const WifiMacHeader& hdr = mpdu->GetHeader ();
1305 
1306  if (hdr.IsCtl ())
1307  {
1309  && m_psdu != 0)
1310  {
1311  NS_ABORT_MSG_IF (inAmpdu, "Received CTS as part of an A-MPDU");
1312  NS_ASSERT (hdr.GetAddr1 () == m_self);
1313 
1314  Mac48Address sender = m_psdu->GetAddr1 ();
1315  NS_LOG_DEBUG ("Received CTS from=" << sender);
1316 
1317  SnrTag tag;
1318  mpdu->GetPacket ()->PeekPacketTag (tag);
1319  m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1320  m_mac->GetWifiRemoteStationManager ()->ReportRtsOk (m_psdu->GetHeader (0),
1321  rxSnr, txVector.GetMode (), tag.Get ());
1322 
1323  m_txTimer.Cancel ();
1324  m_channelAccessManager->NotifyCtsTimeoutResetNow ();
1326  }
1327  else if (hdr.IsBlockAck () && m_txTimer.IsRunning ()
1329  && hdr.GetAddr1 () == m_self)
1330  {
1331  Mac48Address sender = hdr.GetAddr2 ();
1332  NS_LOG_DEBUG ("Received BlockAck from=" << sender);
1333 
1334  SnrTag tag;
1335  mpdu->GetPacket ()->PeekPacketTag (tag);
1336 
1337  // notify the Block Ack Manager
1338  CtrlBAckResponseHeader blockAck;
1339  mpdu->GetPacket ()->PeekHeader (blockAck);
1340  uint8_t tid = blockAck.GetTidInfo ();
1341  GetBaManager (tid)->NotifyGotBlockAck (&blockAck, hdr.GetAddr2 (), rxSnr,
1342  tag.Get (), m_txParams.m_txVector);
1343 
1344  // cancel the timer
1345  m_txTimer.Cancel ();
1346  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1347 
1348  // Reset the CW
1349  m_edca->ResetCw ();
1350 
1351  m_psdu = 0;
1353  }
1354  else if (hdr.IsBlockAckReq ())
1355  {
1356  NS_ASSERT (hdr.GetAddr1 () == m_self);
1357  NS_ABORT_MSG_IF (inAmpdu, "BlockAckReq in A-MPDU is not supported");
1358 
1359  Mac48Address sender = hdr.GetAddr2 ();
1360  NS_LOG_DEBUG ("Received BlockAckReq from=" << sender);
1361 
1362  CtrlBAckRequestHeader blockAckReq;
1363  mpdu->GetPacket ()->PeekHeader (blockAckReq);
1364  NS_ABORT_MSG_IF (blockAckReq.IsMultiTid (), "Multi-TID BlockAckReq not supported");
1365  uint8_t tid = blockAckReq.GetTidInfo ();
1366 
1367  auto agreementIt = m_agreements.find ({sender, tid});
1368 
1369  if (agreementIt == m_agreements.end ())
1370  {
1371  NS_LOG_DEBUG ("There's not a valid agreement for this BlockAckReq");
1372  return;
1373  }
1374 
1375  agreementIt->second.NotifyReceivedBar (blockAckReq.GetStartingSequence ());
1376 
1377  NS_LOG_DEBUG ("Schedule Block Ack");
1379  agreementIt->second, hdr.GetDuration (),
1380  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (sender, txVector),
1381  rxSnr);
1382  }
1383  else
1384  {
1385  // the received control frame cannot be handled here
1386  QosFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1387  }
1388  return;
1389  }
1390 
1391  if (hdr.IsQosData () && hdr.HasData () && hdr.GetAddr1 () == m_self)
1392  {
1393  uint8_t tid = hdr.GetQosTid ();
1394 
1395  auto agreementIt = m_agreements.find ({hdr.GetAddr2 (), tid});
1396  if (agreementIt != m_agreements.end ())
1397  {
1398  // a Block Ack agreement has been established
1399  NS_LOG_DEBUG ("Received from=" << hdr.GetAddr2 ()
1400  << " (" << *mpdu << ")");
1401 
1402  agreementIt->second.NotifyReceivedMpdu (mpdu);
1403 
1404  if (!inAmpdu && hdr.GetQosAckPolicy () == WifiMacHeader::NORMAL_ACK)
1405  {
1406  NS_LOG_DEBUG ("Schedule Normal Ack");
1408  this, hdr, txVector, rxSnr);
1409  }
1410  return;
1411  }
1412  // We let the QosFrameExchangeManager handle QoS data frame not belonging
1413  // to a Block Ack agreement
1414  }
1415 
1416  QosFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1417 }
1418 
1419 void
1421  const WifiTxVector& txVector, const std::vector<bool>& perMpduStatus)
1422 {
1423  std::set<uint8_t> tids = psdu->GetTids ();
1424 
1425  // Multi-TID A-MPDUs are not supported yet
1426  if (tids.size () == 1)
1427  {
1428  uint8_t tid = *tids.begin ();
1429  WifiMacHeader::QosAckPolicy ackPolicy = psdu->GetAckPolicyForTid (tid);
1430  NS_ASSERT (psdu->GetNMpdus () > 1);
1431 
1432  if (ackPolicy == WifiMacHeader::NORMAL_ACK)
1433  {
1434  // Normal Ack or Implicit Block Ack Request
1435  NS_LOG_DEBUG ("Schedule Block Ack");
1436  auto agreementIt = m_agreements.find ({psdu->GetAddr2 (), tid});
1437  NS_ASSERT (agreementIt != m_agreements.end ());
1438 
1440  agreementIt->second, psdu->GetDuration (),
1441  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (psdu->GetAddr2 (), txVector),
1442  rxSignalInfo.snr);
1443  }
1444  }
1445 }
1446 
1447 } //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.
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
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:745
WifiTxTimer m_txTimer
the timer set upon frame transmission
virtual 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.
virtual 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:856
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:989
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.
virtual 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:707
Ptr< WifiMacQueueItem > Dequeue(void)
Dequeue the packet in the front of the queue.
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.
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
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
virtual 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...
virtual 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:1616
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:767
bool IsAction(void) const
Return true if the header is an Action header.
virtual void SetWifiMac(const Ptr< RegularWifiMac > mac) override
Set the MAC layer to use.
virtual 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:714
Reason GetReason(void) const
Get the reason why the timer was started.
void SetImmediateBlockAck()
Enable immediate BlockAck.
void FillBlockAckBitmap(CtrlBAckResponseHeader *blockAckHeader) const
Set the Starting Sequence Number subfield of the Block Ack Starting Sequence Control subfield of the ...
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.
virtual 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:199
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.
virtual void TransmissionSucceeded(void) override
Take necessary actions upon a transmission success.
virtual 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.
virtual void RetransmitMpduAfterMissedCts(Ptr< WifiMacQueueItem > mpdu) const override
Retransmit an MPDU that was not sent because a CTS was not received.
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.
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMacQueueItem > mpdu) const override
Retransmit an MPDU that was not acknowledged.
std::pair< uint16_t, uint32_t > GetSizeIfAggregateMsdu(Ptr< const WifiMacQueueItem > msdu) const
Get the size in bytes of the frame in case the given MSDU is aggregated.
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.
virtual 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)
Extraction operator for TypeId.
Definition: qos-utils.cc:120
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
virtual 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.
#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
virtual 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:932
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:1121
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:1242
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
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:927
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.
void SendAddBaRequest(Mac48Address recipient, uint8_t tid, uint16_t timeout, bool immediateBAck)
Sends an ADDBA Request to establish a block ack agreement with STA addressed by recipient for TID tid...
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)
TODO Transmit a data frame, if data is available and its trasmission plus the response fits within th...
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:1774
WifiNoProtection specifies that no protection method is used.
virtual 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 ...
virtual 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
virtual 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...
virtual 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
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:780
ActionValue GetAction()
Return the action value.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
Headers for BlockAckRequest.
Definition: ctrl-headers.h:47
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
virtual 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:728
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...
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.