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 #include "ns3/log.h"
21 #include "ns3/assert.h"
22 #include "ns3/simulator.h"
23 #include "ns3/fatal-error.h"
24 
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  tid = (*it)->hdr.GetQosTid ();
264  else
265  NS_FATAL_ERROR("Packet in blockAck manager retry queue is not Qos Data");
266  recipient = (*it)->hdr.GetAddr1 ();
267  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
268  NS_ASSERT (agreement != m_agreements.end());
269  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
270  {
271  //standard says the originator should not send a packet with seqnum < winstart
272  NS_LOG_DEBUG("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
273  agreement->second.second.erase ((*it));
274  it = m_retryPackets.erase (it);
275  continue;
276  }
277  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence ()+63) %4096)
278  {
279  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
280  }
281  packet = (*it)->packet->Copy();
282  hdr = (*it)->hdr;
283  hdr.SetRetry ();
284  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
285  if (hdr.IsQosData ())
286  tid = hdr.GetQosTid ();
287  else
288  NS_FATAL_ERROR("Packet in blockAck manager retry queue is not Qos Data");
289  recipient = hdr.GetAddr1 ();
290  if (!agreement->second.first.IsHtSupported ()
292  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
293  {
295  }
296  else
297  {
298  /* From section 9.10.3 in IEEE802.11e standard:
299  * In order to improve efficiency, originators using the Block Ack facility
300  * may send MPDU frames with the Ack Policy subfield in QoS control frames
301  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
302  * When there are sufficient number of MPDUs, the originator may switch back to
303  * the use of Block Ack.
304  */
306  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
307  i->second.second.erase (*it);
308  }
309  it = m_retryPackets.erase (it);
310  NS_LOG_DEBUG("Removed one packet retry buffer size = " <<m_retryPackets.size () );
311  break;
312  }
313  }
314  return packet;
315 }
316 
317 
319 BlockAckManager::PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *tstamp)
320 {
321  NS_LOG_FUNCTION (this);
322  Ptr<const Packet> packet = 0;
323  CleanupBuffers ();
324  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
325  NS_ASSERT (agreement != m_agreements.end());
326  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
327  for (; it != m_retryPackets.end();it++)
328  {
329  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
330  {
331  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
332  {
333  //standard says the originator should not send a packet with seqnum < winstart
334  NS_LOG_DEBUG("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
335  agreement->second.second.erase ((*it));
336  it = m_retryPackets.erase (it);
337  it--;
338  continue;
339  }
340  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
341  {
342  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
343  }
344  packet = (*it)->packet->Copy();
345  hdr = (*it)->hdr;
346  hdr.SetRetry ();
347  *tstamp = (*it)->timestamp;
348  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
349  Mac48Address recipient = hdr.GetAddr1 ();
350  if (!agreement->second.first.IsHtSupported ()
352  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
353  {
355  }
356  else
357  {
358  /* From section 9.10.3 in IEEE802.11e standard:
359  * In order to improve efficiency, originators using the Block Ack facility
360  * may send MPDU frames with the Ack Policy subfield in QoS control frames
361  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
362  * When there are sufficient number of MPDUs, the originator may switch back to
363  * the use of Block Ack.
364  */
366  }
367  NS_LOG_DEBUG("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
368  return packet;
369  }
370  }
371  return packet;
372 }
373 
374 bool
375 BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
376 {
377 
378  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();
379  for (; it != m_retryPackets.end (); it++)
380  {
381  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber)
382  {
383  WifiMacHeader hdr = (*it)->hdr;
384  uint8_t tid = hdr.GetQosTid ();
385  Mac48Address recipient = hdr.GetAddr1 ();
386 
387  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
388  i->second.second.erase ((*it));
389 
390  m_retryPackets.erase (it);
391  NS_LOG_DEBUG("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << (uint32_t) tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
392  return true;
393  }
394  }
395  return false;
396 }
397 
398 bool
400 {
401  NS_LOG_FUNCTION (this << &bar);
402  if (m_bars.size () > 0)
403  {
404  bar = m_bars.front ();
405  m_bars.pop_front ();
406  return true;
407  }
408  return false;
409 }
410 
411 bool
413 {
414  NS_LOG_FUNCTION (this);
415  return (m_retryPackets.size () > 0 || m_bars.size () > 0);
416 }
417 
418 uint32_t
420 {
421  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
422  uint32_t nPackets = 0;
423  if (ExistsAgreement (recipient, tid))
424  {
425  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
426  PacketQueueCI queueIt = (*it).second.second.begin ();
427  uint16_t currentSeq = 0;
428  while (queueIt != (*it).second.second.end ())
429  {
430  currentSeq = (*queueIt).hdr.GetSequenceNumber ();
431  nPackets++;
432  /* a fragmented packet must be counted as one packet */
433  while (queueIt != (*it).second.second.end () && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
434  {
435  queueIt++;
436  }
437  }
438  return nPackets;
439  }
440  return 0;
441 }
442 
443 uint32_t
445 {
446  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
447  uint32_t nPackets = 0;
448  uint16_t currentSeq = 0;
449  if (ExistsAgreement (recipient, tid))
450  {
451  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
452  while (it != m_retryPackets.end ())
453  {
454  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
455  {
456  currentSeq = (*it)->hdr.GetSequenceNumber ();
457  nPackets++;
458  /* a fragmented packet must be counted as one packet */
459  while (it != m_retryPackets.end () && (*it)->hdr.GetSequenceNumber () == currentSeq)
460  {
461  it++;
462  }
463  }
464  //go to next packet
465  if (it != m_retryPackets.end ())
466  {
467  it++;
468  }
469  }
470  }
471  return nPackets;
472 }
473 
474 void
476 {
477  NS_LOG_FUNCTION (this << static_cast<uint32_t> (nPackets));
478  m_blockAckThreshold = nPackets;
479 }
480 
481 void
483 {
484  NS_LOG_FUNCTION (this << manager);
485  m_stationManager = manager;
486 }
487 
488 bool
489 BlockAckManager::AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid)
490 {
491  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
492  while (it != m_retryPackets.end ())
493  {
494  NS_LOG_FUNCTION (this<<(*it)->hdr.GetType());
495  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
496  return true;
497  it++;
498  }
499  return false;
500 }
501 
502 void
504 {
505  NS_LOG_FUNCTION (this << blockAck << recipient);
506  uint16_t sequenceFirstLost = 0;
507  if (!blockAck->IsMultiTid ())
508  {
509  uint8_t tid = blockAck->GetTidInfo ();
511  {
512  bool foundFirstLost = false;
513  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
514  PacketQueueI queueEnd = it->second.second.end ();
515 
516  if (it->second.first.m_inactivityEvent.IsRunning ())
517  {
518  /* Upon reception of a block ack frame, the inactivity timer at the
519  originator must be reset.
520  For more details see section 11.5.3 in IEEE802.11e standard */
521  it->second.first.m_inactivityEvent.Cancel ();
522  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
523  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
525  this,
526  recipient, tid);
527  }
528  if (blockAck->IsBasic ())
529  {
530  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd;)
531  {
532  if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
533  (*queueIt).hdr.GetFragmentNumber ()))
534  {
535  queueIt = it->second.second.erase (queueIt);
536  }
537  else
538  {
539  if (!foundFirstLost)
540  {
541  foundFirstLost = true;
542  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
543  (*it).second.first.SetStartingSequence (sequenceFirstLost);
544  }
545 
546  if (!AlreadyExists((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
547  InsertInRetryQueue(queueIt);
548 
549  queueIt++;
550  }
551  }
552  }
553  else if (blockAck->IsCompressed ())
554  {
555  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd;)
556  {
557  if (blockAck->IsPacketReceived ((*queueIt).hdr.GetSequenceNumber ()))
558  {
559  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
560  while (queueIt != queueEnd
561  && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
562  {
563  //notify remote station of successful transmission
564  m_stationManager->ReportDataOk ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr, 0, txMode, 0);
565  if (!m_txOkCallback.IsNull ())
566  {
567  m_txOkCallback ((*queueIt).hdr);
568  }
569  queueIt = it->second.second.erase (queueIt);
570  }
571  }
572  else
573  {
574  if (!foundFirstLost)
575  {
576  foundFirstLost = true;
577  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
578  (*it).second.first.SetStartingSequence (sequenceFirstLost);
579  }
580  //notify remote station of unsuccessful transmission
581  m_stationManager->ReportDataFailed ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr);
582  if (!m_txFailedCallback.IsNull ())
583  {
584  m_txFailedCallback ((*queueIt).hdr);
585  }
586  if (!AlreadyExists((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
587  {
588  InsertInRetryQueue(queueIt);
589  }
590  queueIt++;
591  }
592  }
593  }
594  uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
595  if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
596  || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
597  {
598  it->second.first.CompleteExchange();
599  }
600  }
601  }
602  else
603  {
604  //NOT SUPPORTED FOR NOW
605  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
606  }
607 }
608 
609 void
611 {
612  NS_LOG_FUNCTION (this << bAckType);
613  m_blockAckType = bAckType;
614 }
615 
618 {
619  /* This method checks if a BlockAckRequest frame should be send to the recipient station.
620  Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
621  this number could be incorrect. In fact is possible that a block ack agreement exists for n
622  packets but some of these packets are dropped due to MSDU lifetime expiration.
623  */
624  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
625  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
626  NS_ASSERT (it != m_agreements.end ());
627 
628  if ((*it).second.first.IsBlockAckRequestNeeded ()
629  || (GetNRetryNeededPackets (recipient, tid) == 0
630  && m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) == 0))
631  {
632  OriginatorBlockAckAgreement &agreement = (*it).second.first;
633  agreement.CompleteExchange ();
634 
635  CtrlBAckRequestHeader reqHdr;
637  {
638  reqHdr.SetType (m_blockAckType);
639  reqHdr.SetTidInfo (agreement.GetTid ());
640  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
641  }
643  {
644  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
645  }
646  else
647  {
648  NS_FATAL_ERROR ("Invalid block ack type.");
649  }
650  Ptr<Packet> bar = Create<Packet> ();
651  bar->AddHeader (reqHdr);
652  return bar;
653  }
654  return 0;
655 }
656 
657 void
659 {
660  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
661  m_blockAckInactivityTimeout (recipient, tid, true);
662 }
663 
664 void
665 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
666 {
667  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
668  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
669  NS_ASSERT (it != m_agreements.end ());
670 
671  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
672  it->second.first.SetStartingSequence (startingSeq);
673 }
674 
675 void
677 {
678  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
679  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
680  NS_ASSERT (it != m_agreements.end ());
681  if (it != m_agreements.end ())
682  {
683  it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
684  }
685 }
686 
687 void
688 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, enum WifiMacHeader::QosAckPolicy policy)
689 {
690  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << nextSeqNumber);
691  Ptr<Packet> bar = 0;
692  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
693  NS_ASSERT (it != m_agreements.end ());
694 
695  uint16_t nextSeq;
696  if (GetNRetryNeededPackets (recipient, tid) > 0)
697  {
698  nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
699  }
700  else
701  {
702  nextSeq = nextSeqNumber;
703  }
704  it->second.first.NotifyMpduTransmission (nextSeq);
705  if (policy == WifiMacHeader::BLOCK_ACK)
706  {
707  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
708  if (bar != 0)
709  {
710  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
711  m_bars.push_back (request);
712  }
713  }
714 }
715 
716 void
718 {
719  NS_LOG_FUNCTION (this << queue);
720  m_queue = queue;
721 }
722 
723 bool
724 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
725 {
726  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
728  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
729  {
730  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) +
731  GetNBufferedPackets (recipient, tid);
732  if (packets >= m_blockAckThreshold)
733  {
734  NotifyAgreementEstablished (recipient, tid, startingSeq);
735  return true;
736  }
737  }
738  return false;
739 }
740 
741 void
743 {
744  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
745  DestroyAgreement (recipient, tid);
746 }
747 
748 bool
749 BlockAckManager::HasOtherFragments (uint16_t sequenceNumber) const
750 {
751  NS_LOG_FUNCTION (this << sequenceNumber);
752  bool retVal = false;
753  if (m_retryPackets.size () > 0)
754  {
755  Item next = *(m_retryPackets.front ());
756  if (next.hdr.GetSequenceNumber () == sequenceNumber)
757  {
758  retVal = true;
759  }
760  }
761  return retVal;
762 }
763 
764 uint32_t
766 {
767  NS_LOG_FUNCTION (this);
768  uint32_t size = 0;
769  if (m_retryPackets.size () > 0)
770  {
771  Item next = *(m_retryPackets.front ());
772  size = next.packet->GetSize ();
773  }
774  return size;
775 }
776 
777 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
778 {
779  //the standard says the BAR gets discarded when all MSDUs lifetime expires
780  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
781  NS_ASSERT (it != m_agreements.end());
782  CleanupBuffers();
783  if ((seqNumber+63) < it->second.first.GetStartingSequence())
784  return false;
785  else
786  return true;
787 }
788 
789 void
791 {
792  NS_LOG_FUNCTION (this);
793  for (AgreementsI j = m_agreements.begin (); j != m_agreements.end (); j++)
794  {
795  if (j->second.second.empty ())
796  {
797  continue;
798  }
799  Time now = Simulator::Now ();
800  PacketQueueI end = j->second.second.begin ();
801  for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
802  {
803  if (i->timestamp + m_maxDelay > now)
804  {
805  end = i;
806  break;
807  }
808  else
809  {
810  /* remove retry packet iterator if it's present in retry queue */
811  for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end ();)
812  {
813  if ((*it)->hdr.GetAddr1 () == j->second.first.GetPeer ()
814  && (*it)->hdr.GetQosTid () == j->second.first.GetTid ()
815  && (*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ())
816  {
817  it = m_retryPackets.erase (it);
818  }
819  else
820  {
821  it++;
822  }
823  }
824  }
825  }
826  j->second.second.erase (j->second.second.begin (), end);
827  j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
828  }
829 }
830 
831 void
833 {
834  NS_LOG_FUNCTION (this << maxDelay);
835  m_maxDelay = maxDelay;
836 }
837 
838 void
840 {
841  NS_LOG_FUNCTION (this << &callback);
842  m_blockAckInactivityTimeout = callback;
843 }
844 
845 void
847 {
848  NS_LOG_FUNCTION (this << &callback);
849  m_blockPackets = callback;
850 }
851 
852 void
854 {
855  NS_LOG_FUNCTION (this << &callback);
856  m_unblockPackets = callback;
857 }
858 
859 void
861 {
862  NS_LOG_FUNCTION (this << txMiddle);
863  m_txMiddle = txMiddle;
864 }
865 
866 uint16_t
868 {
869  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
870  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
871  while (it != m_retryPackets.end ())
872  {
873  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
874  {
875  return (*it)->hdr.GetSequenceNumber ();
876  }
877  it++;
878  }
879  return 4096;
880 }
881 
882 void
884 {
885  m_txOkCallback = callback;
886 }
887 
888 void
890 {
891  m_txFailedCallback = callback;
892 }
893 
894 void
896 {
897  NS_LOG_INFO ("Adding to retry queue " <<(*item).hdr.GetSequenceNumber ());
898  if (m_retryPackets.size () == 0)
899  {
900  m_retryPackets.push_back (item);
901  }
902  else
903  {
904  for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end ();)
905  {
906  if(((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
907  {
908  it = m_retryPackets.insert (it, item);
909  break;
910  }
911  else
912  {
913  it++;
914  if(it == m_retryPackets.end ())
915  m_retryPackets.push_back (item);
916  }
917  }
918  }
919 }
920 
921 } // 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.
Definition: mgt-headers.cc:947
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:95
#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:978
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:454
bool IsImmediateBlockAck(void) const
Return whether the Block ACK policy is immediate Block ACK.
Definition: mgt-headers.cc:935
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1072
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:61
#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:766
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)
Fatal error handling.
Definition: fatal-error.h:100
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:86
bool HasPackets(void) const
Returns true if there are packets that need of retransmission or at least a BAR is scheduled...
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Schedule an event to expire at the relative time "time" is reached.
Definition: simulator.h:819
ns3::Time timeout
BlockAckType
Enumeration for different block ACK policies.
Definition: ctrl-headers.h:30
Block Ack Request.
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:93
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.
Definition: mgt-headers.cc:953
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)
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:183
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).
Definition: mgt-headers.cc:745
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.
Definition: mgt-headers.cc:769
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.
Definition: mgt-headers.cc:941
uint8_t GetTid(void) const
Return the Traffic ID (TID).
Definition: mgt-headers.cc:929
void SetMaxPacketDelay(Time maxDelay)
void NotifyMpduTransmission(Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
bool IsImmediateBlockAck(void) const
Return whether the Block ACK policy is immediate Block ACK.
Definition: mgt-headers.cc:751
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.
Definition: mgt-headers.cc:775
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:582
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:875
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
Headers for Block ack request.
Definition: ctrl-headers.h:49
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:253
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.
Definition: mgt-headers.cc:757
std::list< Item >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.