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 #include "wifi-tx-vector.h"
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  m_retryPackets = CreateObject<WifiMacQueue> ();
70  m_retryPackets->TraceConnectWithoutContext ("Expired", MakeCallback (&BlockAckManager::NotifyDiscardedMpdu, this));
71 }
72 
74 {
75  NS_LOG_FUNCTION (this);
76  m_queue = 0;
77  m_agreements.clear ();
78  m_retryPackets = 0;
79 }
80 
81 bool
82 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
83 {
84  NS_LOG_FUNCTION (this << recipient << +tid);
85  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
86 }
87 
88 bool
91 {
92  AgreementsCI it;
93  it = m_agreements.find (std::make_pair (recipient, tid));
94  if (it != m_agreements.end ())
95  {
96  switch (state)
97  {
99  return it->second.first.IsEstablished ();
101  return it->second.first.IsPending ();
103  return it->second.first.IsRejected ();
105  return it->second.first.IsNoReply ();
107  return it->second.first.IsReset ();
108  default:
109  NS_FATAL_ERROR ("Invalid state for block ack agreement");
110  }
111  }
112  return false;
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this << reqHdr << recipient);
119  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
120  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
121  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
122  /* For now we assume that originator doesn't use this field. Use of this field
123  is mandatory only for recipient */
124  agreement.SetBufferSize (reqHdr->GetBufferSize());
125  agreement.SetTimeout (reqHdr->GetTimeout ());
126  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
127  agreement.SetHtSupported (m_stationManager->GetHtSupported ());
128  if (reqHdr->IsImmediateBlockAck ())
129  {
130  agreement.SetImmediateBlockAck ();
131  }
132  else
133  {
134  agreement.SetDelayedBlockAck ();
135  }
136  uint8_t tid = reqHdr->GetTid ();
138  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
139  PacketQueue queue;
140  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
141  if (ExistsAgreement (recipient, tid))
142  {
143  // Delete agreement if it exists and in RESET state
145  m_agreements.erase (key);
146  }
147  m_agreements.insert (std::make_pair (key, value));
148  m_blockPackets (recipient, reqHdr->GetTid ());
149 }
150 
151 void
153 {
154  NS_LOG_FUNCTION (this << recipient << +tid);
155  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
156  if (it != m_agreements.end ())
157  {
158  for (WifiMacQueue::ConstIterator i = m_retryPackets->begin (); i != m_retryPackets->end (); )
159  {
160  if ((*i)->GetHeader ().GetAddr1 () == recipient && (*i)->GetHeader ().GetQosTid () == tid)
161  {
162  i = m_retryPackets->Remove (i);
163  }
164  else
165  {
166  i++;
167  }
168  }
169  m_agreements.erase (it);
170  //remove scheduled BAR
171  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
172  {
173  if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
174  {
175  i = m_bars.erase (i);
176  }
177  else
178  {
179  i++;
180  }
181  }
182  }
183 }
184 
185 void
187 {
188  NS_LOG_FUNCTION (this << respHdr << recipient);
189  uint8_t tid = respHdr->GetTid ();
190  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
191  if (it != m_agreements.end ())
192  {
193  OriginatorBlockAckAgreement& agreement = it->second.first;
194  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
195  agreement.SetTimeout (respHdr->GetTimeout ());
196  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
197  // When the Add BA Response is received, there may be a packet transmitted
198  // under the normal ack policy that needs to be retransmitted. If so, such
199  // packet is placed in the retransmit queue. If this is the case, the starting
200  // sequence number is the sequence number of such packet. Otherwise, it is
201  // the sequence number that will be assigned to the next packet to be transmitted.
202  uint16_t startSeq;
203  WifiMacQueue::ConstIterator mpduIt = m_retryPackets->PeekByTidAndAddress (tid, recipient);
204  if (mpduIt != m_retryPackets->end ())
205  {
206  startSeq = (*mpduIt)->GetHeader ().GetSequenceNumber ();
207  }
208  else
209  {
210  startSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
211  }
212  agreement.SetStartingSequence (startSeq);
213  agreement.InitTxWindow ();
214  if (respHdr->IsImmediateBlockAck ())
215  {
216  agreement.SetImmediateBlockAck ();
217  }
218  else
219  {
220  agreement.SetDelayedBlockAck ();
221  }
222  if (!it->second.first.IsEstablished ())
223  {
225  }
227  if (agreement.GetTimeout () != 0)
228  {
229  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
232  this,
233  recipient, tid);
234  }
235  }
236  m_unblockPackets (recipient, tid);
237 }
238 
241 {
242  return m_retryPackets;
243 }
244 
245 void
247 {
248  NS_LOG_FUNCTION (this << *mpdu);
249  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
250 
251  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
252  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
253 
254  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
255  NS_ASSERT (agreementIt != m_agreements.end ());
256 
257  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
258 
259  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
260  {
261  NS_LOG_DEBUG ("Got an old packet. Do nothing");
262  return;
263  }
264 
265  // store the packet and keep the list sorted in increasing order of sequence number
266  // with respect to the starting sequence number
267  PacketQueueI it = agreementIt->second.second.begin ();
268  while (it != agreementIt->second.second.end ())
269  {
270  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
271  {
272  NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
273  return;
274  }
275 
276  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
277 
278  if (mpduDist < dist ||
279  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
280  {
281  break;
282  }
283 
284  it++;
285  }
286  agreementIt->second.second.insert (it, mpdu);
287  agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
288 }
289 
292 {
294  // remove all expired MPDUs in the retransmission queue, so that Block Ack Requests
295  // (if needed) are scheduled
296  m_retryPackets->Remove (WifiMacQueue::EMPTY, true);
297 
298  auto nextBar = m_bars.begin ();
299 
300  while (nextBar != m_bars.end ())
301  {
302  if (nextBar->bar->GetHeader ().IsBlockAckReq ())
303  {
304  Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
305  AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
306  if (it == m_agreements.end ())
307  {
308  // BA agreement was torn down; remove this BAR and continue
309  nextBar = m_bars.erase (nextBar);
310  continue;
311  }
312  if (nextBar->skipIfNoDataQueued
313  && m_retryPackets->PeekByTidAndAddress (nextBar->tid, recipient) == m_retryPackets->end ()
314  && m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == m_queue->end ())
315  {
316  // skip this BAR as there is no data queued
317  nextBar++;
318  continue;
319  }
320  // remove expired outstanding MPDUs and update the starting sequence number
321  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
322  {
323  if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= Simulator::Now ())
324  {
325  // MPDU expired
326  it->second.first.NotifyDiscardedMpdu (*mpduIt);
327  mpduIt = it->second.second.erase (mpduIt);
328  }
329  else
330  {
331  mpduIt++;
332  }
333  }
334  // update BAR if the starting sequence number changed
335  CtrlBAckRequestHeader reqHdr;
336  nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
337  if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
338  {
339  reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
340  Ptr<Packet> packet = Create<Packet> ();
341  packet->AddHeader (reqHdr);
342  nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
343  }
344  }
345 
346  bar = nextBar->bar;
347  if (remove)
348  {
349  m_bars.erase (nextBar);
350  }
351  break;
352  }
353  return bar;
354 }
355 
356 bool
358 {
359  NS_LOG_FUNCTION (this);
360  return (!m_retryPackets->IsEmpty () || GetBar (false) != 0);
361 }
362 
363 uint32_t
365 {
366  NS_LOG_FUNCTION (this << recipient << +tid);
367  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
368  if (it == m_agreements.end ())
369  {
370  return 0;
371  }
372  uint32_t nPackets = 0;
373  PacketQueueCI queueIt = (*it).second.second.begin ();
374  while (queueIt != (*it).second.second.end ())
375  {
376  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
377  nPackets++;
378  /* a fragmented packet must be counted as one packet */
379  while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
380  {
381  queueIt++;
382  }
383  }
384  return nPackets;
385 }
386 
387 void
389 {
390  NS_LOG_FUNCTION (this << +nPackets);
391  m_blockAckThreshold = nPackets;
392 }
393 
394 void
396 {
397  NS_LOG_FUNCTION (this << manager);
398  m_stationManager = manager;
399 }
400 
401 void
403 {
404  NS_LOG_FUNCTION (this << *mpdu);
405  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
406 
407  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
408  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
410 
411  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
412  NS_ASSERT (it != m_agreements.end ());
413 
414  // remove the acknowledged frame from the queue of outstanding packets
415  PacketQueueI queueIt = it->second.second.begin ();
416  while (queueIt != it->second.second.end ())
417  {
418  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
419  {
420  queueIt = it->second.second.erase (queueIt);
421  }
422  else
423  {
424  queueIt++;
425  }
426  }
427 
428  it->second.first.NotifyAckedMpdu (mpdu);
429 }
430 
431 void
433 {
434  NS_LOG_FUNCTION (this << *mpdu);
435  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
436 
437  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
438  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
440 
441  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
442  NS_ASSERT (it != m_agreements.end ());
443 
444  // remove the frame from the queue of outstanding packets (it will be re-inserted
445  // if retransmitted)
446  PacketQueueI queueIt = it->second.second.begin ();
447  while (queueIt != it->second.second.end ())
448  {
449  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
450  {
451  queueIt = it->second.second.erase (queueIt);
452  }
453  else
454  {
455  queueIt++;
456  }
457  }
458 
459  // insert in the retransmission queue
460  InsertInRetryQueue (mpdu);
461 }
462 
463 void
464 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
465 {
466  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << dataSnr << dataTxVector);
467  if (!blockAck->IsMultiTid ())
468  {
469  uint8_t tid = blockAck->GetTidInfo ();
471  {
472  bool foundFirstLost = false;
473  uint8_t nSuccessfulMpdus = 0;
474  uint8_t nFailedMpdus = 0;
475  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
476  PacketQueueI queueEnd = it->second.second.end ();
477 
478  if (it->second.first.m_inactivityEvent.IsRunning ())
479  {
480  /* Upon reception of a BlockAck frame, the inactivity timer at the
481  originator must be reset.
482  For more details see section 11.5.3 in IEEE802.11e standard */
483  it->second.first.m_inactivityEvent.Cancel ();
484  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
485  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
487  this,
488  recipient, tid);
489  }
490 
491  uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
492  uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
493 
494  if (blockAck->IsBasic ())
495  {
496  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
497  {
498  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
499  if (blockAck->IsFragmentReceived (currentSeq,
500  (*queueIt)->GetHeader ().GetFragmentNumber ()))
501  {
502  nSuccessfulMpdus++;
503  }
504  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
505  {
506  if (!foundFirstLost)
507  {
508  foundFirstLost = true;
509  RemoveOldPackets (recipient, tid, currentSeq);
510  }
511  nFailedMpdus++;
512  InsertInRetryQueue (*queueIt);
513  }
514  // in any case, this packet is no longer outstanding
515  queueIt = it->second.second.erase (queueIt);
516  }
517  // If all frames were acknowledged, move the transmit window past the last one
518  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
519  {
520  RemoveOldPackets (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
521  }
522  }
523  else if (blockAck->IsCompressed () || blockAck->IsExtendedCompressed ())
524  {
525  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
526  {
527  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
528  if (blockAck->IsPacketReceived (currentSeq))
529  {
530  it->second.first.NotifyAckedMpdu (*queueIt);
531  nSuccessfulMpdus++;
532  if (!m_txOkCallback.IsNull ())
533  {
534  m_txOkCallback ((*queueIt)->GetHeader ());
535  }
536  }
537  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
538  {
539  nFailedMpdus++;
540  if (!m_txFailedCallback.IsNull ())
541  {
542  m_txFailedCallback ((*queueIt)->GetHeader ());
543  }
544  InsertInRetryQueue (*queueIt);
545  }
546  // in any case, this packet is no longer outstanding
547  queueIt = it->second.second.erase (queueIt);
548  }
549  }
550  m_stationManager->ReportAmpduTxStatus (recipient, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr, dataTxVector);
551  }
552  }
553  else
554  {
555  //NOT SUPPORTED FOR NOW
556  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
557  }
558 }
559 
560 void
562 {
563  NS_LOG_FUNCTION (this << recipient << +tid);
565  {
566  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
567  for (auto& item : it->second.second)
568  {
569  // Queue previously transmitted packets that do not already exist in the retry queue.
570  InsertInRetryQueue (item);
571  }
572  // remove all packets from the queue of outstanding packets (they will be
573  // re-inserted if retransmitted)
574  it->second.second.clear ();
575  }
576 }
577 
578 void
580 {
581  NS_LOG_FUNCTION (this << recipient << +tid);
583  {
584  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
585  while (!it->second.second.empty ())
586  {
587  Ptr<WifiMacQueueItem> mpdu = it->second.second.front ();
588  if (it->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
589  {
590  // old packet
591  it->second.second.pop_front ();
592  }
593  else
594  {
595  NotifyDiscardedMpdu (mpdu);
596  }
597  }
598  }
599 }
600 
601 void
603 {
604  NS_LOG_FUNCTION (this << bAckType);
605  m_blockAckType = bAckType;
606 }
607 
608 void
610 {
611  NS_LOG_FUNCTION (this << *mpdu);
612 
613  if (!mpdu->GetHeader ().IsQosData ())
614  {
615  NS_LOG_DEBUG ("Not a QoS Data frame");
616  return;
617  }
618 
619  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
620  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
622  {
623  NS_LOG_DEBUG ("No established Block Ack agreement");
624  return;
625  }
626 
627  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
628  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
629  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
630  {
631  NS_LOG_DEBUG ("Discarded an old frame");
632  return;
633  }
634 
635  // remove outstanding frames and frames in the retransmit queue with a sequence
636  // number less than or equal to the discarded MPDU
637  RemoveOldPackets (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
638  // actually advance the transmit window
639  it->second.first.NotifyDiscardedMpdu (mpdu);
640 
641  // schedule a BlockAckRequest
642  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
643  Ptr<Packet> bar = Create<Packet> ();
644  bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
645 
646  WifiMacHeader hdr;
648  hdr.SetAddr1 (recipient);
649  hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
650  hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
651  hdr.SetDsNotTo ();
652  hdr.SetDsNotFrom ();
653  hdr.SetNoRetry ();
654  hdr.SetNoMoreFragments ();
655 
656  ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
657 }
658 
661 {
662  NS_LOG_FUNCTION (this << recipient << +tid);
663  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
664  NS_ASSERT (it != m_agreements.end ());
665 
666  CtrlBAckRequestHeader reqHdr;
667  reqHdr.SetType (m_blockAckType);
668  reqHdr.SetTidInfo (tid);
669  reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
670  return reqHdr;
671 }
672 
673 void
675 {
676  NS_LOG_FUNCTION (this << *bar);
677  NS_ASSERT (bar->GetHeader ().IsBlockAckReq ());
678 
679  CtrlBAckRequestHeader reqHdr;
680  bar->GetPacket ()->PeekHeader (reqHdr);
681  uint8_t tid = reqHdr.GetTidInfo ();
682  Bar request (bar, tid, skipIfNoDataQueued);
683 
684  // if a BAR for the given agreement is present, replace it with the new one
685  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); i++)
686  {
687  if (i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
688  {
689  i = m_bars.erase (i);
690  m_bars.insert (i, request);
691  return;
692  }
693  }
694 
695  if (bar->GetHeader ().IsRetry ())
696  {
697  m_bars.push_front (request);
698  }
699  else
700  {
701  m_bars.push_back (request);
702  }
703 }
704 
705 void
707 {
708  NS_LOG_FUNCTION (this << recipient << +tid);
709  m_blockAckInactivityTimeout (recipient, tid, true);
710 }
711 
712 void
713 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
714 {
715  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
716  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
717  NS_ASSERT (it != m_agreements.end ());
718  if (!it->second.first.IsEstablished ())
719  {
721  }
722  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
723  it->second.first.SetStartingSequence (startingSeq);
724 }
725 
726 void
728 {
729  NS_LOG_FUNCTION (this << recipient << +tid);
730  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
731  NS_ASSERT (it != m_agreements.end ());
732  if (!it->second.first.IsRejected ())
733  {
735  }
736  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
737 }
738 
739 void
741 {
742  NS_LOG_FUNCTION (this << recipient << +tid);
743  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
744  NS_ASSERT (it != m_agreements.end ());
745  if (!it->second.first.IsNoReply ())
746  {
748  }
749  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
750  m_unblockPackets (recipient, tid);
751 }
752 
753 void
755 {
756  NS_LOG_FUNCTION (this << recipient << +tid);
757  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
758  NS_ASSERT (it != m_agreements.end ());
759  if (!it->second.first.IsReset ())
760  {
762  }
763  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
764 }
765 
766 void
768 {
769  NS_LOG_FUNCTION (this << queue);
770  m_queue = queue;
771 }
772 
773 bool
774 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
775 {
776  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
778  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
779  {
780  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
781  GetNBufferedPackets (recipient, tid);
782  if (packets >= m_blockAckThreshold)
783  {
784  NotifyAgreementEstablished (recipient, tid, startingSeq);
785  return true;
786  }
787  }
788  return false;
789 }
790 
792 {
794  {
795  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
796  NS_ASSERT (it != m_agreements.end ());
797 
798  // A BAR needs to be retransmitted if there is at least a non-expired outstanding MPDU
799  for (auto& mpdu : it->second.second)
800  {
801  if (mpdu->GetTimeStamp () + m_queue->GetMaxDelay () > Simulator::Now ())
802  {
803  return true;
804  }
805  }
806  }
807 
808  // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
809  // has destroyed the agreement, hence we get here and correctly return false
810  return false;
811 }
812 
813 void
815 {
816  RemoveFromRetryQueue (address, tid, seq, seq);
817 }
818 
819 void
820 BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
821 {
822  NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
823 
824  AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
825  NS_ASSERT (agreementIt != m_agreements.end ());
826 
827  /* remove retry packet iterators if they are present in retry queue */
828  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
829 
830  while (it != m_retryPackets->end ())
831  {
832  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
833 
834  if (agreementIt->second.first.GetDistance (itSeq) >= agreementIt->second.first.GetDistance (startSeq)
835  && agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (endSeq))
836  {
837  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
838  it = m_retryPackets->Remove (it);
839  it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
840  }
841  else
842  {
843  it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
844  }
845  }
846 }
847 
848 void
849 BlockAckManager::RemoveOldPackets (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
850 {
851  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
852 
853  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
854  NS_ASSERT (agreementIt != m_agreements.end ());
855  uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
856 
857  NS_ABORT_MSG_IF (agreementIt->second.first.GetDistance (startingSeq) >= SEQNO_SPACE_HALF_SIZE,
858  "The new starting sequence number is an old sequence number");
859 
860  if (startingSeq == currStartingSeq)
861  {
862  return;
863  }
864 
865  // remove packets that will become old from the retransmission queue
866  uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
867  RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
868 
869  // remove packets that will become old from the queue of outstanding packets
870  PacketQueueI it = agreementIt->second.second.begin ();
871  while (it != agreementIt->second.second.end ())
872  {
873  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
874 
875  if (agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (lastRemovedSeq))
876  {
877  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
878  it = agreementIt->second.second.erase (it);
879  }
880  else
881  {
882  it++;
883  }
884  }
885 }
886 
887 void
889 {
890  NS_LOG_FUNCTION (this << &callback);
891  m_blockAckInactivityTimeout = callback;
892 }
893 
894 void
896 {
897  NS_LOG_FUNCTION (this << &callback);
898  m_blockPackets = callback;
899 }
900 
901 void
903 {
904  NS_LOG_FUNCTION (this << &callback);
905  m_unblockPackets = callback;
906 }
907 
908 void
910 {
911  NS_LOG_FUNCTION (this << txMiddle);
912  m_txMiddle = txMiddle;
913 }
914 
915 void
917 {
918  m_txOkCallback = callback;
919 }
920 
921 void
923 {
924  m_txFailedCallback = callback;
925 }
926 
927 void
929 {
930  NS_LOG_INFO ("Adding to retry queue " << *mpdu);
931  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
932 
933  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
934  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
935 
936  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
937  NS_ASSERT (agreementIt != m_agreements.end ());
938 
939  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
940 
941  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
942  {
943  NS_LOG_DEBUG ("Got an old packet. Do nothing");
944  return;
945  }
946 
947  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
948 
949  while (it != m_retryPackets->end ())
950  {
951  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
952  {
953  NS_LOG_DEBUG ("Packet already in the retransmit queue");
954  return;
955  }
956 
957  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
958 
959  if (mpduDist < dist ||
960  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
961  {
962  break;
963  }
964 
965  it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
966  }
967  mpdu->GetHeader ().SetRetry ();
968  m_retryPackets->Insert (it, mpdu);
969 }
970 
971 uint16_t
973 {
974  uint16_t size = 0;
975  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
976  if (it != m_agreements.end ())
977  {
978  size = it->second.first.GetBufferSize ();
979  }
980  return size;
981 }
982 
983 uint16_t
985 {
986  uint16_t seqNum = 0;
987  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
988  if (it != m_agreements.end ())
989  {
990  seqNum = it->second.first.GetStartingSequence ();
991  }
992  return seqNum;
993 }
994 
995 } //namespace ns3
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:557
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 "...
Callback template class.
Definition: callback.h:1278
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
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:190
#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:165
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.
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)
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)
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)
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.
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:195
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.
void NotifyGotBlockAck(const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
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:187
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:1294
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:1386
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
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 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.
void ReportAmpduTxStatus(Mac48Address address, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
BlockAckType
The different block ack policies.