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  : packet (packet),
37  hdr (hdr),
38  timestamp (tStamp)
39 {
40  NS_LOG_FUNCTION (this << packet << hdr << tStamp);
41 }
42 
44 {
45  NS_LOG_FUNCTION (this);
46 }
47 
48 Bar::Bar (Ptr<const Packet> bar, Mac48Address recipient, uint8_t tid, bool immediate)
49  : bar (bar),
50  recipient (recipient),
51  tid (tid),
52  immediate (immediate)
53 {
54  NS_LOG_FUNCTION (this << bar << recipient << +tid << immediate);
55 }
56 
58 
59 TypeId
61 {
62  static TypeId tid = TypeId ("ns3::BlockAckManager")
63  .SetParent<Object> ()
64  .SetGroupName ("Wifi")
65  .AddConstructor<BlockAckManager> ()
66  ;
67  return tid;
68 }
69 
71 {
72  NS_LOG_FUNCTION (this);
73 }
74 
76 {
77  NS_LOG_FUNCTION (this);
78  m_queue = 0;
79  m_agreements.clear ();
80  m_retryPackets.clear ();
81 }
82 
83 bool
84 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
85 {
86  NS_LOG_FUNCTION (this << recipient << +tid);
87  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
88 }
89 
90 bool
93 {
94  NS_LOG_FUNCTION (this << recipient << +tid << state);
95  AgreementsCI it;
96  it = m_agreements.find (std::make_pair (recipient, tid));
97  if (it != m_agreements.end ())
98  {
99  switch (state)
100  {
102  return it->second.first.IsInactive ();
104  return it->second.first.IsEstablished ();
106  return it->second.first.IsPending ();
108  return it->second.first.IsUnsuccessful ();
109  default:
110  NS_FATAL_ERROR ("Invalid state for block ack agreement");
111  }
112  }
113  return false;
114 }
115 
116 void
118 {
119  NS_LOG_FUNCTION (this << reqHdr << recipient);
120  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
121  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
122  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
123  /* For now we assume that originator doesn't use this field. Use of this field
124  is mandatory only for recipient */
125  agreement.SetBufferSize (64);
126  agreement.SetWinEnd ((agreement.GetStartingSequence () + agreement.GetBufferSize () - 1) % 4096);
127  agreement.SetTimeout (reqHdr->GetTimeout ());
128  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
129  agreement.SetHtSupported (m_stationManager->HasHtSupported ());
130  if (reqHdr->IsImmediateBlockAck ())
131  {
132  agreement.SetImmediateBlockAck ();
133  }
134  else
135  {
136  agreement.SetDelayedBlockAck ();
137  }
138  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
139  PacketQueue queue;
140  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
141  m_agreements.insert (std::make_pair (key, value));
142  m_blockPackets (recipient, reqHdr->GetTid ());
143 }
144 
145 void
147 {
148  NS_LOG_FUNCTION (this << recipient << +tid);
149  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
150  if (it != m_agreements.end ())
151  {
152  for (std::list<PacketQueueI>::const_iterator i = m_retryPackets.begin (); i != m_retryPackets.end (); )
153  {
154  if ((*i)->hdr.GetAddr1 () == recipient && (*i)->hdr.GetQosTid () == tid)
155  {
156  i = m_retryPackets.erase (i);
157  }
158  else
159  {
160  i++;
161  }
162  }
163  m_agreements.erase (it);
164  //remove scheduled bar
165  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
166  {
167  if (i->recipient == recipient && i->tid == tid)
168  {
169  i = m_bars.erase (i);
170  }
171  else
172  {
173  i++;
174  }
175  }
176  }
177 }
178 
179 void
181 {
182  NS_LOG_FUNCTION (this << respHdr << recipient);
183  uint8_t tid = respHdr->GetTid ();
184  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
185  if (it != m_agreements.end ())
186  {
187  OriginatorBlockAckAgreement& agreement = it->second.first;
188  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
189  agreement.SetTimeout (respHdr->GetTimeout ());
190  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
191  if (respHdr->IsImmediateBlockAck ())
192  {
193  agreement.SetImmediateBlockAck ();
194  }
195  else
196  {
197  agreement.SetDelayedBlockAck ();
198  }
200  if (agreement.GetTimeout () != 0)
201  {
202  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
205  this,
206  recipient, tid);
207  }
208  }
209  m_unblockPackets (recipient, tid);
210 }
211 
212 void
214 {
215  NS_LOG_FUNCTION (this << packet << hdr << tStamp);
216  NS_ASSERT (hdr.IsQosData ());
217 
218  uint8_t tid = hdr.GetQosTid ();
219  Mac48Address recipient = hdr.GetAddr1 ();
220 
221  Item item (packet, hdr, tStamp);
222  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
223  NS_ASSERT (it != m_agreements.end ());
224  PacketQueueI queueIt = it->second.second.begin ();
225  for (; queueIt != it->second.second.end (); )
226  {
227  if (((hdr.GetSequenceNumber () - queueIt->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
228  {
229  queueIt = it->second.second.insert (queueIt, item);
230  break;
231  }
232  else
233  {
234  queueIt++;
235  }
236  }
237  if (queueIt == it->second.second.end ())
238  {
239  it->second.second.push_back (item);
240  }
241 }
242 
243 void
245 {
246  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
247  NS_ASSERT (it != m_agreements.end ());
248  OriginatorBlockAckAgreement &agreement = (*it).second.first;
249  agreement.CompleteExchange ();
250 }
251 
254 {
255  NS_LOG_FUNCTION (this << &hdr);
256  Ptr<const Packet> packet = 0;
257  uint8_t tid;
258  Mac48Address recipient;
259  CleanupBuffers ();
260  if (!m_retryPackets.empty ())
261  {
262  NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets.size ());
263  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
264  while (it != m_retryPackets.end ())
265  {
266  if ((*it)->hdr.IsQosData ())
267  {
268  tid = (*it)->hdr.GetQosTid ();
269  }
270  else
271  {
272  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
273  }
274  recipient = (*it)->hdr.GetAddr1 ();
275  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
276  NS_ASSERT (agreement != m_agreements.end ());
277  if (removePacket)
278  {
279  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
280  {
281  //Standard says the originator should not send a packet with seqnum < winstart
282  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
283  agreement->second.second.erase ((*it));
284  it = m_retryPackets.erase (it);
285  continue;
286  }
287  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
288  {
289  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
290  }
291  }
292  packet = (*it)->packet->Copy ();
293  hdr = (*it)->hdr;
294  hdr.SetRetry ();
295  if (hdr.IsQosData ())
296  {
297  tid = hdr.GetQosTid ();
298  }
299  else
300  {
301  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
302  }
303  recipient = hdr.GetAddr1 ();
304  if (!agreement->second.first.IsHtSupported ()
306  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
307  {
309  }
310  else
311  {
312  /* From section 9.10.3 in IEEE802.11e standard:
313  * In order to improve efficiency, originators using the Block Ack facility
314  * may send MPDU frames with the Ack Policy subfield in QoS control frames
315  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
316  * When there are sufficient number of MPDUs, the originator may switch back to
317  * the use of Block Ack.
318  */
320  if (removePacket)
321  {
322  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
323  i->second.second.erase (*it);
324  }
325  }
326  if (removePacket)
327  {
328  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
329  it = m_retryPackets.erase (it);
330  NS_LOG_DEBUG ("Removed one packet, retry buffer size = " << m_retryPackets.size ());
331  }
332  break;
333  }
334  }
335  return packet;
336 }
337 
340 {
341  NS_LOG_FUNCTION (this);
342  Ptr<const Packet> packet = 0;
343  CleanupBuffers ();
344  Mac48Address recipient = hdr.GetAddr1 ();
345  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
346  NS_ASSERT (agreement != m_agreements.end ());
347  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
348  for (; it != m_retryPackets.end (); it++)
349  {
350  if (!(*it)->hdr.IsQosData ())
351  {
352  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
353  }
354  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
355  {
356  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
357  {
358  //standard says the originator should not send a packet with seqnum < winstart
359  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
360  agreement->second.second.erase ((*it));
361  it = m_retryPackets.erase (it);
362  it--;
363  continue;
364  }
365  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
366  {
367  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
368  }
369  packet = (*it)->packet->Copy ();
370  hdr = (*it)->hdr;
371  hdr.SetRetry ();
372  *tstamp = (*it)->timestamp;
373  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
374  if (!agreement->second.first.IsHtSupported ()
376  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
377  {
379  }
380  else
381  {
382  /* From section 9.10.3 in IEEE802.11e standard:
383  * In order to improve efficiency, originators using the Block Ack facility
384  * may send MPDU frames with the Ack Policy subfield in QoS control frames
385  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
386  * When there are sufficient number of MPDUs, the originator may switch back to
387  * the use of Block Ack.
388  */
390  }
391  NS_LOG_DEBUG ("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
392  return packet;
393  }
394  }
395  return packet;
396 }
397 
398 bool
399 BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
400 {
401 
402  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
403  for (; it != m_retryPackets.end (); it++)
404  {
405  if (!(*it)->hdr.IsQosData ())
406  {
407  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
408  }
409  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber)
410  {
411  WifiMacHeader hdr = (*it)->hdr;
412  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
413  i->second.second.erase ((*it));
414  m_retryPackets.erase (it);
415  NS_LOG_DEBUG ("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << +tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
416  return true;
417  }
418  }
419  return false;
420 }
421 
422 bool
424 {
425  NS_LOG_FUNCTION (this << &bar);
426  if (m_bars.size () > 0)
427  {
428  bar = m_bars.front ();
429  m_bars.pop_front ();
430  return true;
431  }
432  return false;
433 }
434 
435 bool
437 {
438  NS_LOG_FUNCTION (this);
439  return (m_retryPackets.size () > 0 || m_bars.size () > 0);
440 }
441 
442 uint32_t
444 {
445  NS_LOG_FUNCTION (this << recipient << +tid);
446  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
447  if (it == m_agreements.end ())
448  {
449  return 0;
450  }
451  uint32_t nPackets = 0;
452  PacketQueueCI queueIt = (*it).second.second.begin ();
453  while (queueIt != (*it).second.second.end ())
454  {
455  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
456  nPackets++;
457  /* a fragmented packet must be counted as one packet */
458  while (queueIt != (*it).second.second.end () && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
459  {
460  queueIt++;
461  }
462  }
463  return nPackets;
464 }
465 
466 uint32_t
468 {
469  NS_LOG_FUNCTION (this << recipient << +tid);
470  uint32_t nPackets = 0;
471  uint16_t currentSeq = 0;
472  if (ExistsAgreement (recipient, tid))
473  {
474  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
475  while (it != m_retryPackets.end ())
476  {
477  if (!(*it)->hdr.IsQosData ())
478  {
479  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
480  }
481  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
482  {
483  currentSeq = (*it)->hdr.GetSequenceNumber ();
484  nPackets++;
485  /* a fragmented packet must be counted as one packet */
486  while (it != m_retryPackets.end () && (*it)->hdr.GetSequenceNumber () == currentSeq)
487  {
488  it++;
489  }
490  }
491  //go to next packet
492  else
493  {
494  it++;
495  }
496  }
497  }
498  return nPackets;
499 }
500 
501 void
503 {
504  NS_LOG_FUNCTION (this << +nPackets);
505  m_blockAckThreshold = nPackets;
506 }
507 
508 void
510 {
511  NS_LOG_FUNCTION (this << manager);
512  m_stationManager = manager;
513 }
514 
515 bool
516 BlockAckManager::AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid) const
517 {
518  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
519  while (it != m_retryPackets.end ())
520  {
521  NS_LOG_FUNCTION (this << (*it)->hdr.GetType ());
522  if (!(*it)->hdr.IsQosData ())
523  {
524  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
525  }
526  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
527  {
528  return true;
529  }
530  it++;
531  }
532  return false;
533 }
534 
535 void
536 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
537 {
538  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
539  uint16_t sequenceFirstLost = 0;
540  if (!blockAck->IsMultiTid ())
541  {
542  uint8_t tid = blockAck->GetTidInfo ();
544  {
545  bool foundFirstLost = false;
546  uint8_t nSuccessfulMpdus = 0;
547  uint8_t nFailedMpdus = 0;
548  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
549  PacketQueueI queueEnd = it->second.second.end ();
550 
551  if (it->second.first.m_inactivityEvent.IsRunning ())
552  {
553  /* Upon reception of a block ack frame, the inactivity timer at the
554  originator must be reset.
555  For more details see section 11.5.3 in IEEE802.11e standard */
556  it->second.first.m_inactivityEvent.Cancel ();
557  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
558  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
560  this,
561  recipient, tid);
562  }
563  if (blockAck->IsBasic ())
564  {
565  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
566  {
567  if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
568  (*queueIt).hdr.GetFragmentNumber ()))
569  {
570  nSuccessfulMpdus++;
571  RemoveFromRetryQueue (recipient, tid, (*queueIt).hdr.GetSequenceNumber ());
572  queueIt = it->second.second.erase (queueIt);
573  }
574  else
575  {
576  if (!foundFirstLost)
577  {
578  foundFirstLost = true;
579  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
580  (*it).second.first.SetStartingSequence (sequenceFirstLost);
581  }
582  nFailedMpdus++;
583  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
584  {
585  InsertInRetryQueue (queueIt);
586  }
587  queueIt++;
588  }
589  }
590  }
591  else if (blockAck->IsCompressed ())
592  {
593  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
594  {
595  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
596  if (blockAck->IsPacketReceived (currentSeq))
597  {
598  while (queueIt != queueEnd
599  && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
600  {
601  nSuccessfulMpdus++;
602  if (!m_txOkCallback.IsNull ())
603  {
604  m_txOkCallback ((*queueIt).hdr);
605  }
606  RemoveFromRetryQueue (recipient, tid, currentSeq);
607  queueIt = it->second.second.erase (queueIt);
608  }
609  }
610  else
611  {
612  if (!foundFirstLost)
613  {
614  foundFirstLost = true;
615  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
616  (*it).second.first.SetStartingSequence (sequenceFirstLost);
617  }
618  nFailedMpdus++;
619  if (!m_txFailedCallback.IsNull ())
620  {
621  m_txFailedCallback ((*queueIt).hdr);
622  }
623  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
624  {
625  InsertInRetryQueue (queueIt);
626  }
627  queueIt++;
628  }
629  }
630  }
631  m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
632  uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
633  if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
634  || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
635  {
636  it->second.first.CompleteExchange ();
637  }
638  }
639  }
640  else
641  {
642  //NOT SUPPORTED FOR NOW
643  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
644  }
645 }
646 
647 void
649 {
650  NS_LOG_FUNCTION (this << bAckType);
651  m_blockAckType = bAckType;
652 }
653 
656 {
657  /* This method checks if a BlockAckRequest frame should be send to the recipient station.
658  Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
659  this number could be incorrect. In fact is possible that a block ack agreement exists for n
660  packets but some of these packets are dropped due to MSDU lifetime expiration.
661  */
662  NS_LOG_FUNCTION (this << recipient << +tid);
663  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
664  NS_ASSERT (it != m_agreements.end ());
665 
666  if ((*it).second.first.IsBlockAckRequestNeeded ()
667  || (GetNRetryNeededPackets (recipient, tid) == 0
668  && m_queue->GetNPacketsByTidAndAddress (tid, recipient) == 0))
669  {
670  OriginatorBlockAckAgreement &agreement = (*it).second.first;
671  agreement.CompleteExchange ();
672 
673  CtrlBAckRequestHeader reqHdr;
675  {
676  reqHdr.SetType (m_blockAckType);
677  reqHdr.SetTidInfo (agreement.GetTid ());
678  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
679  }
681  {
682  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
683  }
684  else
685  {
686  NS_FATAL_ERROR ("Invalid block ack type.");
687  }
688  Ptr<Packet> bar = Create<Packet> ();
689  bar->AddHeader (reqHdr);
690  return bar;
691  }
692  return 0;
693 }
694 
695 void
697 {
698  NS_LOG_FUNCTION (this << recipient << +tid);
699  m_blockAckInactivityTimeout (recipient, tid, true);
700 }
701 
702 void
703 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
704 {
705  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
706  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
707  NS_ASSERT (it != m_agreements.end ());
708  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
709  it->second.first.SetStartingSequence (startingSeq);
710 }
711 
712 void
714 {
715  NS_LOG_FUNCTION (this << recipient << +tid);
716  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
717  NS_ASSERT (it != m_agreements.end ());
718  if (it != m_agreements.end ())
719  {
720  it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
721  }
722 }
723 
724 void
725 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
726 {
727  NS_LOG_FUNCTION (this << recipient << +tid << nextSeqNumber);
728  Ptr<Packet> bar = 0;
729  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
730  NS_ASSERT (it != m_agreements.end ());
731  uint16_t nextSeq;
732  if (GetNRetryNeededPackets (recipient, tid) > 0)
733  {
734  nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
735  }
736  else
737  {
738  nextSeq = nextSeqNumber;
739  }
740  it->second.first.NotifyMpduTransmission (nextSeq);
741  if (policy == WifiMacHeader::BLOCK_ACK)
742  {
743  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
744  if (bar != 0)
745  {
746  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
747  m_bars.push_back (request);
748  }
749  }
750 }
751 
752 void
754 {
755  NS_LOG_FUNCTION (this << queue);
756  m_queue = queue;
757 }
758 
759 bool
760 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
761 {
762  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
764  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
765  {
766  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
767  GetNBufferedPackets (recipient, tid);
768  if (packets >= m_blockAckThreshold)
769  {
770  NotifyAgreementEstablished (recipient, tid, startingSeq);
771  return true;
772  }
773  }
774  return false;
775 }
776 
777 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
778 {
779  //The standard says the BAR gets discarded when all MSDUs lifetime expires
780  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
781  NS_ASSERT (it != m_agreements.end ());
782  CleanupBuffers ();
783  if ((seqNumber + 63) < it->second.first.GetStartingSequence ())
784  {
785  return false;
786  }
787  else if (it->second.first.GetTimeout () > 0 && it->second.first.m_inactivityEvent.IsExpired ())
788  {
789  /*
790  * According to "11.5.4 Error recovery upon a peer failure",
791  * DELBA should be issued after inactivity timeout,
792  * so block ack request should not be retransmitted anymore.
793  *
794  * Otherwise we risk retransmitting BAR forever if condition
795  * above is never met and the STA is not available.
796  *
797  * See https://www.nsnam.org/bugzilla/show_bug.cgi?id=2928 for details.
798  */
799  return false;
800  }
801  else
802  {
803  return true;
804  }
805 }
806 
807 void
809 {
810  /* remove retry packet iterator if it's present in retry queue */
811  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
812  while (it != m_retryPackets.end ())
813  {
814  if ((*it)->hdr.GetAddr1 () == address
815  && (*it)->hdr.GetQosTid () == tid
816  && (*it)->hdr.GetSequenceNumber () == seq)
817  {
818  it = m_retryPackets.erase (it);
819  }
820  else
821  {
822  it++;
823  }
824  }
825 }
826 
827 void
829 {
830  NS_LOG_FUNCTION (this);
831  for (AgreementsI j = m_agreements.begin (); j != m_agreements.end (); j++)
832  {
833  if (j->second.second.empty ())
834  {
835  continue;
836  }
837  Time now = Simulator::Now ();
838  PacketQueueI end = j->second.second.begin ();
839  for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
840  {
841  if (i->timestamp + m_maxDelay > now)
842  {
843  end = i;
844  break;
845  }
846  else
847  {
848  RemoveFromRetryQueue (j->second.first.GetPeer (),
849  j->second.first.GetTid (),
850  i->hdr.GetSequenceNumber ());
851  }
852  }
853  j->second.second.erase (j->second.second.begin (), end);
854  j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
855  }
856 }
857 
858 void
860 {
861  NS_LOG_FUNCTION (this << maxDelay);
862  m_maxDelay = maxDelay;
863 }
864 
865 void
867 {
868  NS_LOG_FUNCTION (this << &callback);
869  m_blockAckInactivityTimeout = callback;
870 }
871 
872 void
874 {
875  NS_LOG_FUNCTION (this << &callback);
876  m_blockPackets = callback;
877 }
878 
879 void
881 {
882  NS_LOG_FUNCTION (this << &callback);
883  m_unblockPackets = callback;
884 }
885 
886 void
888 {
889  NS_LOG_FUNCTION (this << txMiddle);
890  m_txMiddle = txMiddle;
891 }
892 
893 uint16_t
895 {
896  NS_LOG_FUNCTION (this << recipient << +tid);
897  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
898  while (it != m_retryPackets.end ())
899  {
900  if (!(*it)->hdr.IsQosData ())
901  {
902  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
903  }
904  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
905  {
906  return (*it)->hdr.GetSequenceNumber ();
907  }
908  it++;
909  }
910  return 4096;
911 }
912 
913 void
915 {
916  m_txOkCallback = callback;
917 }
918 
919 void
921 {
922  m_txFailedCallback = callback;
923 }
924 
925 void
927 {
928  NS_LOG_INFO ("Adding to retry queue " << (*item).hdr.GetSequenceNumber ());
929  if (m_retryPackets.size () == 0)
930  {
931  m_retryPackets.push_back (item);
932  }
933  else
934  {
935  for (std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
936  {
937  if (((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
938  {
939  it = m_retryPackets.insert (it, item);
940  break;
941  }
942  else
943  {
944  it++;
945  if (it == m_retryPackets.end ())
946  {
947  m_retryPackets.push_back (item);
948  }
949  }
950  }
951  }
952 }
953 
954 } //namespace ns3
void SetRetry(void)
Set the Retry bit in the Frame Control field.
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
std::list< Item > PacketQueue
typedef for a list of Item struct.
Maintains the state and information about transmitted MPDUs with ack policy block ack for an originat...
uint32_t GetNRetryNeededPackets(Mac48Address recipient, uint8_t tid) const
#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 StorePacket(Ptr< const Packet > packet, const WifiMacHeader &hdr, Time tStamp)
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...
Implement the header for management frames of type add block ack request.
Definition: mgt-headers.h:997
Mac48Address GetAddr1(void) const
Return the address in the Address 1 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
uint16_t GetStartingSequence(void) const
Return the starting squence number.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
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:278
#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:83
uint16_t GetBufferSize(void) const
Return the buffer size.
Ptr< const Packet > GetNextPacket(WifiMacHeader &hdr, bool removePacket)
ns3::Time timeout
Block Ack Request.
uint16_t GetTimeout(void) const
Return the timeout.
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 ACK policy is basic (i.e.
void SetType(BlockAckType type)
Set the block ACK type.
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
void RemoveFromRetryQueue(Mac48Address address, uint8_t tid, uint16_t seq)
Remove items from retransmission queue.
void SetTxFailedCallback(TxFailed callback)
Ptr< Packet > ScheduleBlockAckReqIfNeeded(Mac48Address recipient, uint8_t tid)
uint8_t GetTid(void) const
Return the Traffic ID (TID).
WifiMacHeader hdr
header
bool IsImmediateBlockAck(void) const
Return whether the Block ACK policy is immediate Block ACK.
bool IsCompressed(void) const
Check if the current ACK policy is compressed ACK and not multiple TID.
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:1381
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.
void NotifyAgreementUnsuccessful(Mac48Address recipient, uint8_t tid)
static TypeId GetTypeId(void)
Get the type ID.
void InsertInRetryQueue(PacketQueueI item)
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
bool IsPacketReceived(uint16_t seq) const
Check if the packet with the given sequence number was ACKed in this Block ACK response.
std::list< PacketQueueI > m_retryPackets
This list contains all iterators to stored packets that need to be retransmitted. ...
Headers for Block ack response.
Definition: ctrl-headers.h:181
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
bool AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid) const
Checks if the packet already exists in the retransmit queue or not if it does then it doesn&#39;t add it ...
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)
Item(Ptr< const Packet > packet, const WifiMacHeader &hdr, Time tStamp)
Constructor.
void SetState(State state)
Set the current state.
void SetTxOkCallback(TxOk callback)
std::string GetUniqueName(void) const
Definition: wifi-mode.cc:463
bool HasBar(Bar &bar)
Returns true if the BAR is scheduled.
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.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
address
Definition: first.py:37
uint16_t GetSeqNumOfNextRetryPacket(Mac48Address recipient, uint8_t tid) const
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
bool RemovePacket(uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
Remove a packet after you peek in the queue and get it.
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
block ack inactivity timeout callback
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
an EUI-48 address
Definition: mac48-address.h:43
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:249
State
Represents the state for this agreement.
QosAckPolicy
ACK policy for QoS frames.
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
bool HasHtSupported(void) const
Return whether the device has HT capability support enabled.
void SetMaxPacketDelay(Time maxDelay)
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 else it r...
uint8_t GetTid(void) const
Return the Traffic ID (TID).
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
A struct for packet, Wifi header, and timestamp.
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
std::list< Item >::const_iterator PacketQueueCI
typedef for a const iterator for PacketQueue.
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
void CleanupBuffers(void)
This method removes packets whose lifetime was exceeded.
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
void CompleteAmpduExchange(Mac48Address recipient, uint8_t tid)
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:270
Ptr< const Packet > bar
block ack request
bool IsMultiTid(void) const
Check if the current ACK policy has multiple TID.
uint16_t GetNextSeqNumberByTidAndAddress(uint8_t tid, Mac48Address addr) const
Return the next sequence number for the Traffic ID and destination.
void SetImmediateBlockAck(void)
Set Block ACK policy to immediate ACK.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS DATA...
Time m_maxDelay
maximum delay
void SetTimeout(uint16_t timeout)
Set timeout.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1030
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
uint8_t GetTid(void) const
Return the Traffic ID (TID).
Ptr< const Packet > packet
packet
Ptr< const Packet > PeekNextPacketByTidAndAddress(WifiMacHeader &hdr, uint8_t tid, Time *timestamp)
Peek in retransmit queue and get the next packet having address indicated by type equals to addr...
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 CompleteExchange(void)
Complete exchange function.
std::list< Item >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
BlockAckType
The different block ACK policies.
void SetQosAckPolicy(QosAckPolicy policy)
Set the QoS ACK policy in the QoS control field.