A Discrete-Event Network Simulator
API
block-ack-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009, 2010 MIRKO BANCHI
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: Mirko Banchi <mk.banchi@gmail.com>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/simulator.h"
23 #include "block-ack-manager.h"
24 #include "wifi-utils.h"
25 #include "ctrl-headers.h"
26 #include "mgt-headers.h"
27 #include "wifi-mac-queue.h"
28 #include "qos-utils.h"
29 #include "wifi-tx-vector.h"
30 #include <optional>
31 
32 namespace ns3 {
33 
34 NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
35 
37 {
38  NS_LOG_FUNCTION (this);
39 }
40 
41 Bar::Bar (Ptr<const WifiMacQueueItem> bar, uint8_t tid, bool skipIfNoDataQueued)
42  : bar (bar),
43  tid (tid),
44  skipIfNoDataQueued (skipIfNoDataQueued)
45 {
46  NS_LOG_FUNCTION (this << *bar << +tid << skipIfNoDataQueued);
47 }
48 
50 
51 TypeId
53 {
54  static TypeId tid = TypeId ("ns3::BlockAckManager")
55  .SetParent<Object> ()
56  .SetGroupName ("Wifi")
57  .AddConstructor<BlockAckManager> ()
58  .AddTraceSource ("AgreementState",
59  "The state of the ADDBA handshake",
61  "ns3::BlockAckManager::AgreementStateTracedCallback")
62  ;
63  return tid;
64 }
65 
67 {
68  NS_LOG_FUNCTION (this);
69 }
70 
72 {
73  NS_LOG_FUNCTION (this);
74 }
75 
76 void
78 {
79  NS_LOG_FUNCTION (this);
80  m_agreements.clear ();
81  m_bars.clear ();
82  m_queue = nullptr;
83 }
84 
85 bool
86 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
87 {
88  NS_LOG_FUNCTION (this << recipient << +tid);
89  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
90 }
91 
92 bool
95 {
96  AgreementsCI it;
97  it = m_agreements.find (std::make_pair (recipient, tid));
98  if (it != m_agreements.end ())
99  {
100  switch (state)
101  {
103  return it->second.first.IsEstablished ();
105  return it->second.first.IsPending ();
107  return it->second.first.IsRejected ();
109  return it->second.first.IsNoReply ();
111  return it->second.first.IsReset ();
112  default:
113  NS_FATAL_ERROR ("Invalid state for block ack agreement");
114  }
115  }
116  return false;
117 }
118 
119 void
120 BlockAckManager::CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient, bool htSupported)
121 {
122  NS_LOG_FUNCTION (this << reqHdr << recipient << htSupported);
123  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
124  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
125  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
126  /* For now we assume that originator doesn't use this field. Use of this field
127  is mandatory only for recipient */
128  agreement.SetBufferSize (reqHdr->GetBufferSize());
129  agreement.SetTimeout (reqHdr->GetTimeout ());
130  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
131  agreement.SetHtSupported (htSupported);
132  if (reqHdr->IsImmediateBlockAck ())
133  {
134  agreement.SetImmediateBlockAck ();
135  }
136  else
137  {
138  agreement.SetDelayedBlockAck ();
139  }
140  uint8_t tid = reqHdr->GetTid ();
143  PacketQueue queue;
144  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
145  if (ExistsAgreement (recipient, tid))
146  {
147  // Delete agreement if it exists and in RESET state
149  m_agreements.erase (key);
150  }
151  m_agreements.insert (std::make_pair (key, value));
152  m_blockPackets (recipient, reqHdr->GetTid ());
153 }
154 
155 void
157 {
158  NS_LOG_FUNCTION (this << recipient << +tid);
159  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
160  if (it != m_agreements.end ())
161  {
162  m_agreements.erase (it);
163  //remove scheduled BAR
164  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
165  {
166  if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
167  {
168  i = m_bars.erase (i);
169  }
170  else
171  {
172  i++;
173  }
174  }
175  }
176 }
177 
178 void
180  uint16_t startingSeq)
181 {
182  NS_LOG_FUNCTION (this << respHdr << recipient << startingSeq);
183  uint8_t tid = respHdr->GetTid ();
184  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
185  if (it != m_agreements.end ())
186  {
187  OriginatorBlockAckAgreement& agreement = it->second.first;
188  agreement.SetBufferSize (respHdr->GetBufferSize ());
189  agreement.SetTimeout (respHdr->GetTimeout ());
190  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
191  agreement.SetStartingSequence (startingSeq);
192  agreement.InitTxWindow ();
193  if (respHdr->IsImmediateBlockAck ())
194  {
195  agreement.SetImmediateBlockAck ();
196  }
197  else
198  {
199  agreement.SetDelayedBlockAck ();
200  }
201  if (!it->second.first.IsEstablished ())
202  {
204  }
206  if (agreement.GetTimeout () != 0)
207  {
208  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
211  this,
212  recipient, tid);
213  }
214  }
215  m_unblockPackets (recipient, tid);
216 }
217 
218 void
220 {
221  NS_LOG_FUNCTION (this << *mpdu);
222  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
223 
224  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
225  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
226 
227  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
228  NS_ASSERT (agreementIt != m_agreements.end ());
229 
230  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
231 
232  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
233  {
234  NS_LOG_DEBUG ("Got an old packet. Do nothing");
235  return;
236  }
237 
238  // store the packet and keep the list sorted in increasing order of sequence number
239  // with respect to the starting sequence number
240  auto it = agreementIt->second.second.rbegin ();
241  while (it != agreementIt->second.second.rend ())
242  {
243  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
244  {
245  NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
246  return;
247  }
248 
249  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
250 
251  if (mpduDist > dist ||
252  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () > (*it)->GetHeader ().GetFragmentNumber ()))
253  {
254  break;
255  }
256 
257  it++;
258  }
259  agreementIt->second.second.insert (it.base (), mpdu);
260  agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
261  mpdu->SetInFlight ();
262 }
263 
265 BlockAckManager::GetBar (bool remove, uint8_t tid, Mac48Address address)
266 {
267  Time now = Simulator::Now ();
269  // remove all expired MPDUs from the head of the MAC queue, so that
270  // BlockAckRequest frames (if needed) are scheduled
271  m_queue->IsEmpty ();
272 
273  auto nextBar = m_bars.begin ();
274 
275  while (nextBar != m_bars.end ())
276  {
277  Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
278 
279  if (address != Mac48Address::GetBroadcast () && tid != 8
280  && (!nextBar->bar->GetHeader ().IsBlockAckReq ()
281  || address != recipient || tid != nextBar->tid))
282  {
283  // we can only return a BAR addressed to the given station and for the given TID
284  nextBar++;
285  continue;
286  }
287  if (nextBar->bar->GetHeader ().IsBlockAckReq ())
288  {
289  AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
290  if (it == m_agreements.end ())
291  {
292  // BA agreement was torn down; remove this BAR and continue
293  nextBar = m_bars.erase (nextBar);
294  continue;
295  }
296  if (nextBar->skipIfNoDataQueued
297  && m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == nullptr)
298  {
299  // skip this BAR as there is no data queued
300  nextBar++;
301  continue;
302  }
303  // remove expired outstanding MPDUs and update the starting sequence number
304  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
305  {
306  if (!(*mpduIt)->IsQueued ())
307  {
308  // the MPDU is no longer in the EDCA queue
309  mpduIt = it->second.second.erase (mpduIt);
310  continue;
311  }
312 
313  if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= now)
314  {
315  // MPDU expired
316  it->second.first.NotifyDiscardedMpdu (*mpduIt);
317  // Remove from the EDCA queue and fire the Expired trace source, but the
318  // consequent call to NotifyDiscardedMpdu does nothing (in particular,
319  // does not schedule a BAR) because we have advanced the transmit window
320  // and hence this MPDU became an old packet
321  m_queue->TtlExceeded (*mpduIt, now);
322  mpduIt = it->second.second.erase (mpduIt);
323  }
324  else
325  {
326  // MPDUs are typically in increasing order of remaining lifetime
327  break;
328  }
329  }
330  // update BAR if the starting sequence number changed
331  CtrlBAckRequestHeader reqHdr;
332  nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
333  if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
334  {
335  reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
336  Ptr<Packet> packet = Create<Packet> ();
337  packet->AddHeader (reqHdr);
338  nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
339  }
340  }
341 
342  bar = nextBar->bar;
343  if (remove)
344  {
345  m_bars.erase (nextBar);
346  }
347  break;
348  }
349  return bar;
350 }
351 
352 uint32_t
354 {
355  NS_LOG_FUNCTION (this << recipient << +tid);
356  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
357  if (it == m_agreements.end ())
358  {
359  return 0;
360  }
361  return it->second.second.size ();
362 }
363 
364 void
366 {
367  NS_LOG_FUNCTION (this << +nPackets);
368  m_blockAckThreshold = nPackets;
369 }
370 
373  const AgreementsI& it, const Time& now)
374 {
375  NS_LOG_FUNCTION (this << **mpduIt << +static_cast<uint8_t> (status));
376 
377  if (!(*mpduIt)->IsQueued ())
378  {
379  // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
380  // removed by another method), remove from the queue of in flight MPDUs
381  NS_LOG_DEBUG ("MPDU is not stored in the EDCA queue, drop MPDU");
382  return it->second.second.erase (mpduIt);
383  }
384 
385  if (status == ACKNOWLEDGED)
386  {
387  // the MPDU has to be dequeued from the EDCA queue
388  m_queue->DequeueIfQueued (*mpduIt);
389  return it->second.second.erase (mpduIt);
390  }
391 
392  WifiMacHeader& hdr = (*mpduIt)->GetHeader ();
393 
394  NS_ASSERT (hdr.GetAddr1 () == it->first.first);
395  NS_ASSERT (hdr.IsQosData () && hdr.GetQosTid () == it->first.second);
396 
397  if (it->second.first.GetDistance (hdr.GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
398  {
399  NS_LOG_DEBUG ("Old packet. Remove from the EDCA queue, too");
401  {
402  m_droppedOldMpduCallback (*mpduIt);
403  }
404  m_queue->Remove (*mpduIt, false);
405  return it->second.second.erase (mpduIt);
406  }
407 
408  std::optional<PacketQueueI> prevIt;
409  if (mpduIt != it->second.second.begin ())
410  {
411  prevIt = std::prev (mpduIt);
412  }
413 
414  if (m_queue->TtlExceeded (*mpduIt, now))
415  {
416  // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
417  // and fired the Expired trace source, which called NotifyDiscardedMpdu,
418  // which removed this MPDU (and possibly others) from the in flight queue as well
419  NS_LOG_DEBUG ("MSDU lifetime expired, drop MPDU");
420  return (prevIt.has_value () ? std::next (prevIt.value ()) : it->second.second.begin ());
421  }
422 
423  if (status == STAY_INFLIGHT)
424  {
425  // the MPDU has to stay in flight, do nothing
426  return ++mpduIt;
427  }
428 
429  NS_ASSERT (status == TO_RETRANSMIT);
430  (*mpduIt)->GetHeader ().SetRetry ();
431  (*mpduIt)->ResetInFlight (); // no longer in flight; will be if retransmitted
432 
433  return it->second.second.erase (mpduIt);
434 }
435 
436 void
438 {
439  NS_LOG_FUNCTION (this << *mpdu);
440  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
441 
442  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
443  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
445 
446  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
447  NS_ASSERT (it != m_agreements.end ());
448 
449  it->second.first.NotifyAckedMpdu (mpdu);
450 
451  // remove the acknowledged frame from the queue of outstanding packets
452  for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); ++queueIt)
453  {
454  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
455  {
457  break;
458  }
459  }
460 }
461 
462 void
464 {
465  NS_LOG_FUNCTION (this << *mpdu);
466  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
467 
468  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
469  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
471 
472  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
473  NS_ASSERT (it != m_agreements.end ());
474 
475  // remove the frame from the queue of outstanding packets (it will be re-inserted
476  // if retransmitted)
477  for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); ++queueIt)
478  {
479  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
480  {
482  break;
483  }
484  }
485 }
486 
487 std::pair<uint16_t,uint16_t>
489  const std::set<uint8_t>& tids, size_t index)
490 {
491  NS_LOG_FUNCTION (this << blockAck << recipient << index);
492  uint16_t nSuccessfulMpdus = 0;
493  uint16_t nFailedMpdus = 0;
494 
495  NS_ABORT_MSG_IF (blockAck.IsBasic (), "Basic Block Ack is not supported");
496  NS_ABORT_MSG_IF (blockAck.IsMultiTid (), "Multi-TID Block Ack is not supported");
497 
498  uint8_t tid = blockAck.GetTidInfo (index);
499  // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
500  // use the TID passed by the caller.
501  if (tid == 14)
502  {
503  NS_ASSERT (blockAck.GetAckType (index) && tids.size () == 1);
504  tid = *tids.begin ();
505  }
507  {
508  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
509 
510  if (it->second.first.m_inactivityEvent.IsRunning ())
511  {
512  /* Upon reception of a BlockAck frame, the inactivity timer at the
513  originator must be reset.
514  For more details see section 11.5.3 in IEEE802.11e standard */
515  it->second.first.m_inactivityEvent.Cancel ();
516  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
517  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
519  this,
520  recipient, tid);
521  }
522 
523  NS_ASSERT (blockAck.IsCompressed () || blockAck.IsExtendedCompressed () || blockAck.IsMultiSta ());
524  Time now = Simulator::Now ();
525 
526  for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); )
527  {
528  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
529  if (blockAck.IsPacketReceived (currentSeq, index))
530  {
531  it->second.first.NotifyAckedMpdu (*queueIt);
532  nSuccessfulMpdus++;
533  if (!m_txOkCallback.IsNull ())
534  {
535  m_txOkCallback (*queueIt);
536  }
537  queueIt = HandleInFlightMpdu (queueIt, ACKNOWLEDGED, it, now);
538  }
539  else
540  {
541  nFailedMpdus++;
542  if (!m_txFailedCallback.IsNull ())
543  {
544  m_txFailedCallback (*queueIt);
545  }
546  queueIt = HandleInFlightMpdu (queueIt, TO_RETRANSMIT, it, now);
547  }
548  }
549  }
550  return {nSuccessfulMpdus, nFailedMpdus};
551 }
552 
553 void
555 {
556  NS_LOG_FUNCTION (this << recipient << +tid);
558  {
559  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
560  Time now = Simulator::Now ();
561 
562  // remove all packets from the queue of outstanding packets (they will be
563  // re-inserted if retransmitted)
564  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
565  {
566  mpduIt = HandleInFlightMpdu (mpduIt, TO_RETRANSMIT, it, now);
567  }
568  }
569 }
570 
571 void
573 {
574  NS_LOG_FUNCTION (this << *mpdu);
575 
576  if (!mpdu->GetHeader ().IsQosData ())
577  {
578  NS_LOG_DEBUG ("Not a QoS Data frame");
579  return;
580  }
581 
582  if (!mpdu->GetHeader ().IsRetry () && !mpdu->IsInFlight ())
583  {
584  NS_LOG_DEBUG ("This frame has never been transmitted");
585  return;
586  }
587 
588  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
589  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
591  {
592  NS_LOG_DEBUG ("No established Block Ack agreement");
593  return;
594  }
595 
596  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
597  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
598  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
599  {
600  NS_LOG_DEBUG ("Discarded an old frame");
601  return;
602  }
603 
604  // actually advance the transmit window
605  it->second.first.NotifyDiscardedMpdu (mpdu);
606 
607  // remove old MPDUs from the EDCA queue and from the in flight queue
608  // (including the given MPDU which became old after advancing the transmit window)
609  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
610  {
611  if (it->second.first.GetDistance ((*mpduIt)->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
612  {
613  NS_LOG_DEBUG ("Dropping old MPDU: " << **mpduIt);
614  m_queue->DequeueIfQueued (*mpduIt);
616  {
617  m_droppedOldMpduCallback (*mpduIt);
618  }
619  mpduIt = it->second.second.erase (mpduIt);
620  }
621  else
622  {
623  break; // MPDUs are in increasing order of sequence number in the in flight queue
624  }
625  }
626 
627  // schedule a BlockAckRequest
628  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
629  Ptr<Packet> bar = Create<Packet> ();
630  bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
631 
632  WifiMacHeader hdr;
634  hdr.SetAddr1 (recipient);
635  hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
636  hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
637  hdr.SetDsNotTo ();
638  hdr.SetDsNotFrom ();
639  hdr.SetNoRetry ();
640  hdr.SetNoMoreFragments ();
641 
642  ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
643 }
644 
647 {
648  NS_LOG_FUNCTION (this << recipient << +tid);
649  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
650  NS_ASSERT (it != m_agreements.end ());
651 
652  CtrlBAckRequestHeader reqHdr;
653  reqHdr.SetType ((*it).second.first.GetBlockAckReqType ());
654  reqHdr.SetTidInfo (tid);
655  reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
656  return reqHdr;
657 }
658 
659 void
661 {
662  NS_LOG_FUNCTION (this << *bar);
663  NS_ASSERT (bar->GetHeader ().IsBlockAckReq () || bar->GetHeader ().IsTrigger ());
664 
665  uint8_t tid = 0;
666  if (bar->GetHeader ().IsBlockAckReq ())
667  {
668  CtrlBAckRequestHeader reqHdr;
669  bar->GetPacket ()->PeekHeader (reqHdr);
670  tid = reqHdr.GetTidInfo ();
671  }
672 #ifdef NS3_BUILD_PROFILE_DEBUG
673  else
674  {
675  CtrlTriggerHeader triggerHdr;
676  bar->GetPacket ()->PeekHeader (triggerHdr);
677  NS_ASSERT (triggerHdr.IsMuBar ());
678  }
679 #endif
680  Bar request (bar, tid, skipIfNoDataQueued);
681 
682  // if a BAR for the given agreement is present, replace it with the new one
683  std::list<Bar>::const_iterator i = m_bars.end ();
684 
685  if (bar->GetHeader ().IsBlockAckReq ())
686  {
687  for (i = m_bars.begin (); i != m_bars.end (); i++)
688  {
689  if (i->bar->GetHeader ().IsBlockAckReq ()
690  && i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
691  {
692  i = m_bars.erase (i);
693  break;
694  }
695  }
696  }
697 
698  if (bar->GetHeader ().IsRetry ())
699  {
700  m_bars.push_front (request);
701  }
702  else
703  {
704  m_bars.insert (i, request);
705  }
706 }
707 
708 void
710 {
711  NS_LOG_FUNCTION (this << recipient << +tid);
712  m_blockAckInactivityTimeout (recipient, tid, true);
713 }
714 
715 void
716 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
717 {
718  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
719  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
720  NS_ASSERT (it != m_agreements.end ());
721  if (!it->second.first.IsEstablished ())
722  {
724  }
725  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
726  it->second.first.SetStartingSequence (startingSeq);
727 }
728 
729 void
731 {
732  NS_LOG_FUNCTION (this << recipient << +tid);
733  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
734  NS_ASSERT (it != m_agreements.end ());
735  if (!it->second.first.IsRejected ())
736  {
738  }
739  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
740 }
741 
742 void
744 {
745  NS_LOG_FUNCTION (this << recipient << +tid);
746  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
747  NS_ASSERT (it != m_agreements.end ());
748  if (!it->second.first.IsNoReply ())
749  {
751  }
752  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
753  m_unblockPackets (recipient, tid);
754 }
755 
756 void
758 {
759  NS_LOG_FUNCTION (this << recipient << +tid);
760  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
761  NS_ASSERT (it != m_agreements.end ());
762  if (!it->second.first.IsReset ())
763  {
765  }
766  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
767 }
768 
769 void
771 {
772  NS_LOG_FUNCTION (this << queue);
773  m_queue = queue;
774 }
775 
776 bool
777 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
778 {
779  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
781  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
782  {
783  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
784  GetNBufferedPackets (recipient, tid);
785  if (packets >= m_blockAckThreshold)
786  {
787  NotifyAgreementEstablished (recipient, tid, startingSeq);
788  return true;
789  }
790  }
791  return false;
792 }
793 
795 {
797  {
798  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
799  NS_ASSERT (it != m_agreements.end ());
800 
801  Time now = Simulator::Now ();
802 
803  // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
804  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
805  {
806  // remove MPDU if old or with expired lifetime
807  mpduIt = HandleInFlightMpdu (mpduIt, STAY_INFLIGHT, it, now);
808 
809  if (mpduIt != it->second.second.begin ())
810  {
811  // the MPDU has not been removed
812  return true;
813  }
814  }
815  }
816 
817  // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
818  // has destroyed the agreement, hence we get here and correctly return false
819  return false;
820 }
821 
822 void
824 {
825  NS_LOG_FUNCTION (this << &callback);
826  m_blockAckInactivityTimeout = callback;
827 }
828 
829 void
831 {
832  NS_LOG_FUNCTION (this << &callback);
833  m_blockPackets = callback;
834 }
835 
836 void
838 {
839  NS_LOG_FUNCTION (this << &callback);
840  m_unblockPackets = callback;
841 }
842 
843 void
845 {
846  m_txOkCallback = callback;
847 }
848 
849 void
851 {
852  m_txFailedCallback = callback;
853 }
854 
855 void
857 {
858  m_droppedOldMpduCallback = callback;
859 }
860 
861 uint16_t
863 {
864  uint16_t size = 0;
865  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
866  if (it != m_agreements.end ())
867  {
868  size = it->second.first.GetBufferSize ();
869  }
870  return size;
871 }
872 
874 BlockAckManager::GetBlockAckReqType (Mac48Address recipient, uint8_t tid) const
875 {
876  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
877  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
878  return it->second.first.GetBlockAckReqType ();
879 }
880 
882 BlockAckManager::GetBlockAckType (Mac48Address recipient, uint8_t tid) const
883 {
884  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
885  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
886  return it->second.first.GetBlockAckType ();
887 }
888 
889 uint16_t
891 {
892  uint16_t seqNum = 0;
893  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
894  if (it != m_agreements.end ())
895  {
896  seqNum = it->second.first.GetStartingSequence ();
897  }
898  return seqNum;
899 }
900 
901 } //namespace ns3
void SetImmediateBlockAck(void)
Set block ack policy to immediate Ack.
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
void SetDelayedBlockAck(void)
Set block ack policy to delayed Ack.
uint16_t GetTimeout(void) const
Return the timeout.
EventId m_inactivityEvent
inactivity event
void SetBufferSize(uint16_t bufferSize)
Set buffer size.
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
void SetTimeout(uint16_t timeout)
Set timeout.
void SetHtSupported(bool htSupported)
Enable or disable HT support.
Manages all block ack agreements for an originator station.
void StorePacket(Ptr< WifiMacQueueItem > mpdu)
std::list< Ptr< WifiMacQueueItem > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
void SetTxFailedCallback(TxFailed callback)
void NotifyAgreementRejected(Mac48Address recipient, uint8_t tid)
CtrlBAckRequestHeader GetBlockAckReqHeader(Mac48Address recipient, uint8_t tid) const
Callback< void, Mac48Address, uint8_t > m_unblockPackets
unblock packets callback
void SetQueue(const Ptr< WifiMacQueue > queue)
void SetTxOkCallback(TxOk callback)
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
uint8_t m_blockAckThreshold
block ack threshold
void SetBlockAckThreshold(uint8_t nPackets)
DroppedOldMpdu m_droppedOldMpduCallback
the dropped MPDU callback
std::list< Ptr< WifiMacQueueItem > > PacketQueue
typedef for a list of WifiMacQueueItem.
void NotifyAgreementEstablished(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
void SetDroppedOldMpduCallback(DroppedOldMpdu callback)
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
void NotifyDiscardedMpdu(Ptr< const WifiMacQueueItem > mpdu)
void NotifyGotAck(Ptr< const WifiMacQueueItem > mpdu)
Invoked upon receipt of an Ack frame after the transmission of a QoS data frame sent under an establi...
TxFailed m_txFailedCallback
transmit failed callback
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
Ptr< WifiMacQueue > m_queue
queue
std::pair< uint16_t, uint16_t > NotifyGotBlockAck(const CtrlBAckResponseHeader &blockAck, Mac48Address recipient, const std::set< uint8_t > &tids, size_t index=0)
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent to the recipient.
void NotifyAgreementReset(Mac48Address recipient, uint8_t tid)
void NotifyMissedAck(Ptr< WifiMacQueueItem > mpdu)
Invoked upon missed reception of an Ack frame after the transmission of a QoS data frame sent under a...
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_agreementState
The trace source fired when a state transition occurred.
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::const_iterator AgreementsCI
typedef for a const iterator for Agreements.
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient, uint16_t startingSeq)
Ptr< const WifiMacQueueItem > GetBar(bool remove=true, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast())
Returns the next BlockAckRequest or MU-BAR Trigger Frame to send, if any.
uint16_t GetRecipientBufferSize(Mac48Address recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
void NotifyAgreementNoReply(Mac48Address recipient, uint8_t tid)
bool NeedBarRetransmission(uint8_t tid, Mac48Address recipient)
This function returns true if a block ack agreement is established with the given recipient for the g...
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent by the recipient.
static TypeId GetTypeId(void)
Get the type ID.
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, TID), a set of packets for whi...
void CreateAgreement(const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient, bool htSupported=true)
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
BlockAck inactivity timeout callback.
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::iterator AgreementsI
typedef for an iterator for Agreements.
TxOk m_txOkCallback
transmit OK callback
MpduStatus
Enumeration for the statuses of a buffered MPDU.
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
void DoDispose() override
Destructor implementation.
uint32_t GetNBufferedPackets(Mac48Address recipient, uint8_t tid) const
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
uint16_t GetOriginatorStartingSequence(Mac48Address recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
std::list< Bar > m_bars
list of BARs
PacketQueueI HandleInFlightMpdu(PacketQueueI mpduIt, MpduStatus status, const AgreementsI &it, const Time &now)
Handle the given in flight MPDU based on its given status.
Callback template class.
Definition: callback.h:1279
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1386
Headers for BlockAckRequest.
Definition: ctrl-headers.h:49
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
Headers for BlockAck response.
Definition: ctrl-headers.h:202
bool IsCompressed(void) const
Check if the current BA policy is Compressed Block Ack.
bool IsPacketReceived(uint16_t seq, std::size_t index=0) const
Check if the packet with the given sequence number was acknowledged in this BlockAck response.
bool IsBasic(void) const
Check if the current BA policy is Basic Block Ack.
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
bool IsExtendedCompressed(void) const
Check if the current BA policy is Extended Compressed Block Ack.
bool IsMultiTid(void) const
Check if the current BA policy is Multi-TID Block Ack.
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
Headers for Trigger frames.
Definition: ctrl-headers.h:886
bool IsMuBar(void) const
Check if this is a MU-BAR Trigger frame.
an EUI-48 address
Definition: mac48-address.h:44
static Mac48Address GetBroadcast(void)
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.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
uint16_t GetBufferSize(void) const
Return the buffer size.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1150
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.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
A base class which provides memory management and object aggregation.
Definition: object.h:88
Maintains the state and information about transmitted MPDUs with Ack Policy set to Block Ack for an o...
void InitTxWindow(void)
Initialize the originator's transmit window by setting its size and starting sequence number equal to...
void SetState(State state)
Set the current state.
State
Represents the state for this agreement.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:556
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Implements the IEEE 802.11 MAC header.
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
void SetNoRetry(void)
Un-set the Retry bit in the Frame Control field.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetNoMoreFragments(void)
Un-set the More Fragment bit in the Frame Control Field.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
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.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
#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_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h: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(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
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
bool QosUtilsIsOldPacket(uint16_t startingSeq, uint16_t seqNumber)
This function checks if packet with sequence number seqNumber is an "old" packet.
Definition: qos-utils.cc:178
address
Definition: first.py:44
Every class exported by the ns3 library is enclosed in the ns3 namespace.
@ WIFI_MAC_CTL_BACKREQ
const uint16_t SEQNO_SPACE_HALF_SIZE
Size of the half the space of sequence numbers (used to determine old packets)
Definition: wifi-utils.h:134
ns3::Time timeout
BlockAckRequest frame information.
uint8_t tid
TID (unused if MU-BAR)
bool skipIfNoDataQueued
do not send if there is no data queued (unused if MU-BAR)
Ptr< const WifiMacQueueItem > bar
BlockAckRequest or MU-BAR Trigger Frame.
The different BlockAckRequest variants.
The different BlockAck variants.