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 Packet> bar, Mac48Address recipient, uint8_t tid, bool immediate)
41  : bar (bar),
42  recipient (recipient),
43  tid (tid),
44  immediate (immediate)
45 {
46  NS_LOG_FUNCTION (this << bar << recipient << +tid << immediate);
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.SetWinEnd ((agreement.GetStartingSequence () + agreement.GetBufferSize () - 1) % SEQNO_SPACE_SIZE);
126  agreement.SetTimeout (reqHdr->GetTimeout ());
127  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
128  agreement.SetHtSupported (m_stationManager->GetHtSupported ());
129  if (reqHdr->IsImmediateBlockAck ())
130  {
131  agreement.SetImmediateBlockAck ();
132  }
133  else
134  {
135  agreement.SetDelayedBlockAck ();
136  }
137  uint8_t tid = reqHdr->GetTid ();
139  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
140  PacketQueue queue;
141  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
142  if (ExistsAgreement (recipient, tid))
143  {
144  // Delete agreement if it exists and in RESET state
146  m_agreements.erase (key);
147  }
148  m_agreements.insert (std::make_pair (key, value));
149  m_blockPackets (recipient, reqHdr->GetTid ());
150 }
151 
152 void
154 {
155  NS_LOG_FUNCTION (this << recipient << +tid);
156  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
157  if (it != m_agreements.end ())
158  {
159  for (WifiMacQueue::ConstIterator i = m_retryPackets->begin (); i != m_retryPackets->end (); )
160  {
161  if ((*i)->GetHeader ().GetAddr1 () == recipient && (*i)->GetHeader ().GetQosTid () == tid)
162  {
163  i = m_retryPackets->Remove (i);
164  }
165  else
166  {
167  i++;
168  }
169  }
170  m_agreements.erase (it);
171  //remove scheduled bar
172  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
173  {
174  if (i->recipient == recipient && i->tid == tid)
175  {
176  i = m_bars.erase (i);
177  }
178  else
179  {
180  i++;
181  }
182  }
183  }
184 }
185 
186 void
188 {
189  NS_LOG_FUNCTION (this << respHdr << recipient);
190  uint8_t tid = respHdr->GetTid ();
191  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
192  if (it != m_agreements.end ())
193  {
194  OriginatorBlockAckAgreement& agreement = it->second.first;
195  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
196  agreement.SetTimeout (respHdr->GetTimeout ());
197  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
198  // update the starting sequence number because some frames may have been sent
199  // under Normal Ack policy after the transmission of the ADDBA Request frame
200  agreement.SetStartingSequence (m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient));
201  if (respHdr->IsImmediateBlockAck ())
202  {
203  agreement.SetImmediateBlockAck ();
204  }
205  else
206  {
207  agreement.SetDelayedBlockAck ();
208  }
209  if (!it->second.first.IsEstablished ())
210  {
212  }
214  if (agreement.GetTimeout () != 0)
215  {
216  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
219  this,
220  recipient, tid);
221  }
222  }
223  m_unblockPackets (recipient, tid);
224 }
225 
228 {
229  return m_retryPackets;
230 }
231 
232 void
234 {
235  NS_LOG_FUNCTION (this << *mpdu);
236  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
237 
238  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
239  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
240 
241  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
242  NS_ASSERT (agreementIt != m_agreements.end ());
243 
244  uint16_t startingSeq = agreementIt->second.first.GetStartingSequence ();
245  uint16_t mpduDist = (mpdu->GetHeader ().GetSequenceNumber () - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
246 
247  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
248  {
249  NS_LOG_DEBUG ("Got an old packet. Do nothing");
250  return;
251  }
252 
253  // store the packet and keep the list sorted in increasing order of sequence number
254  // with respect to the starting sequence number
255  PacketQueueI it = agreementIt->second.second.begin ();
256  while (it != agreementIt->second.second.end ())
257  {
258  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
259  {
260  NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
261  return;
262  }
263 
264  uint16_t dist = ((*it)->GetHeader ().GetSequenceNumber () - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
265 
266  if (mpduDist < dist ||
267  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
268  {
269  break;
270  }
271 
272  it++;
273  }
274  agreementIt->second.second.insert (it, mpdu);
275 }
276 
277 bool
278 BlockAckManager::HasBar (Bar &bar, bool remove)
279 {
280  if (m_bars.size () > 0)
281  {
282  bar = m_bars.front ();
283  if (remove)
284  {
285  m_bars.pop_front ();
286  }
287  return true;
288  }
289  return false;
290 }
291 
292 bool
294 {
295  NS_LOG_FUNCTION (this);
296  return (!m_retryPackets->IsEmpty () || m_bars.size () > 0);
297 }
298 
299 uint32_t
301 {
302  NS_LOG_FUNCTION (this << recipient << +tid);
303  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
304  if (it == m_agreements.end ())
305  {
306  return 0;
307  }
308  uint32_t nPackets = 0;
309  PacketQueueCI queueIt = (*it).second.second.begin ();
310  while (queueIt != (*it).second.second.end ())
311  {
312  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
313  nPackets++;
314  /* a fragmented packet must be counted as one packet */
315  while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
316  {
317  queueIt++;
318  }
319  }
320  return nPackets;
321 }
322 
323 void
325 {
326  NS_LOG_FUNCTION (this << +nPackets);
327  m_blockAckThreshold = nPackets;
328 }
329 
330 void
332 {
333  NS_LOG_FUNCTION (this << manager);
334  m_stationManager = manager;
335 }
336 
337 void
339 {
340  NS_LOG_FUNCTION (this << *mpdu);
341  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
342 
343  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
344  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
346 
347  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
348  NS_ASSERT (it != m_agreements.end ());
349 
350  // remove the acknowledged frame from the queue of outstanding packets
351  PacketQueueI queueIt = it->second.second.begin ();
352  while (queueIt != it->second.second.end ())
353  {
354  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
355  {
356  queueIt = it->second.second.erase (queueIt);
357  }
358  else
359  {
360  queueIt++;
361  }
362  }
363 
364  uint16_t startingSeq = it->second.first.GetStartingSequence ();
365  if (mpdu->GetHeader ().GetSequenceNumber () == startingSeq)
366  {
367  // make the transmit window advance
368  it->second.first.SetStartingSequence ((startingSeq + 1) % SEQNO_SPACE_SIZE);
369  }
370 }
371 
372 void
374 {
375  NS_LOG_FUNCTION (this << *mpdu);
376  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
377 
378  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
379  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
381 
382  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
383  NS_ASSERT (it != m_agreements.end ());
384 
385  // remove the frame from the queue of outstanding packets (it will be re-inserted
386  // if retransmitted)
387  PacketQueueI queueIt = it->second.second.begin ();
388  while (queueIt != it->second.second.end ())
389  {
390  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
391  {
392  queueIt = it->second.second.erase (queueIt);
393  }
394  else
395  {
396  queueIt++;
397  }
398  }
399 
400  // insert in the retransmission queue
401  InsertInRetryQueue (mpdu);
402 }
403 
404 void
405 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
406 {
407  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
408  if (!blockAck->IsMultiTid ())
409  {
410  uint8_t tid = blockAck->GetTidInfo ();
412  {
413  bool foundFirstLost = false;
414  uint8_t nSuccessfulMpdus = 0;
415  uint8_t nFailedMpdus = 0;
416  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
417  PacketQueueI queueEnd = it->second.second.end ();
418 
419  if (it->second.first.m_inactivityEvent.IsRunning ())
420  {
421  /* Upon reception of a block ack frame, the inactivity timer at the
422  originator must be reset.
423  For more details see section 11.5.3 in IEEE802.11e standard */
424  it->second.first.m_inactivityEvent.Cancel ();
425  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
426  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
428  this,
429  recipient, tid);
430  }
431 
432  uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
433  uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
434 
435  if (blockAck->IsBasic ())
436  {
437  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
438  {
439  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
440  if (blockAck->IsFragmentReceived (currentSeq,
441  (*queueIt)->GetHeader ().GetFragmentNumber ()))
442  {
443  nSuccessfulMpdus++;
444  }
445  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
446  {
447  if (!foundFirstLost)
448  {
449  foundFirstLost = true;
450  SetStartingSequence (recipient, tid, currentSeq);
451  }
452  nFailedMpdus++;
453  InsertInRetryQueue (*queueIt);
454  }
455  // in any case, this packet is no longer outstanding
456  queueIt = it->second.second.erase (queueIt);
457  }
458  // If all frames were acknowledged, move the transmit window past the last one
459  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
460  {
461  SetStartingSequence (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
462  }
463  }
464  else if (blockAck->IsCompressed () || blockAck->IsExtendedCompressed ())
465  {
466  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
467  {
468  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
469  if (blockAck->IsPacketReceived (currentSeq))
470  {
471  nSuccessfulMpdus++;
472  if (!m_txOkCallback.IsNull ())
473  {
474  m_txOkCallback ((*queueIt)->GetHeader ());
475  }
476  }
477  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
478  {
479  if (!foundFirstLost)
480  {
481  foundFirstLost = true;
482  SetStartingSequence (recipient, tid, currentSeq);
483  }
484  nFailedMpdus++;
485  if (!m_txFailedCallback.IsNull ())
486  {
487  m_txFailedCallback ((*queueIt)->GetHeader ());
488  }
489  InsertInRetryQueue (*queueIt);
490  }
491  // in any case, this packet is no longer outstanding
492  queueIt = it->second.second.erase (queueIt);
493  }
494  // If all frames were acknowledged, move the transmit window past the last one
495  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
496  {
497  SetStartingSequence (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
498  }
499  }
500  m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
501  }
502  }
503  else
504  {
505  //NOT SUPPORTED FOR NOW
506  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
507  }
508 }
509 
510 void
512 {
513  NS_LOG_FUNCTION (this << recipient << +tid);
515  {
516  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
517  for (auto& item : it->second.second)
518  {
519  // Queue previously transmitted packets that do not already exist in the retry queue.
520  InsertInRetryQueue (item);
521  }
522  // remove all packets from the queue of outstanding packets (they will be
523  // re-inserted if retransmitted)
524  it->second.second.clear ();
525  }
526 }
527 
528 void
530 {
531  NS_LOG_FUNCTION (this << recipient << +tid);
533  {
534  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
535  it->second.second.clear ();
536  }
537 }
538 
539 void
541 {
542  NS_LOG_FUNCTION (this << bAckType);
543  m_blockAckType = bAckType;
544 }
545 
546 void
548 {
549  NS_LOG_FUNCTION (this << *mpdu);
550 
551  if (!mpdu->GetHeader ().IsQosData ())
552  {
553  NS_LOG_DEBUG ("Not a QoS Data frame");
554  return;
555  }
556 
557  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
558  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
560  {
561  NS_LOG_DEBUG ("No established Block Ack agreement");
562  return;
563  }
564 
565  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
566  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
567  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
568  {
569  NS_LOG_DEBUG ("Discarded an old frame");
570  return;
571  }
572 
573  // advance the transmit window past the discarded mpdu
574  SetStartingSequence (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
575 
576  // schedule a block ack request
577  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
578  ScheduleBlockAckReq (recipient, tid);
579 }
580 
581 void
583 {
584  NS_LOG_FUNCTION (this << recipient << +tid);
585  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
586  NS_ASSERT (it != m_agreements.end ());
587 
588  OriginatorBlockAckAgreement &agreement = (*it).second.first;
589 
590  CtrlBAckRequestHeader reqHdr;
591  reqHdr.SetType (m_blockAckType);
592  reqHdr.SetTidInfo (agreement.GetTid ());
593  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
594 
595  Ptr<Packet> bar = Create<Packet> ();
596  bar->AddHeader (reqHdr);
597  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
598 
599  // if a BAR for the given agreement is present, replace it with the new one
600  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); i++)
601  {
602  if (i->recipient == recipient && i->tid == tid)
603  {
604  i = m_bars.erase (i);
605  m_bars.insert (i, request);
606  return;
607  }
608  }
609  m_bars.push_back (request);
610 }
611 
612 void
614 {
615  NS_LOG_FUNCTION (this << recipient << +tid);
616  m_blockAckInactivityTimeout (recipient, tid, true);
617 }
618 
619 void
620 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
621 {
622  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
623  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
624  NS_ASSERT (it != m_agreements.end ());
625  if (!it->second.first.IsEstablished ())
626  {
628  }
629  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
630  it->second.first.SetStartingSequence (startingSeq);
631 }
632 
633 void
635 {
636  NS_LOG_FUNCTION (this << recipient << +tid);
637  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
638  NS_ASSERT (it != m_agreements.end ());
639  if (!it->second.first.IsRejected ())
640  {
642  }
643  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
644 }
645 
646 void
648 {
649  NS_LOG_FUNCTION (this << recipient << +tid);
650  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
651  NS_ASSERT (it != m_agreements.end ());
652  if (!it->second.first.IsNoReply ())
653  {
655  }
656  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
657  m_unblockPackets (recipient, tid);
658 }
659 
660 void
662 {
663  NS_LOG_FUNCTION (this << recipient << +tid);
664  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
665  NS_ASSERT (it != m_agreements.end ());
666  if (!it->second.first.IsReset ())
667  {
669  }
670  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
671 }
672 
673 void
674 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
675 {
676  NS_LOG_FUNCTION (this << recipient << +tid << nextSeqNumber);
677  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
678  NS_ASSERT (it != m_agreements.end ());
679  if (policy == WifiMacHeader::BLOCK_ACK)
680  {
681  ScheduleBlockAckReq (recipient, tid);
682  }
683 }
684 
685 void
687 {
688  NS_LOG_FUNCTION (this << queue);
689  m_queue = queue;
690 }
691 
692 bool
693 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
694 {
695  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
697  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
698  {
699  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
700  GetNBufferedPackets (recipient, tid);
701  if (packets >= m_blockAckThreshold)
702  {
703  NotifyAgreementEstablished (recipient, tid, startingSeq);
704  return true;
705  }
706  }
707  return false;
708 }
709 
710 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
711 {
712  //The standard says the BAR gets discarded when all MSDUs lifetime expires
713  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
714  NS_ASSERT (it != m_agreements.end ());
715  if (QosUtilsIsOldPacket (it->second.first.GetStartingSequence (), seqNumber))
716  {
717  return false;
718  }
719  else if (it->second.first.GetTimeout () > 0 && it->second.first.m_inactivityEvent.IsExpired ())
720  {
721  /*
722  * According to "11.5.4 Error recovery upon a peer failure",
723  * DELBA should be issued after inactivity timeout,
724  * so block ack request should not be retransmitted anymore.
725  *
726  * Otherwise we risk retransmitting BAR forever if condition
727  * above is never met and the STA is not available.
728  *
729  * See https://www.nsnam.org/bugzilla/show_bug.cgi?id=2928 for details.
730  */
731  return false;
732  }
733  else
734  {
735  return true;
736  }
737 }
738 
739 void
741 {
742  RemoveFromRetryQueue (address, tid, seq, seq);
743 }
744 
745 void
746 BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
747 {
748  NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
749 
750  AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
751  NS_ASSERT (agreementIt != m_agreements.end ());
752  uint16_t startingSeq = agreementIt->second.first.GetStartingSequence ();
753 
754  /* remove retry packet iterators if they are present in retry queue */
755  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
756 
757  while (it != m_retryPackets->end ())
758  {
759  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
760 
761  if ((itSeq - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE
762  >= (startSeq - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE
763  && (itSeq - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE
764  <= (endSeq - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE)
765  {
766  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
767  it = m_retryPackets->Remove (it);
768  it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
769  }
770  else
771  {
772  it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
773  }
774  }
775 }
776 
777 void
778 BlockAckManager::SetStartingSequence (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
779 {
780  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
781 
782  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
783  NS_ASSERT (agreementIt != m_agreements.end ());
784  uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
785 
786  NS_ABORT_MSG_IF ((startingSeq - currStartingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE >= SEQNO_SPACE_HALF_SIZE,
787  "The new starting sequence number is an old sequence number");
788 
789  if (startingSeq == currStartingSeq)
790  {
791  return;
792  }
793 
794  // remove packets that will become old from the retransmission queue
795  uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
796  RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
797 
798  // remove packets that will become old from the queue of outstanding packets
799  PacketQueueI it = agreementIt->second.second.begin ();
800  while (it != agreementIt->second.second.end ())
801  {
802  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
803 
804  if ((itSeq - currStartingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE
805  <= (lastRemovedSeq - currStartingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE)
806  {
807  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
808  it = agreementIt->second.second.erase (it);
809  }
810  else
811  {
812  it++;
813  }
814  }
815 
816  // update the starting sequence number
817  agreementIt->second.first.SetStartingSequence (startingSeq);
818 }
819 
820 void
822 {
823  NS_LOG_FUNCTION (this << &callback);
824  m_blockAckInactivityTimeout = callback;
825 }
826 
827 void
829 {
830  NS_LOG_FUNCTION (this << &callback);
831  m_blockPackets = callback;
832 }
833 
834 void
836 {
837  NS_LOG_FUNCTION (this << &callback);
838  m_unblockPackets = callback;
839 }
840 
841 void
843 {
844  NS_LOG_FUNCTION (this << txMiddle);
845  m_txMiddle = txMiddle;
846 }
847 
848 void
850 {
851  m_txOkCallback = callback;
852 }
853 
854 void
856 {
857  m_txFailedCallback = callback;
858 }
859 
860 void
862 {
863  NS_LOG_INFO ("Adding to retry queue " << *mpdu);
864  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
865 
866  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
867  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
868 
869  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
870  NS_ASSERT (agreementIt != m_agreements.end ());
871 
872  uint16_t startingSeq = agreementIt->second.first.GetStartingSequence ();
873  uint16_t mpduDist = (mpdu->GetHeader ().GetSequenceNumber () - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
874 
875  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
876  {
877  NS_LOG_DEBUG ("Got an old packet. Do nothing");
878  return;
879  }
880 
881  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
882 
883  while (it != m_retryPackets->end ())
884  {
885  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
886  {
887  NS_LOG_DEBUG ("Packet already in the retransmit queue");
888  return;
889  }
890 
891  uint16_t dist = ((*it)->GetHeader ().GetSequenceNumber () - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
892 
893  if (mpduDist < dist ||
894  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
895  {
896  break;
897  }
898 
899  it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
900  }
901  m_retryPackets->Insert (it, mpdu);
902 }
903 
904 uint16_t
906 {
907  uint16_t size = 0;
908  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
909  if (it != m_agreements.end ())
910  {
911  size = it->second.first.GetBufferSize ();
912  }
913  return size;
914 }
915 
916 uint16_t
918 {
919  uint16_t seqNum = 0;
920  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
921  if (it != m_agreements.end ())
922  {
923  seqNum = it->second.first.GetStartingSequence ();
924  }
925  return seqNum;
926 }
927 
928 } //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)
#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:1176
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
Maintains the state and information about transmitted MPDUs with ack policy block ack for an originat...
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
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_agreementState
The trace source fired when a state transition occured.
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:997
#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:201
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:204
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:280
#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
void ScheduleBlockAckReq(Mac48Address recipient, uint8_t tid)
Block Ack Request.
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.
bool immediate
immediate
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:1389
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
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 ACKed in this Block ACK response.
Headers for Block ack 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:1489
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.
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
void SetState(State state)
Set the current state.
void SetTxOkCallback(TxOk callback)
bool HasBar(Bar &bar, bool remove=true)
Returns true if the BAR is scheduled.
std::string GetUniqueName(void) const
Definition: wifi-mode.cc:457
uint16_t GetRecipientBufferSize(Mac48Address recipient, uint8_t tid) const
This function returns the buffer size negociated with the recipient.
void InsertInRetryQueue(Ptr< WifiMacQueueItem > mpdu)
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
Mac48Address recipient
recipient
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
Every class exported by the ns3 library is enclosed in the ns3 namespace.
address
Definition: first.py:37
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
block ack 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 SetStartingSequence(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
Set the starting sequence number for the agreement with recipient equal to recipient and TID equal to...
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.
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.
QosAckPolicy
ACK policy for QoS frames.
void NotifyAgreementReset(Mac48Address recipient, uint8_t tid)
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
uint16_t GetOriginatorStartingSequence(Mac48Address recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
void NotifyMpduTransmission(Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
bool IsFragmentReceived(uint16_t seq, uint8_t frag) const
Check if the packet with the given sequence number and fragment number was ACKed in this Block ACK re...
void SetDelayedBlockAck(void)
Set Block ACK policy to delayed ACK.
EventId m_inactivityEvent
inactivity event
bool NeedBarRetransmission(uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
This function returns true if the lifetime of the packets a BAR refers to didn&#39;t expire yet otherwise...
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
bool HasPackets(void) const
Returns true if there are packets that need of retransmission or at least a BAR is scheduled...
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
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:1129
BlockAckType m_blockAckType
block ack type
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:272
Ptr< const Packet > bar
block ack request
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:198
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:1078
void ReportAmpduTxStatus(Mac48Address address, uint8_t tid, 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...
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 Block ack request.
Definition: ctrl-headers.h:41
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1270
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:915
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Ptr< WifiMacQueue > m_queue
queue
BlockAckType
The different block ACK policies.