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
530 {
531  NS_LOG_FUNCTION (this << blockAck << recipient);
532  uint16_t sequenceFirstLost = 0;
533  if (!blockAck->IsMultiTid ())
534  {
535  uint8_t tid = blockAck->GetTidInfo ();
537  {
538  bool foundFirstLost = false;
539  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
540  PacketQueueI queueEnd = it->second.second.end ();
541 
542  if (it->second.first.m_inactivityEvent.IsRunning ())
543  {
544  /* Upon reception of a block ack frame, the inactivity timer at the
545  originator must be reset.
546  For more details see section 11.5.3 in IEEE802.11e standard */
547  it->second.first.m_inactivityEvent.Cancel ();
548  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
549  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
551  this,
552  recipient, tid);
553  }
554  if (blockAck->IsBasic ())
555  {
556  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
557  {
558  if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
559  (*queueIt).hdr.GetFragmentNumber ()))
560  {
561  queueIt = it->second.second.erase (queueIt);
562  }
563  else
564  {
565  if (!foundFirstLost)
566  {
567  foundFirstLost = true;
568  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
569  (*it).second.first.SetStartingSequence (sequenceFirstLost);
570  }
571 
572  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
573  {
574  InsertInRetryQueue (queueIt);
575  }
576 
577  queueIt++;
578  }
579  }
580  }
581  else if (blockAck->IsCompressed ())
582  {
583  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
584  {
585  if (blockAck->IsPacketReceived ((*queueIt).hdr.GetSequenceNumber ()))
586  {
587  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
588  while (queueIt != queueEnd
589  && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
590  {
591  //notify remote station of successful transmission
592  m_stationManager->ReportDataOk ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr, 0, txMode, 0);
593  if (!m_txOkCallback.IsNull ())
594  {
595  m_txOkCallback ((*queueIt).hdr);
596  }
597  queueIt = it->second.second.erase (queueIt);
598  }
599  }
600  else
601  {
602  if (!foundFirstLost)
603  {
604  foundFirstLost = true;
605  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
606  (*it).second.first.SetStartingSequence (sequenceFirstLost);
607  }
608  //notify remote station of unsuccessful transmission
609  m_stationManager->ReportDataFailed ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr);
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  uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
623  if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
624  || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
625  {
626  it->second.first.CompleteExchange ();
627  }
628  }
629  }
630  else
631  {
632  //NOT SUPPORTED FOR NOW
633  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
634  }
635 }
636 
637 void
639 {
640  NS_LOG_FUNCTION (this << bAckType);
641  m_blockAckType = bAckType;
642 }
643 
646 {
647  /* This method checks if a BlockAckRequest frame should be send to the recipient station.
648  Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
649  this number could be incorrect. In fact is possible that a block ack agreement exists for n
650  packets but some of these packets are dropped due to MSDU lifetime expiration.
651  */
652  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
653  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
654  NS_ASSERT (it != m_agreements.end ());
655 
656  if ((*it).second.first.IsBlockAckRequestNeeded ()
657  || (GetNRetryNeededPackets (recipient, tid) == 0
658  && m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) == 0))
659  {
660  OriginatorBlockAckAgreement &agreement = (*it).second.first;
661  agreement.CompleteExchange ();
662 
663  CtrlBAckRequestHeader reqHdr;
665  {
666  reqHdr.SetType (m_blockAckType);
667  reqHdr.SetTidInfo (agreement.GetTid ());
668  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
669  }
671  {
672  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
673  }
674  else
675  {
676  NS_FATAL_ERROR ("Invalid block ack type.");
677  }
678  Ptr<Packet> bar = Create<Packet> ();
679  bar->AddHeader (reqHdr);
680  return bar;
681  }
682  return 0;
683 }
684 
685 void
687 {
688  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
689  m_blockAckInactivityTimeout (recipient, tid, true);
690 }
691 
692 void
693 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
694 {
695  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
696  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
697  NS_ASSERT (it != m_agreements.end ());
698 
699  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
700  it->second.first.SetStartingSequence (startingSeq);
701 }
702 
703 void
705 {
706  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
707  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
708  NS_ASSERT (it != m_agreements.end ());
709  if (it != m_agreements.end ())
710  {
711  it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
712  }
713 }
714 
715 void
716 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, enum WifiMacHeader::QosAckPolicy policy)
717 {
718  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << nextSeqNumber);
719  Ptr<Packet> bar = 0;
720  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
721  NS_ASSERT (it != m_agreements.end ());
722 
723  uint16_t nextSeq;
724  if (GetNRetryNeededPackets (recipient, tid) > 0)
725  {
726  nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
727  }
728  else
729  {
730  nextSeq = nextSeqNumber;
731  }
732  it->second.first.NotifyMpduTransmission (nextSeq);
733  if (policy == WifiMacHeader::BLOCK_ACK)
734  {
735  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
736  if (bar != 0)
737  {
738  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
739  m_bars.push_back (request);
740  }
741  }
742 }
743 
744 void
746 {
747  NS_LOG_FUNCTION (this << queue);
748  m_queue = queue;
749 }
750 
751 bool
752 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
753 {
754  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
756  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
757  {
758  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) +
759  GetNBufferedPackets (recipient, tid);
760  if (packets >= m_blockAckThreshold)
761  {
762  NotifyAgreementEstablished (recipient, tid, startingSeq);
763  return true;
764  }
765  }
766  return false;
767 }
768 
769 void
771 {
772  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
773  DestroyAgreement (recipient, tid);
774 }
775 
776 bool
777 BlockAckManager::HasOtherFragments (uint16_t sequenceNumber) const
778 {
779  NS_LOG_FUNCTION (this << sequenceNumber);
780  bool retVal = false;
781  if (m_retryPackets.size () > 0)
782  {
783  Item next = *(m_retryPackets.front ());
784  if (next.hdr.GetSequenceNumber () == sequenceNumber)
785  {
786  retVal = true;
787  }
788  }
789  return retVal;
790 }
791 
792 uint32_t
794 {
795  NS_LOG_FUNCTION (this);
796  uint32_t size = 0;
797  if (m_retryPackets.size () > 0)
798  {
799  Item next = *(m_retryPackets.front ());
800  size = next.packet->GetSize ();
801  }
802  return size;
803 }
804 
805 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
806 {
807  //The standard says the BAR gets discarded when all MSDUs lifetime expires
808  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
809  NS_ASSERT (it != m_agreements.end ());
810  CleanupBuffers ();
811  if ((seqNumber + 63) < it->second.first.GetStartingSequence ())
812  {
813  return false;
814  }
815  else
816  {
817  return true;
818  }
819 }
820 
821 void
823 {
824  NS_LOG_FUNCTION (this);
825  for (AgreementsI j = m_agreements.begin (); j != m_agreements.end (); j++)
826  {
827  if (j->second.second.empty ())
828  {
829  continue;
830  }
831  Time now = Simulator::Now ();
832  PacketQueueI end = j->second.second.begin ();
833  for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
834  {
835  if (i->timestamp + m_maxDelay > now)
836  {
837  end = i;
838  break;
839  }
840  else
841  {
842  /* remove retry packet iterator if it's present in retry queue */
843  for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
844  {
845  if ((*it)->hdr.GetAddr1 () == j->second.first.GetPeer ()
846  && (*it)->hdr.GetQosTid () == j->second.first.GetTid ()
847  && (*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ())
848  {
849  it = m_retryPackets.erase (it);
850  }
851  else
852  {
853  it++;
854  }
855  }
856  }
857  }
858  j->second.second.erase (j->second.second.begin (), end);
859  j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
860  }
861 }
862 
863 void
865 {
866  NS_LOG_FUNCTION (this << maxDelay);
867  m_maxDelay = maxDelay;
868 }
869 
870 void
872 {
873  NS_LOG_FUNCTION (this << &callback);
874  m_blockAckInactivityTimeout = callback;
875 }
876 
877 void
879 {
880  NS_LOG_FUNCTION (this << &callback);
881  m_blockPackets = callback;
882 }
883 
884 void
886 {
887  NS_LOG_FUNCTION (this << &callback);
888  m_unblockPackets = callback;
889 }
890 
891 void
893 {
894  NS_LOG_FUNCTION (this << txMiddle);
895  m_txMiddle = txMiddle;
896 }
897 
898 uint16_t
900 {
901  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
902  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
903  while (it != m_retryPackets.end ())
904  {
905  if (!(*it)->hdr.IsQosData ())
906  {
907  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
908  }
909  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
910  {
911  return (*it)->hdr.GetSequenceNumber ();
912  }
913  it++;
914  }
915  return 4096;
916 }
917 
918 void
920 {
921  m_txOkCallback = callback;
922 }
923 
924 void
926 {
927  m_txFailedCallback = callback;
928 }
929 
930 void
932 {
933  NS_LOG_INFO ("Adding to retry queue " << (*item).hdr.GetSequenceNumber ());
934  if (m_retryPackets.size () == 0)
935  {
936  m_retryPackets.push_back (item);
937  }
938  else
939  {
940  for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
941  {
942  if (((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
943  {
944  it = m_retryPackets.insert (it, item);
945  break;
946  }
947  else
948  {
949  it++;
950  if (it == m_retryPackets.end ())
951  {
952  m_retryPackets.push_back (item);
953  }
954  }
955  }
956  }
957 }
958 
959 } //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
#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 ReportDataFailed(Mac48Address address, const WifiMacHeader *header)
Should be invoked whenever the AckTimeout associated to a transmission attempt expires.
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:538
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)
#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:97
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::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 ReportDataOk(Mac48Address address, const WifiMacHeader *header, double ackSnr, WifiMode ackMode, double dataSnr)
Should be invoked whenever we receive the Ack associated to a data packet we just sent...
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:670
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 NotifyGotBlockAck(const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode)
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:255
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.