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