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"
25 #include "ctrl-headers.h"
26 #include "mgt-headers.h"
27 #include "wifi-mac-queue.h"
28 #include "mac-tx-middle.h"
29 #include "qos-utils.h"
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
34 
36 {
37  NS_LOG_FUNCTION (this);
38 }
39 
40 Bar::Bar (Ptr<const WifiMacQueueItem> bar, uint8_t tid, bool skipIfNoDataQueued)
41  : bar (bar),
42  tid (tid),
43  skipIfNoDataQueued (skipIfNoDataQueued)
44 {
45  NS_LOG_FUNCTION (this << *bar << +tid << skipIfNoDataQueued);
46 }
47 
49 
50 TypeId
52 {
53  static TypeId tid = TypeId ("ns3::BlockAckManager")
54  .SetParent<Object> ()
55  .SetGroupName ("Wifi")
56  .AddConstructor<BlockAckManager> ()
57  .AddTraceSource ("AgreementState",
58  "The state of the ADDBA handshake",
60  "ns3::BlockAckManager::AgreementStateTracedCallback")
61  ;
62  return tid;
63 }
64 
66 {
67  NS_LOG_FUNCTION (this);
68  m_retryPackets = CreateObject<WifiMacQueue> ();
69  m_retryPackets->TraceConnectWithoutContext ("Expired", MakeCallback (&BlockAckManager::NotifyDiscardedMpdu, this));
70 }
71 
73 {
74  NS_LOG_FUNCTION (this);
75  m_queue = 0;
76  m_agreements.clear ();
77  m_retryPackets = 0;
78 }
79 
80 bool
81 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
82 {
83  NS_LOG_FUNCTION (this << recipient << +tid);
84  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
85 }
86 
87 bool
90 {
91  AgreementsCI it;
92  it = m_agreements.find (std::make_pair (recipient, tid));
93  if (it != m_agreements.end ())
94  {
95  switch (state)
96  {
98  return it->second.first.IsEstablished ();
100  return it->second.first.IsPending ();
102  return it->second.first.IsRejected ();
104  return it->second.first.IsNoReply ();
106  return it->second.first.IsReset ();
107  default:
108  NS_FATAL_ERROR ("Invalid state for block ack agreement");
109  }
110  }
111  return false;
112 }
113 
114 void
116 {
117  NS_LOG_FUNCTION (this << reqHdr << recipient);
118  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
119  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
120  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
121  /* For now we assume that originator doesn't use this field. Use of this field
122  is mandatory only for recipient */
123  agreement.SetBufferSize (reqHdr->GetBufferSize());
124  agreement.SetTimeout (reqHdr->GetTimeout ());
125  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
126  agreement.SetHtSupported (m_stationManager->GetHtSupported ());
127  if (reqHdr->IsImmediateBlockAck ())
128  {
129  agreement.SetImmediateBlockAck ();
130  }
131  else
132  {
133  agreement.SetDelayedBlockAck ();
134  }
135  uint8_t tid = reqHdr->GetTid ();
137  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
138  PacketQueue queue;
139  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
140  if (ExistsAgreement (recipient, tid))
141  {
142  // Delete agreement if it exists and in RESET state
144  m_agreements.erase (key);
145  }
146  m_agreements.insert (std::make_pair (key, value));
147  m_blockPackets (recipient, reqHdr->GetTid ());
148 }
149 
150 void
152 {
153  NS_LOG_FUNCTION (this << recipient << +tid);
154  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
155  if (it != m_agreements.end ())
156  {
157  for (WifiMacQueue::ConstIterator i = m_retryPackets->begin (); i != m_retryPackets->end (); )
158  {
159  if ((*i)->GetHeader ().GetAddr1 () == recipient && (*i)->GetHeader ().GetQosTid () == tid)
160  {
161  i = m_retryPackets->Remove (i);
162  }
163  else
164  {
165  i++;
166  }
167  }
168  m_agreements.erase (it);
169  //remove scheduled BAR
170  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
171  {
172  if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
173  {
174  i = m_bars.erase (i);
175  }
176  else
177  {
178  i++;
179  }
180  }
181  }
182 }
183 
184 void
186 {
187  NS_LOG_FUNCTION (this << respHdr << recipient);
188  uint8_t tid = respHdr->GetTid ();
189  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
190  if (it != m_agreements.end ())
191  {
192  OriginatorBlockAckAgreement& agreement = it->second.first;
193  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
194  agreement.SetTimeout (respHdr->GetTimeout ());
195  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
196  // When the Add BA Response is received, there may be a packet transmitted
197  // under the normal ack policy that needs to be retransmitted. If so, such
198  // packet is placed in the retransmit queue. If this is the case, the starting
199  // sequence number is the sequence number of such packet. Otherwise, it is
200  // the sequence number that will be assigned to the next packet to be transmitted.
201  uint16_t startSeq;
202  WifiMacQueue::ConstIterator mpduIt = m_retryPackets->PeekByTidAndAddress (tid, recipient);
203  if (mpduIt != m_retryPackets->end ())
204  {
205  startSeq = (*mpduIt)->GetHeader ().GetSequenceNumber ();
206  }
207  else
208  {
209  startSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
210  }
211  agreement.SetStartingSequence (startSeq);
212  agreement.InitTxWindow ();
213  if (respHdr->IsImmediateBlockAck ())
214  {
215  agreement.SetImmediateBlockAck ();
216  }
217  else
218  {
219  agreement.SetDelayedBlockAck ();
220  }
221  if (!it->second.first.IsEstablished ())
222  {
224  }
226  if (agreement.GetTimeout () != 0)
227  {
228  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
231  this,
232  recipient, tid);
233  }
234  }
235  m_unblockPackets (recipient, tid);
236 }
237 
240 {
241  return m_retryPackets;
242 }
243 
244 void
246 {
247  NS_LOG_FUNCTION (this << *mpdu);
248  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
249 
250  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
251  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
252 
253  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
254  NS_ASSERT (agreementIt != m_agreements.end ());
255 
256  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
257 
258  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
259  {
260  NS_LOG_DEBUG ("Got an old packet. Do nothing");
261  return;
262  }
263 
264  // store the packet and keep the list sorted in increasing order of sequence number
265  // with respect to the starting sequence number
266  PacketQueueI it = agreementIt->second.second.begin ();
267  while (it != agreementIt->second.second.end ())
268  {
269  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
270  {
271  NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
272  return;
273  }
274 
275  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
276 
277  if (mpduDist < dist ||
278  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
279  {
280  break;
281  }
282 
283  it++;
284  }
285  agreementIt->second.second.insert (it, mpdu);
286  agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
287 }
288 
291 {
293  // remove all expired MPDUs in the retransmission queue, so that Block Ack Requests
294  // (if needed) are scheduled
295  m_retryPackets->Remove (WifiMacQueue::EMPTY, true);
296 
297  auto nextBar = m_bars.begin ();
298 
299  while (nextBar != m_bars.end ())
300  {
301  if (nextBar->bar->GetHeader ().IsBlockAckReq ())
302  {
303  Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
304  AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
305  if (it == m_agreements.end ())
306  {
307  // BA agreement was torn down; remove this BAR and continue
308  nextBar = m_bars.erase (nextBar);
309  continue;
310  }
311  if (nextBar->skipIfNoDataQueued
312  && m_retryPackets->PeekByTidAndAddress (nextBar->tid, recipient) == m_retryPackets->end ()
313  && m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == m_queue->end ())
314  {
315  // skip this BAR as there is no data queued
316  nextBar++;
317  continue;
318  }
319  // remove expired outstanding MPDUs and update the starting sequence number
320  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
321  {
322  if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= Simulator::Now ())
323  {
324  // MPDU expired
325  it->second.first.NotifyDiscardedMpdu (*mpduIt);
326  mpduIt = it->second.second.erase (mpduIt);
327  }
328  else
329  {
330  mpduIt++;
331  }
332  }
333  // update BAR if the starting sequence number changed
334  CtrlBAckRequestHeader reqHdr;
335  nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
336  if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
337  {
338  reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
339  Ptr<Packet> packet = Create<Packet> ();
340  packet->AddHeader (reqHdr);
341  nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
342  }
343  }
344 
345  bar = nextBar->bar;
346  if (remove)
347  {
348  m_bars.erase (nextBar);
349  }
350  break;
351  }
352  return bar;
353 }
354 
355 bool
357 {
358  NS_LOG_FUNCTION (this);
359  return (!m_retryPackets->IsEmpty () || GetBar (false) != 0);
360 }
361 
362 uint32_t
364 {
365  NS_LOG_FUNCTION (this << recipient << +tid);
366  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
367  if (it == m_agreements.end ())
368  {
369  return 0;
370  }
371  uint32_t nPackets = 0;
372  PacketQueueCI queueIt = (*it).second.second.begin ();
373  while (queueIt != (*it).second.second.end ())
374  {
375  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
376  nPackets++;
377  /* a fragmented packet must be counted as one packet */
378  while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
379  {
380  queueIt++;
381  }
382  }
383  return nPackets;
384 }
385 
386 void
388 {
389  NS_LOG_FUNCTION (this << +nPackets);
390  m_blockAckThreshold = nPackets;
391 }
392 
393 void
395 {
396  NS_LOG_FUNCTION (this << manager);
397  m_stationManager = manager;
398 }
399 
400 void
402 {
403  NS_LOG_FUNCTION (this << *mpdu);
404  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
405 
406  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
407  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
409 
410  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
411  NS_ASSERT (it != m_agreements.end ());
412 
413  // remove the acknowledged frame from the queue of outstanding packets
414  PacketQueueI queueIt = it->second.second.begin ();
415  while (queueIt != it->second.second.end ())
416  {
417  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
418  {
419  queueIt = it->second.second.erase (queueIt);
420  }
421  else
422  {
423  queueIt++;
424  }
425  }
426 
427  it->second.first.NotifyAckedMpdu (mpdu);
428 }
429 
430 void
432 {
433  NS_LOG_FUNCTION (this << *mpdu);
434  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
435 
436  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
437  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
439 
440  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
441  NS_ASSERT (it != m_agreements.end ());
442 
443  // remove the frame from the queue of outstanding packets (it will be re-inserted
444  // if retransmitted)
445  PacketQueueI queueIt = it->second.second.begin ();
446  while (queueIt != it->second.second.end ())
447  {
448  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
449  {
450  queueIt = it->second.second.erase (queueIt);
451  }
452  else
453  {
454  queueIt++;
455  }
456  }
457 
458  // insert in the retransmission queue
459  InsertInRetryQueue (mpdu);
460 }
461 
462 void
463 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
464 {
465  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
466  if (!blockAck->IsMultiTid ())
467  {
468  uint8_t tid = blockAck->GetTidInfo ();
470  {
471  bool foundFirstLost = false;
472  uint8_t nSuccessfulMpdus = 0;
473  uint8_t nFailedMpdus = 0;
474  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
475  PacketQueueI queueEnd = it->second.second.end ();
476 
477  if (it->second.first.m_inactivityEvent.IsRunning ())
478  {
479  /* Upon reception of a BlockAck frame, the inactivity timer at the
480  originator must be reset.
481  For more details see section 11.5.3 in IEEE802.11e standard */
482  it->second.first.m_inactivityEvent.Cancel ();
483  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
484  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
486  this,
487  recipient, tid);
488  }
489 
490  uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
491  uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
492 
493  if (blockAck->IsBasic ())
494  {
495  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
496  {
497  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
498  if (blockAck->IsFragmentReceived (currentSeq,
499  (*queueIt)->GetHeader ().GetFragmentNumber ()))
500  {
501  nSuccessfulMpdus++;
502  }
503  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
504  {
505  if (!foundFirstLost)
506  {
507  foundFirstLost = true;
508  RemoveOldPackets (recipient, tid, currentSeq);
509  }
510  nFailedMpdus++;
511  InsertInRetryQueue (*queueIt);
512  }
513  // in any case, this packet is no longer outstanding
514  queueIt = it->second.second.erase (queueIt);
515  }
516  // If all frames were acknowledged, move the transmit window past the last one
517  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
518  {
519  RemoveOldPackets (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
520  }
521  }
522  else if (blockAck->IsCompressed () || blockAck->IsExtendedCompressed ())
523  {
524  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
525  {
526  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
527  if (blockAck->IsPacketReceived (currentSeq))
528  {
529  it->second.first.NotifyAckedMpdu (*queueIt);
530  nSuccessfulMpdus++;
531  if (!m_txOkCallback.IsNull ())
532  {
533  m_txOkCallback ((*queueIt)->GetHeader ());
534  }
535  }
536  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
537  {
538  nFailedMpdus++;
539  if (!m_txFailedCallback.IsNull ())
540  {
541  m_txFailedCallback ((*queueIt)->GetHeader ());
542  }
543  InsertInRetryQueue (*queueIt);
544  }
545  // in any case, this packet is no longer outstanding
546  queueIt = it->second.second.erase (queueIt);
547  }
548  }
549  m_stationManager->ReportAmpduTxStatus (recipient, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
550  }
551  }
552  else
553  {
554  //NOT SUPPORTED FOR NOW
555  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
556  }
557 }
558 
559 void
561 {
562  NS_LOG_FUNCTION (this << recipient << +tid);
564  {
565  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
566  for (auto& item : it->second.second)
567  {
568  // Queue previously transmitted packets that do not already exist in the retry queue.
569  InsertInRetryQueue (item);
570  }
571  // remove all packets from the queue of outstanding packets (they will be
572  // re-inserted if retransmitted)
573  it->second.second.clear ();
574  }
575 }
576 
577 void
579 {
580  NS_LOG_FUNCTION (this << recipient << +tid);
582  {
583  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
584  while (!it->second.second.empty ())
585  {
586  Ptr<WifiMacQueueItem> mpdu = it->second.second.front ();
587  if (it->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
588  {
589  // old packet
590  it->second.second.pop_front ();
591  }
592  else
593  {
594  NotifyDiscardedMpdu (mpdu);
595  }
596  }
597  }
598 }
599 
600 void
602 {
603  NS_LOG_FUNCTION (this << bAckType);
604  m_blockAckType = bAckType;
605 }
606 
607 void
609 {
610  NS_LOG_FUNCTION (this << *mpdu);
611 
612  if (!mpdu->GetHeader ().IsQosData ())
613  {
614  NS_LOG_DEBUG ("Not a QoS Data frame");
615  return;
616  }
617 
618  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
619  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
621  {
622  NS_LOG_DEBUG ("No established Block Ack agreement");
623  return;
624  }
625 
626  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
627  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
628  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
629  {
630  NS_LOG_DEBUG ("Discarded an old frame");
631  return;
632  }
633 
634  // remove outstanding frames and frames in the retransmit queue with a sequence
635  // number less than or equal to the discarded MPDU
636  RemoveOldPackets (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
637  // actually advance the transmit window
638  it->second.first.NotifyDiscardedMpdu (mpdu);
639 
640  // schedule a BlockAckRequest
641  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
642  Ptr<Packet> bar = Create<Packet> ();
643  bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
644 
645  WifiMacHeader hdr;
647  hdr.SetAddr1 (recipient);
648  hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
649  hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
650  hdr.SetDsNotTo ();
651  hdr.SetDsNotFrom ();
652  hdr.SetNoRetry ();
653  hdr.SetNoMoreFragments ();
654 
655  ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
656 }
657 
660 {
661  NS_LOG_FUNCTION (this << recipient << +tid);
662  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
663  NS_ASSERT (it != m_agreements.end ());
664 
665  CtrlBAckRequestHeader reqHdr;
666  reqHdr.SetType (m_blockAckType);
667  reqHdr.SetTidInfo (tid);
668  reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
669  return reqHdr;
670 }
671 
672 void
674 {
675  NS_LOG_FUNCTION (this << *bar);
676  NS_ASSERT (bar->GetHeader ().IsBlockAckReq ());
677 
678  CtrlBAckRequestHeader reqHdr;
679  bar->GetPacket ()->PeekHeader (reqHdr);
680  uint8_t tid = reqHdr.GetTidInfo ();
681  Bar request (bar, tid, skipIfNoDataQueued);
682 
683  // if a BAR for the given agreement is present, replace it with the new one
684  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); i++)
685  {
686  if (i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
687  {
688  i = m_bars.erase (i);
689  m_bars.insert (i, request);
690  return;
691  }
692  }
693 
694  if (bar->GetHeader ().IsRetry ())
695  {
696  m_bars.push_front (request);
697  }
698  else
699  {
700  m_bars.push_back (request);
701  }
702 }
703 
704 void
706 {
707  NS_LOG_FUNCTION (this << recipient << +tid);
708  m_blockAckInactivityTimeout (recipient, tid, true);
709 }
710 
711 void
712 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
713 {
714  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
715  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
716  NS_ASSERT (it != m_agreements.end ());
717  if (!it->second.first.IsEstablished ())
718  {
720  }
721  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
722  it->second.first.SetStartingSequence (startingSeq);
723 }
724 
725 void
727 {
728  NS_LOG_FUNCTION (this << recipient << +tid);
729  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
730  NS_ASSERT (it != m_agreements.end ());
731  if (!it->second.first.IsRejected ())
732  {
734  }
735  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
736 }
737 
738 void
740 {
741  NS_LOG_FUNCTION (this << recipient << +tid);
742  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
743  NS_ASSERT (it != m_agreements.end ());
744  if (!it->second.first.IsNoReply ())
745  {
747  }
748  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
749  m_unblockPackets (recipient, tid);
750 }
751 
752 void
754 {
755  NS_LOG_FUNCTION (this << recipient << +tid);
756  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
757  NS_ASSERT (it != m_agreements.end ());
758  if (!it->second.first.IsReset ())
759  {
761  }
762  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
763 }
764 
765 void
767 {
768  NS_LOG_FUNCTION (this << queue);
769  m_queue = queue;
770 }
771 
772 bool
773 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
774 {
775  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
777  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
778  {
779  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
780  GetNBufferedPackets (recipient, tid);
781  if (packets >= m_blockAckThreshold)
782  {
783  NotifyAgreementEstablished (recipient, tid, startingSeq);
784  return true;
785  }
786  }
787  return false;
788 }
789 
791 {
793  {
794  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
795  NS_ASSERT (it != m_agreements.end ());
796 
797  // A BAR needs to be retransmitted if there is at least a non-expired outstanding MPDU
798  for (auto& mpdu : it->second.second)
799  {
800  if (mpdu->GetTimeStamp () + m_queue->GetMaxDelay () > Simulator::Now ())
801  {
802  return true;
803  }
804  }
805  }
806 
807  // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
808  // has destroyed the agreement, hence we get here and correctly return false
809  return false;
810 }
811 
812 void
814 {
815  RemoveFromRetryQueue (address, tid, seq, seq);
816 }
817 
818 void
819 BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
820 {
821  NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
822 
823  AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
824  NS_ASSERT (agreementIt != m_agreements.end ());
825 
826  /* remove retry packet iterators if they are present in retry queue */
827  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
828 
829  while (it != m_retryPackets->end ())
830  {
831  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
832 
833  if (agreementIt->second.first.GetDistance (itSeq) >= agreementIt->second.first.GetDistance (startSeq)
834  && agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (endSeq))
835  {
836  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
837  it = m_retryPackets->Remove (it);
838  it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
839  }
840  else
841  {
842  it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
843  }
844  }
845 }
846 
847 void
848 BlockAckManager::RemoveOldPackets (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
849 {
850  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
851 
852  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
853  NS_ASSERT (agreementIt != m_agreements.end ());
854  uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
855 
856  NS_ABORT_MSG_IF (agreementIt->second.first.GetDistance (startingSeq) >= SEQNO_SPACE_HALF_SIZE,
857  "The new starting sequence number is an old sequence number");
858 
859  if (startingSeq == currStartingSeq)
860  {
861  return;
862  }
863 
864  // remove packets that will become old from the retransmission queue
865  uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
866  RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
867 
868  // remove packets that will become old from the queue of outstanding packets
869  PacketQueueI it = agreementIt->second.second.begin ();
870  while (it != agreementIt->second.second.end ())
871  {
872  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
873 
874  if (agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (lastRemovedSeq))
875  {
876  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
877  it = agreementIt->second.second.erase (it);
878  }
879  else
880  {
881  it++;
882  }
883  }
884 }
885 
886 void
888 {
889  NS_LOG_FUNCTION (this << &callback);
890  m_blockAckInactivityTimeout = callback;
891 }
892 
893 void
895 {
896  NS_LOG_FUNCTION (this << &callback);
897  m_blockPackets = callback;
898 }
899 
900 void
902 {
903  NS_LOG_FUNCTION (this << &callback);
904  m_unblockPackets = callback;
905 }
906 
907 void
909 {
910  NS_LOG_FUNCTION (this << txMiddle);
911  m_txMiddle = txMiddle;
912 }
913 
914 void
916 {
917  m_txOkCallback = callback;
918 }
919 
920 void
922 {
923  m_txFailedCallback = callback;
924 }
925 
926 void
928 {
929  NS_LOG_INFO ("Adding to retry queue " << *mpdu);
930  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
931 
932  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
933  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
934 
935  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
936  NS_ASSERT (agreementIt != m_agreements.end ());
937 
938  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
939 
940  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
941  {
942  NS_LOG_DEBUG ("Got an old packet. Do nothing");
943  return;
944  }
945 
946  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
947 
948  while (it != m_retryPackets->end ())
949  {
950  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
951  {
952  NS_LOG_DEBUG ("Packet already in the retransmit queue");
953  return;
954  }
955 
956  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
957 
958  if (mpduDist < dist ||
959  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
960  {
961  break;
962  }
963 
964  it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
965  }
966  mpdu->GetHeader ().SetRetry ();
967  m_retryPackets->Insert (it, mpdu);
968 }
969 
970 uint16_t
972 {
973  uint16_t size = 0;
974  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
975  if (it != m_agreements.end ())
976  {
977  size = it->second.first.GetBufferSize ();
978  }
979  return size;
980 }
981 
982 uint16_t
984 {
985  uint16_t seqNum = 0;
986  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
987  if (it != m_agreements.end ())
988  {
989  seqNum = it->second.first.GetStartingSequence ();
990  }
991  return seqNum;
992 }
993 
994 } //namespace ns3
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
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:102
void NotifyGotBlockAck(const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
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 "...
Callback template class.
Definition: callback.h:1273
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
Maintains the state and information about transmitted MPDUs with Ack Policy set to Block Ack for an o...
void RemoveOldPackets(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
Remove packets from the retransmit queue and from the queue of outstanding packets that become old af...
std::list< Ptr< WifiMacQueueItem > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::const_iterator AgreementsCI
typedef for a const iterator for Agreements.
void CreateAgreement(const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient)
uint32_t GetNBufferedPackets(Mac48Address recipient, uint8_t tid) const
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_agreementState
The trace source fired when a state transition occurred.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint8_t m_blockAckThreshold
block ack threshold
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, TID), a set of packets for whi...
void NotifyMissedAck(Ptr< WifiMacQueueItem > mpdu)
Invoked upon missed reception of an Ack frame after the transmission of a QoS data frame sent under a...
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:1003
void SetNoMoreFragments(void)
Un-set the More Fragment bit in the Frame Control 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
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:200
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
uint16_t GetBufferSize(void) const
Return the buffer size.
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::iterator AgreementsI
typedef for an iterator for Agreements.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
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:84
uint16_t GetBufferSize(void) const
Return the buffer size.
ns3::Time timeout
CtrlBAckRequestHeader GetBlockAckReqHeader(Mac48Address recipient, uint8_t tid) const
BlockAckRequest frame information.
uint16_t GetTimeout(void) const
Return the timeout.
bool IsExtendedCompressed(void) const
Check if the current BA policy is Extended Compressed Block Ack.
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:97
TxOk m_txOkCallback
transmit OK callback
bool IsBasic(void) const
Check if the current BA policy is Basic Block Ack.
void SetType(BlockAckType type)
Set the block ack type.
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
void RemoveFromRetryQueue(Mac48Address address, uint8_t tid, uint16_t seq)
Remove an item from retransmission queue.
void SetTxFailedCallback(TxFailed callback)
uint8_t GetTid(void) const
Return the Traffic ID (TID).
void NotifyDiscardedMpdu(Ptr< const WifiMacQueueItem > mpdu)
Ptr< WifiMacQueue > GetRetransmitQueue(void)
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
bool IsCompressed(void) const
Check if the current BA policy is Compressed Block Ack.
void NotifyAgreementEstablished(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
static EventId Schedule(Time const &delay, MEM mem_ptr, OBJ obj)
Schedule an event to expire after delay.
Definition: simulator.h:1390
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
uint16_t GetTimeout(void) const
Return the timeout.
void SetQueue(const Ptr< WifiMacQueue > queue)
void SetBlockAckType(BlockAckType bAckType)
void SetWifiRemoteStationManager(const Ptr< WifiRemoteStationManager > manager)
Set up WifiRemoteStationManager associated with this BlockAckManager.
static TypeId GetTypeId(void)
Get the type ID.
bool GetHtSupported(void) const
Return whether the device has HT capability support enabled.
bool IsPacketReceived(uint16_t seq) const
Check if the packet with the given sequence number was acknowledged in this BlockAck response...
Headers for BlockAck response.
Definition: ctrl-headers.h:193
void NotifyAgreementRejected(Mac48Address recipient, uint8_t tid)
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1610
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
std::list< Ptr< WifiMacQueueItem > >::const_iterator PacketQueueCI
typedef for a const iterator for PacketQueue.
Ptr< MacTxMiddle > m_txMiddle
the MacTxMiddle
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
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...
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
static const ConstIterator EMPTY
Invalid iterator to signal an empty queue.
void SetState(State state)
Set the current state.
void SetTxOkCallback(TxOk callback)
std::string GetUniqueName(void) const
Definition: wifi-mode.cc:426
Ptr< const WifiMacQueueItem > GetBar(bool remove=true)
Returns the next BlockAckRequest to send, if any.
bool HasPackets(void)
Returns true if there are packets that need of retransmission or at least a BAR is scheduled...
uint16_t GetRecipientBufferSize(Mac48Address recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void InsertInRetryQueue(Ptr< WifiMacQueueItem > mpdu)
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
void SetNoRetry(void)
Un-set the Retry bit in the Frame Control field.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void ReportAmpduTxStatus(Mac48Address address, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
address
Definition: first.py:44
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
BlockAck inactivity timeout callback.
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...
void DiscardOutstandingMpdus(Mac48Address recipient, uint8_t tid)
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
void StorePacket(Ptr< WifiMacQueueItem > mpdu)
an EUI-48 address
Definition: mac48-address.h:43
std::list< Ptr< WifiMacQueueItem > > PacketQueue
typedef for a list of WifiMacQueueItem.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
Ptr< WifiMacQueue > m_retryPackets
This list contains all iterators to stored packets that need to be retransmitted. ...
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:193
State
Represents the state for this agreement.
void NotifyAgreementReset(Mac48Address recipient, uint8_t tid)
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set BlockAck inactivity callback.
uint16_t GetOriginatorStartingSequence(Mac48Address recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
bool IsFragmentReceived(uint16_t seq, uint8_t frag) const
Check if the packet with the given sequence number and fragment number was acknowledged in this Block...
void SetDelayedBlockAck(void)
Set block ack policy to delayed Ack.
EventId m_inactivityEvent
inactivity event
uint8_t GetTid(void) const
Return the Traffic ID (TID).
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
Callback< void, Mac48Address, uint8_t > m_unblockPackets
unblock packets callback
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
std::list< Bar > m_bars
list of BARs
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
Ptr< const WifiMacQueueItem > bar
BlockAckRequest.
void SetTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set the MacTxMiddle.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint8_t tid
TID.
void SetBlockAckThreshold(uint8_t nPackets)
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1135
BlockAckType m_blockAckType
BlockAck type.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
bool IsMultiTid(void) const
Check if the current BA policy is Multi-TID Block Ack.
void NotifyAgreementNoReply(Mac48Address recipient, uint8_t tid)
const uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:197
void SetImmediateBlockAck(void)
Set block ack policy to immediate Ack.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
void SetTimeout(uint16_t timeout)
Set timeout.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1086
A base class which provides memory management and object aggregation.
Definition: object.h:87
Manages all block ack agreements for an originator station.
Headers for BlockAckRequest.
Definition: ctrl-headers.h:41
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1372
TxFailed m_txFailedCallback
transmit failed callback
Ptr< WifiRemoteStationManager > m_stationManager
the station manager
void SetBufferSize(uint16_t bufferSize)
Set buffer size.
a unique identifier for an interface.
Definition: type-id.h:58
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
bool skipIfNoDataQueued
do not send if there is no data queued
void InitTxWindow(void)
Initialize the originator&#39;s transmit window by setting its size and starting sequence number equal to...
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Implements the IEEE 802.11 MAC header.
Ptr< WifiMacQueue > m_queue
queue
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
BlockAckType
The different block ack policies.