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 
327 {
328  NS_LOG_FUNCTION (this << &hdr);
329  Ptr<const Packet> packet = 0;
330  uint8_t tid;
331  Mac48Address recipient;
332  CleanupBuffers ();
333  if (!m_retryPackets.empty ())
334  {
335  NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets.size ());
336  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
337  while (it != m_retryPackets.end ())
338  {
339  if ((*it)->hdr.IsQosData ())
340  {
341  tid = (*it)->hdr.GetQosTid ();
342  }
343  else
344  {
345  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
346  }
347  recipient = (*it)->hdr.GetAddr1 ();
348  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
349  NS_ASSERT (agreement != m_agreements.end ());
350  packet = (*it)->packet->Copy ();
351  hdr = (*it)->hdr;
352  hdr.SetRetry ();
353  if (hdr.IsQosData ())
354  {
355  tid = hdr.GetQosTid ();
356  }
357  else
358  {
359  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
360  }
361  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  break;
380  }
381  }
382  return packet;
383 }
384 
387 {
388  NS_LOG_FUNCTION (this);
389  Ptr<const Packet> packet = 0;
390  CleanupBuffers ();
391  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
392  NS_ASSERT (agreement != m_agreements.end ());
393  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
394  for (; it != m_retryPackets.end (); it++)
395  {
396  if (!(*it)->hdr.IsQosData ())
397  {
398  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
399  }
400  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
401  {
402  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
403  {
404  //standard says the originator should not send a packet with seqnum < winstart
405  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
406  agreement->second.second.erase ((*it));
407  it = m_retryPackets.erase (it);
408  it--;
409  continue;
410  }
411  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
412  {
413  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
414  }
415  packet = (*it)->packet->Copy ();
416  hdr = (*it)->hdr;
417  hdr.SetRetry ();
418  *tstamp = (*it)->timestamp;
419  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
420  Mac48Address recipient = hdr.GetAddr1 ();
421  if (!agreement->second.first.IsHtSupported ()
423  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
424  {
426  }
427  else
428  {
429  /* From section 9.10.3 in IEEE802.11e standard:
430  * In order to improve efficiency, originators using the Block Ack facility
431  * may send MPDU frames with the Ack Policy subfield in QoS control frames
432  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
433  * When there are sufficient number of MPDUs, the originator may switch back to
434  * the use of Block Ack.
435  */
437  }
438  NS_LOG_DEBUG ("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
439  return packet;
440  }
441  }
442  return packet;
443 }
444 
445 bool
446 BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
447 {
448 
449  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
450  for (; it != m_retryPackets.end (); it++)
451  {
452  if (!(*it)->hdr.IsQosData ())
453  {
454  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
455  }
456  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber)
457  {
458  WifiMacHeader hdr = (*it)->hdr;
459  uint8_t tid = hdr.GetQosTid ();
460  Mac48Address recipient = hdr.GetAddr1 ();
461 
462  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
463  i->second.second.erase ((*it));
464 
465  m_retryPackets.erase (it);
466  NS_LOG_DEBUG ("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << (uint32_t) tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
467  return true;
468  }
469  }
470  return false;
471 }
472 
473 bool
475 {
476  NS_LOG_FUNCTION (this << &bar);
477  if (m_bars.size () > 0)
478  {
479  bar = m_bars.front ();
480  m_bars.pop_front ();
481  return true;
482  }
483  return false;
484 }
485 
486 bool
488 {
489  NS_LOG_FUNCTION (this);
490  return (m_retryPackets.size () > 0 || m_bars.size () > 0);
491 }
492 
493 uint32_t
495 {
496  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
497  uint32_t nPackets = 0;
498  if (ExistsAgreement (recipient, tid))
499  {
500  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
501  PacketQueueCI queueIt = (*it).second.second.begin ();
502  uint16_t currentSeq = 0;
503  while (queueIt != (*it).second.second.end ())
504  {
505  currentSeq = (*queueIt).hdr.GetSequenceNumber ();
506  nPackets++;
507  /* a fragmented packet must be counted as one packet */
508  while (queueIt != (*it).second.second.end () && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
509  {
510  queueIt++;
511  }
512  }
513  return nPackets;
514  }
515  return 0;
516 }
517 
518 uint32_t
520 {
521  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
522  uint32_t nPackets = 0;
523  uint16_t currentSeq = 0;
524  if (ExistsAgreement (recipient, tid))
525  {
526  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
527  while (it != m_retryPackets.end ())
528  {
529  if (!(*it)->hdr.IsQosData ())
530  {
531  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
532  }
533  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
534  {
535  currentSeq = (*it)->hdr.GetSequenceNumber ();
536  nPackets++;
537  /* a fragmented packet must be counted as one packet */
538  while (it != m_retryPackets.end () && (*it)->hdr.GetSequenceNumber () == currentSeq)
539  {
540  it++;
541  }
542  }
543  //go to next packet
544  if (it != m_retryPackets.end ())
545  {
546  it++;
547  }
548  }
549  }
550  return nPackets;
551 }
552 
553 void
555 {
556  NS_LOG_FUNCTION (this << static_cast<uint32_t> (nPackets));
557  m_blockAckThreshold = nPackets;
558 }
559 
560 void
562 {
563  NS_LOG_FUNCTION (this << manager);
564  m_stationManager = manager;
565 }
566 
567 bool
568 BlockAckManager::AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid)
569 {
570  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
571  while (it != m_retryPackets.end ())
572  {
573  NS_LOG_FUNCTION (this << (*it)->hdr.GetType ());
574  if (!(*it)->hdr.IsQosData ())
575  {
576  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
577  }
578  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
579  {
580  return true;
581  }
582  it++;
583  }
584  return false;
585 }
586 
587 void
588 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
589 {
590  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
591  uint16_t sequenceFirstLost = 0;
592  if (!blockAck->IsMultiTid ())
593  {
594  uint8_t tid = blockAck->GetTidInfo ();
596  {
597  bool foundFirstLost = false;
598  uint32_t nSuccessfulMpdus = 0;
599  uint32_t nFailedMpdus = 0;
600  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
601  PacketQueueI queueEnd = it->second.second.end ();
602 
603  if (it->second.first.m_inactivityEvent.IsRunning ())
604  {
605  /* Upon reception of a block ack frame, the inactivity timer at the
606  originator must be reset.
607  For more details see section 11.5.3 in IEEE802.11e standard */
608  it->second.first.m_inactivityEvent.Cancel ();
609  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
610  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
612  this,
613  recipient, tid);
614  }
615  if (blockAck->IsBasic ())
616  {
617  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
618  {
619  if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
620  (*queueIt).hdr.GetFragmentNumber ()))
621  {
622  nSuccessfulMpdus++;
623  queueIt = it->second.second.erase (queueIt);
624  }
625  else
626  {
627  if (!foundFirstLost)
628  {
629  foundFirstLost = true;
630  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
631  (*it).second.first.SetStartingSequence (sequenceFirstLost);
632  }
633  nFailedMpdus++;
634  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
635  {
636  InsertInRetryQueue (queueIt);
637  }
638  queueIt++;
639  }
640  }
641  }
642  else if (blockAck->IsCompressed ())
643  {
644  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
645  {
646  if (blockAck->IsPacketReceived ((*queueIt).hdr.GetSequenceNumber ()))
647  {
648  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
649  while (queueIt != queueEnd
650  && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
651  {
652  nSuccessfulMpdus++;
653  if (!m_txOkCallback.IsNull ())
654  {
655  m_txOkCallback ((*queueIt).hdr);
656  }
657  queueIt = it->second.second.erase (queueIt);
658  }
659  }
660  else
661  {
662  if (!foundFirstLost)
663  {
664  foundFirstLost = true;
665  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
666  (*it).second.first.SetStartingSequence (sequenceFirstLost);
667  }
668  nFailedMpdus++;
669  if (!m_txFailedCallback.IsNull ())
670  {
671  m_txFailedCallback ((*queueIt).hdr);
672  }
673  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
674  {
675  InsertInRetryQueue (queueIt);
676  }
677  queueIt++;
678  }
679  }
680  }
681  m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
682  uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
683  if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
684  || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
685  {
686  it->second.first.CompleteExchange ();
687  }
688  }
689  }
690  else
691  {
692  //NOT SUPPORTED FOR NOW
693  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
694  }
695 }
696 
697 void
699 {
700  NS_LOG_FUNCTION (this << bAckType);
701  m_blockAckType = bAckType;
702 }
703 
706 {
707  /* This method checks if a BlockAckRequest frame should be send to the recipient station.
708  Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
709  this number could be incorrect. In fact is possible that a block ack agreement exists for n
710  packets but some of these packets are dropped due to MSDU lifetime expiration.
711  */
712  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
713  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
714  NS_ASSERT (it != m_agreements.end ());
715 
716  if ((*it).second.first.IsBlockAckRequestNeeded ()
717  || (GetNRetryNeededPackets (recipient, tid) == 0
718  && m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) == 0))
719  {
720  OriginatorBlockAckAgreement &agreement = (*it).second.first;
721  agreement.CompleteExchange ();
722 
723  CtrlBAckRequestHeader reqHdr;
725  {
726  reqHdr.SetType (m_blockAckType);
727  reqHdr.SetTidInfo (agreement.GetTid ());
728  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
729  }
731  {
732  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
733  }
734  else
735  {
736  NS_FATAL_ERROR ("Invalid block ack type.");
737  }
738  Ptr<Packet> bar = Create<Packet> ();
739  bar->AddHeader (reqHdr);
740  return bar;
741  }
742  return 0;
743 }
744 
745 void
747 {
748  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
749  m_blockAckInactivityTimeout (recipient, tid, true);
750 }
751 
752 void
753 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
754 {
755  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
756  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
757  NS_ASSERT (it != m_agreements.end ());
758 
759  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
760  it->second.first.SetStartingSequence (startingSeq);
761 }
762 
763 void
765 {
766  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
767  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
768  NS_ASSERT (it != m_agreements.end ());
769  if (it != m_agreements.end ())
770  {
771  it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
772  }
773 }
774 
775 void
776 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, enum WifiMacHeader::QosAckPolicy policy)
777 {
778  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << nextSeqNumber);
779  Ptr<Packet> bar = 0;
780  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
781  NS_ASSERT (it != m_agreements.end ());
782 
783  uint16_t nextSeq;
784  if (GetNRetryNeededPackets (recipient, tid) > 0)
785  {
786  nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
787  }
788  else
789  {
790  nextSeq = nextSeqNumber;
791  }
792  it->second.first.NotifyMpduTransmission (nextSeq);
793  if (policy == WifiMacHeader::BLOCK_ACK)
794  {
795  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
796  if (bar != 0)
797  {
798  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
799  m_bars.push_back (request);
800  }
801  }
802 }
803 
804 void
806 {
807  NS_LOG_FUNCTION (this << queue);
808  m_queue = queue;
809 }
810 
811 bool
812 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
813 {
814  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
816  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
817  {
818  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) +
819  GetNBufferedPackets (recipient, tid);
820  if (packets >= m_blockAckThreshold)
821  {
822  NotifyAgreementEstablished (recipient, tid, startingSeq);
823  return true;
824  }
825  }
826  return false;
827 }
828 
829 void
831 {
832  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
833  DestroyAgreement (recipient, tid);
834 }
835 
836 bool
837 BlockAckManager::HasOtherFragments (uint16_t sequenceNumber) const
838 {
839  NS_LOG_FUNCTION (this << sequenceNumber);
840  bool retVal = false;
841  if (m_retryPackets.size () > 0)
842  {
843  Item next = *(m_retryPackets.front ());
844  if (next.hdr.GetSequenceNumber () == sequenceNumber)
845  {
846  retVal = true;
847  }
848  }
849  return retVal;
850 }
851 
852 uint32_t
854 {
855  NS_LOG_FUNCTION (this);
856  uint32_t size = 0;
857  if (m_retryPackets.size () > 0)
858  {
859  Item next = *(m_retryPackets.front ());
860  size = next.packet->GetSize ();
861  }
862  return size;
863 }
864 
865 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
866 {
867  //The standard says the BAR gets discarded when all MSDUs lifetime expires
868  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
869  NS_ASSERT (it != m_agreements.end ());
870  CleanupBuffers ();
871  if ((seqNumber + 63) < it->second.first.GetStartingSequence ())
872  {
873  return false;
874  }
875  else
876  {
877  return true;
878  }
879 }
880 
881 void
883 {
884  NS_LOG_FUNCTION (this);
885  for (AgreementsI j = m_agreements.begin (); j != m_agreements.end (); j++)
886  {
887  if (j->second.second.empty ())
888  {
889  continue;
890  }
891  Time now = Simulator::Now ();
892  PacketQueueI end = j->second.second.begin ();
893  for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
894  {
895  if (i->timestamp + m_maxDelay > now)
896  {
897  end = i;
898  break;
899  }
900  else
901  {
902  /* remove retry packet iterator if it's present in retry queue */
903  for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
904  {
905  if ((*it)->hdr.GetAddr1 () == j->second.first.GetPeer ()
906  && (*it)->hdr.GetQosTid () == j->second.first.GetTid ()
907  && (*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ())
908  {
909  it = m_retryPackets.erase (it);
910  }
911  else
912  {
913  it++;
914  }
915  }
916  }
917  }
918  j->second.second.erase (j->second.second.begin (), end);
919  j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
920  }
921 }
922 
923 void
925 {
926  NS_LOG_FUNCTION (this << maxDelay);
927  m_maxDelay = maxDelay;
928 }
929 
930 void
932 {
933  NS_LOG_FUNCTION (this << &callback);
934  m_blockAckInactivityTimeout = callback;
935 }
936 
937 void
939 {
940  NS_LOG_FUNCTION (this << &callback);
941  m_blockPackets = callback;
942 }
943 
944 void
946 {
947  NS_LOG_FUNCTION (this << &callback);
948  m_unblockPackets = callback;
949 }
950 
951 void
953 {
954  NS_LOG_FUNCTION (this << txMiddle);
955  m_txMiddle = txMiddle;
956 }
957 
958 uint16_t
960 {
961  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
962  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
963  while (it != m_retryPackets.end ())
964  {
965  if (!(*it)->hdr.IsQosData ())
966  {
967  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
968  }
969  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
970  {
971  return (*it)->hdr.GetSequenceNumber ();
972  }
973  it++;
974  }
975  return 4096;
976 }
977 
978 void
980 {
981  m_txOkCallback = callback;
982 }
983 
984 void
986 {
987  m_txFailedCallback = callback;
988 }
989 
990 void
992 {
993  NS_LOG_INFO ("Adding to retry queue " << (*item).hdr.GetSequenceNumber ());
994  if (m_retryPackets.size () == 0)
995  {
996  m_retryPackets.push_back (item);
997  }
998  else
999  {
1000  for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
1001  {
1002  if (((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
1003  {
1004  it = m_retryPackets.insert (it, item);
1005  break;
1006  }
1007  else
1008  {
1009  it++;
1010  if (it == m_retryPackets.end ())
1011  {
1012  m_retryPackets.push_back (item);
1013  }
1014  }
1015  }
1016  }
1017 }
1018 
1019 } //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: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...
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)
Ptr< const Packet > PeekNextPacketByTidAndAddress(WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *timestamp)
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:667
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:1270
#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:792
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: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: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
Ptr< const Packet > PeekNextPacket(WifiMacHeader &hdr)
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.
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:1238
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:342
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:224
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:799
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.