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  agreement.InitTxWindow ();
202  if (respHdr->IsImmediateBlockAck ())
203  {
204  agreement.SetImmediateBlockAck ();
205  }
206  else
207  {
208  agreement.SetDelayedBlockAck ();
209  }
210  if (!it->second.first.IsEstablished ())
211  {
213  }
215  if (agreement.GetTimeout () != 0)
216  {
217  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
220  this,
221  recipient, tid);
222  }
223  }
224  m_unblockPackets (recipient, tid);
225 }
226 
229 {
230  return m_retryPackets;
231 }
232 
233 void
235 {
236  NS_LOG_FUNCTION (this << *mpdu);
237  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
238 
239  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
240  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
241 
242  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
243  NS_ASSERT (agreementIt != m_agreements.end ());
244 
245  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
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 = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
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  agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
276 }
277 
278 bool
279 BlockAckManager::HasBar (Bar &bar, bool remove)
280 {
281  if (m_bars.size () > 0)
282  {
283  bar = m_bars.front ();
284  if (remove)
285  {
286  m_bars.pop_front ();
287  }
288  return true;
289  }
290  return false;
291 }
292 
293 bool
295 {
296  NS_LOG_FUNCTION (this);
297  return (!m_retryPackets->IsEmpty () || m_bars.size () > 0);
298 }
299 
300 uint32_t
302 {
303  NS_LOG_FUNCTION (this << recipient << +tid);
304  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
305  if (it == m_agreements.end ())
306  {
307  return 0;
308  }
309  uint32_t nPackets = 0;
310  PacketQueueCI queueIt = (*it).second.second.begin ();
311  while (queueIt != (*it).second.second.end ())
312  {
313  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
314  nPackets++;
315  /* a fragmented packet must be counted as one packet */
316  while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
317  {
318  queueIt++;
319  }
320  }
321  return nPackets;
322 }
323 
324 void
326 {
327  NS_LOG_FUNCTION (this << +nPackets);
328  m_blockAckThreshold = nPackets;
329 }
330 
331 void
333 {
334  NS_LOG_FUNCTION (this << manager);
335  m_stationManager = manager;
336 }
337 
338 void
340 {
341  NS_LOG_FUNCTION (this << *mpdu);
342  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
343 
344  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
345  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
347 
348  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
349  NS_ASSERT (it != m_agreements.end ());
350 
351  // remove the acknowledged frame from the queue of outstanding packets
352  PacketQueueI queueIt = it->second.second.begin ();
353  while (queueIt != it->second.second.end ())
354  {
355  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
356  {
357  queueIt = it->second.second.erase (queueIt);
358  }
359  else
360  {
361  queueIt++;
362  }
363  }
364 
365  it->second.first.NotifyAckedMpdu (mpdu);
366 }
367 
368 void
370 {
371  NS_LOG_FUNCTION (this << *mpdu);
372  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
373 
374  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
375  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
377 
378  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
379  NS_ASSERT (it != m_agreements.end ());
380 
381  // remove the frame from the queue of outstanding packets (it will be re-inserted
382  // if retransmitted)
383  PacketQueueI queueIt = it->second.second.begin ();
384  while (queueIt != it->second.second.end ())
385  {
386  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
387  {
388  queueIt = it->second.second.erase (queueIt);
389  }
390  else
391  {
392  queueIt++;
393  }
394  }
395 
396  // insert in the retransmission queue
397  InsertInRetryQueue (mpdu);
398 }
399 
400 void
401 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
402 {
403  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
404  if (!blockAck->IsMultiTid ())
405  {
406  uint8_t tid = blockAck->GetTidInfo ();
408  {
409  bool foundFirstLost = false;
410  uint8_t nSuccessfulMpdus = 0;
411  uint8_t nFailedMpdus = 0;
412  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
413  PacketQueueI queueEnd = it->second.second.end ();
414 
415  if (it->second.first.m_inactivityEvent.IsRunning ())
416  {
417  /* Upon reception of a block ack frame, the inactivity timer at the
418  originator must be reset.
419  For more details see section 11.5.3 in IEEE802.11e standard */
420  it->second.first.m_inactivityEvent.Cancel ();
421  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
422  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
424  this,
425  recipient, tid);
426  }
427 
428  uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
429  uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
430 
431  if (blockAck->IsBasic ())
432  {
433  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
434  {
435  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
436  if (blockAck->IsFragmentReceived (currentSeq,
437  (*queueIt)->GetHeader ().GetFragmentNumber ()))
438  {
439  nSuccessfulMpdus++;
440  }
441  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
442  {
443  if (!foundFirstLost)
444  {
445  foundFirstLost = true;
446  RemoveOldPackets (recipient, tid, currentSeq);
447  }
448  nFailedMpdus++;
449  InsertInRetryQueue (*queueIt);
450  }
451  // in any case, this packet is no longer outstanding
452  queueIt = it->second.second.erase (queueIt);
453  }
454  // If all frames were acknowledged, move the transmit window past the last one
455  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
456  {
457  RemoveOldPackets (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
458  }
459  }
460  else if (blockAck->IsCompressed () || blockAck->IsExtendedCompressed ())
461  {
462  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
463  {
464  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
465  if (blockAck->IsPacketReceived (currentSeq))
466  {
467  it->second.first.NotifyAckedMpdu (*queueIt);
468  nSuccessfulMpdus++;
469  if (!m_txOkCallback.IsNull ())
470  {
471  m_txOkCallback ((*queueIt)->GetHeader ());
472  }
473  }
474  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
475  {
476  nFailedMpdus++;
477  if (!m_txFailedCallback.IsNull ())
478  {
479  m_txFailedCallback ((*queueIt)->GetHeader ());
480  }
481  InsertInRetryQueue (*queueIt);
482  }
483  // in any case, this packet is no longer outstanding
484  queueIt = it->second.second.erase (queueIt);
485  }
486  }
487  m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
488  }
489  }
490  else
491  {
492  //NOT SUPPORTED FOR NOW
493  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
494  }
495 }
496 
497 void
499 {
500  NS_LOG_FUNCTION (this << recipient << +tid);
502  {
503  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
504  for (auto& item : it->second.second)
505  {
506  // Queue previously transmitted packets that do not already exist in the retry queue.
507  InsertInRetryQueue (item);
508  }
509  // remove all packets from the queue of outstanding packets (they will be
510  // re-inserted if retransmitted)
511  it->second.second.clear ();
512  }
513 }
514 
515 void
517 {
518  NS_LOG_FUNCTION (this << recipient << +tid);
520  {
521  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
522  while (!it->second.second.empty ())
523  {
524  Ptr<WifiMacQueueItem> mpdu = it->second.second.front ();
525  if (it->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
526  {
527  // old packet
528  it->second.second.pop_front ();
529  }
530  else
531  {
532  NotifyDiscardedMpdu (mpdu);
533  }
534  }
535  }
536 }
537 
538 void
540 {
541  NS_LOG_FUNCTION (this << bAckType);
542  m_blockAckType = bAckType;
543 }
544 
545 void
547 {
548  NS_LOG_FUNCTION (this << *mpdu);
549 
550  if (!mpdu->GetHeader ().IsQosData ())
551  {
552  NS_LOG_DEBUG ("Not a QoS Data frame");
553  return;
554  }
555 
556  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
557  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
559  {
560  NS_LOG_DEBUG ("No established Block Ack agreement");
561  return;
562  }
563 
564  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
565  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
566  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
567  {
568  NS_LOG_DEBUG ("Discarded an old frame");
569  return;
570  }
571 
572  // remove outstanding frames and frames in the retransmit queue with a sequence
573  // number less than or equal to the discarded MPDU
574  RemoveOldPackets (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
575  // actually advance the transmit window
576  it->second.first.NotifyDiscardedMpdu (mpdu);
577 
578  // schedule a block ack request
579  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
580  ScheduleBlockAckReq (recipient, tid);
581 }
582 
583 void
585 {
586  NS_LOG_FUNCTION (this << recipient << +tid);
587  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
588  NS_ASSERT (it != m_agreements.end ());
589 
590  OriginatorBlockAckAgreement &agreement = (*it).second.first;
591 
592  CtrlBAckRequestHeader reqHdr;
593  reqHdr.SetType (m_blockAckType);
594  reqHdr.SetTidInfo (agreement.GetTid ());
595  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
596 
597  Ptr<Packet> bar = Create<Packet> ();
598  bar->AddHeader (reqHdr);
599  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
600 
601  // if a BAR for the given agreement is present, replace it with the new one
602  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); i++)
603  {
604  if (i->recipient == recipient && i->tid == tid)
605  {
606  i = m_bars.erase (i);
607  m_bars.insert (i, request);
608  return;
609  }
610  }
611  m_bars.push_back (request);
612 }
613 
614 void
616 {
617  NS_LOG_FUNCTION (this << recipient << +tid);
618  m_blockAckInactivityTimeout (recipient, tid, true);
619 }
620 
621 void
622 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
623 {
624  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
625  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
626  NS_ASSERT (it != m_agreements.end ());
627  if (!it->second.first.IsEstablished ())
628  {
630  }
631  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
632  it->second.first.SetStartingSequence (startingSeq);
633 }
634 
635 void
637 {
638  NS_LOG_FUNCTION (this << recipient << +tid);
639  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
640  NS_ASSERT (it != m_agreements.end ());
641  if (!it->second.first.IsRejected ())
642  {
644  }
645  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
646 }
647 
648 void
650 {
651  NS_LOG_FUNCTION (this << recipient << +tid);
652  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
653  NS_ASSERT (it != m_agreements.end ());
654  if (!it->second.first.IsNoReply ())
655  {
657  }
658  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
659  m_unblockPackets (recipient, tid);
660 }
661 
662 void
664 {
665  NS_LOG_FUNCTION (this << recipient << +tid);
666  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
667  NS_ASSERT (it != m_agreements.end ());
668  if (!it->second.first.IsReset ())
669  {
671  }
672  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
673 }
674 
675 void
676 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
677 {
678  NS_LOG_FUNCTION (this << recipient << +tid << nextSeqNumber);
679  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
680  NS_ASSERT (it != m_agreements.end ());
681  if (policy == WifiMacHeader::BLOCK_ACK)
682  {
683  ScheduleBlockAckReq (recipient, tid);
684  }
685 }
686 
687 void
689 {
690  NS_LOG_FUNCTION (this << queue);
691  m_queue = queue;
692 }
693 
694 bool
695 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
696 {
697  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
699  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
700  {
701  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
702  GetNBufferedPackets (recipient, tid);
703  if (packets >= m_blockAckThreshold)
704  {
705  NotifyAgreementEstablished (recipient, tid, startingSeq);
706  return true;
707  }
708  }
709  return false;
710 }
711 
713 {
715  {
716  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
717  NS_ASSERT (it != m_agreements.end ());
718 
719  // A BAR needs to be retransmitted if there is at least a non-expired outstanding MPDU
720  for (auto& mpdu : it->second.second)
721  {
722  if (mpdu->GetTimeStamp () + m_queue->GetMaxDelay () > Simulator::Now ())
723  {
724  return true;
725  }
726  }
727  }
728 
729  // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
730  // has destroyed the agreement, hence we get here and correctly return false
731  return false;
732 }
733 
734 void
736 {
737  RemoveFromRetryQueue (address, tid, seq, seq);
738 }
739 
740 void
741 BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
742 {
743  NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
744 
745  AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
746  NS_ASSERT (agreementIt != m_agreements.end ());
747 
748  /* remove retry packet iterators if they are present in retry queue */
749  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
750 
751  while (it != m_retryPackets->end ())
752  {
753  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
754 
755  if (agreementIt->second.first.GetDistance (itSeq) >= agreementIt->second.first.GetDistance (startSeq)
756  && agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (endSeq))
757  {
758  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
759  it = m_retryPackets->Remove (it);
760  it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
761  }
762  else
763  {
764  it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
765  }
766  }
767 }
768 
769 void
770 BlockAckManager::RemoveOldPackets (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
771 {
772  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
773 
774  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
775  NS_ASSERT (agreementIt != m_agreements.end ());
776  uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
777 
778  NS_ABORT_MSG_IF (agreementIt->second.first.GetDistance (startingSeq) >= SEQNO_SPACE_HALF_SIZE,
779  "The new starting sequence number is an old sequence number");
780 
781  if (startingSeq == currStartingSeq)
782  {
783  return;
784  }
785 
786  // remove packets that will become old from the retransmission queue
787  uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
788  RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
789 
790  // remove packets that will become old from the queue of outstanding packets
791  PacketQueueI it = agreementIt->second.second.begin ();
792  while (it != agreementIt->second.second.end ())
793  {
794  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
795 
796  if (agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (lastRemovedSeq))
797  {
798  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
799  it = agreementIt->second.second.erase (it);
800  }
801  else
802  {
803  it++;
804  }
805  }
806 }
807 
808 void
810 {
811  NS_LOG_FUNCTION (this << &callback);
812  m_blockAckInactivityTimeout = callback;
813 }
814 
815 void
817 {
818  NS_LOG_FUNCTION (this << &callback);
819  m_blockPackets = callback;
820 }
821 
822 void
824 {
825  NS_LOG_FUNCTION (this << &callback);
826  m_unblockPackets = callback;
827 }
828 
829 void
831 {
832  NS_LOG_FUNCTION (this << txMiddle);
833  m_txMiddle = txMiddle;
834 }
835 
836 void
838 {
839  m_txOkCallback = callback;
840 }
841 
842 void
844 {
845  m_txFailedCallback = callback;
846 }
847 
848 void
850 {
851  NS_LOG_INFO ("Adding to retry queue " << *mpdu);
852  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
853 
854  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
855  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
856 
857  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
858  NS_ASSERT (agreementIt != m_agreements.end ());
859 
860  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
861 
862  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
863  {
864  NS_LOG_DEBUG ("Got an old packet. Do nothing");
865  return;
866  }
867 
868  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
869 
870  while (it != m_retryPackets->end ())
871  {
872  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
873  {
874  NS_LOG_DEBUG ("Packet already in the retransmit queue");
875  return;
876  }
877 
878  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
879 
880  if (mpduDist < dist ||
881  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
882  {
883  break;
884  }
885 
886  it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
887  }
888  mpdu->GetHeader ().SetRetry ();
889  m_retryPackets->Insert (it, mpdu);
890 }
891 
892 uint16_t
894 {
895  uint16_t size = 0;
896  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
897  if (it != m_agreements.end ())
898  {
899  size = it->second.first.GetBufferSize ();
900  }
901  return size;
902 }
903 
904 uint16_t
906 {
907  uint16_t seqNum = 0;
908  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
909  if (it != m_agreements.end ())
910  {
911  seqNum = it->second.first.GetStartingSequence ();
912  }
913  return seqNum;
914 }
915 
916 } //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...
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
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.
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)
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 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
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 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
Ptr< WifiMacQueue > m_queue
queue
BlockAckType
The different block ACK policies.