A Discrete-Event Network Simulator
API
block-ack-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009, 2010 MIRKO BANCHI
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mirko Banchi <mk.banchi@gmail.com>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/simulator.h"
23 #include "block-ack-manager.h"
24 #include "mgt-headers.h"
25 #include "wifi-mac-queue.h"
26 #include "mac-tx-middle.h"
27 
28 namespace ns3 {
29 
30 NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
31 
33 {
34  NS_LOG_FUNCTION (this);
35 }
36 
38  : packet (packet),
39  hdr (hdr),
40  timestamp (tStamp)
41 {
42  NS_LOG_FUNCTION (this << packet << hdr << tStamp);
43 }
44 
46 {
47  NS_LOG_FUNCTION (this);
48 }
49 
50 Bar::Bar (Ptr<const Packet> bar, Mac48Address recipient, uint8_t tid, bool immediate)
51  : bar (bar),
52  recipient (recipient),
53  tid (tid),
54  immediate (immediate)
55 {
56  NS_LOG_FUNCTION (this << bar << recipient << (uint16_t)tid << immediate);
57 }
58 
60 
61 TypeId
63 {
64  static TypeId tid = TypeId ("ns3::BlockAckManager")
65  .SetParent<Object> ()
66  .SetGroupName ("Wifi")
67  .AddConstructor<BlockAckManager> ()
68  ;
69  return tid;
70 }
71 
73 {
74  NS_LOG_FUNCTION (this);
75 }
76 
78 {
79  NS_LOG_FUNCTION (this);
80  m_queue = 0;
81  m_agreements.clear ();
82  m_retryPackets.clear ();
83 }
84 
85 bool
86 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
87 {
88  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid);
89  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
90 }
91 
92 bool
95 {
96  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid << state);
97  AgreementsCI it;
98  it = m_agreements.find (std::make_pair (recipient, tid));
99  if (it != m_agreements.end ())
100  {
101  switch (state)
102  {
104  return it->second.first.IsInactive ();
106  return it->second.first.IsEstablished ();
108  return it->second.first.IsPending ();
110  return it->second.first.IsUnsuccessful ();
111  default:
112  NS_FATAL_ERROR ("Invalid state for block ack agreement");
113  }
114  }
115  return false;
116 }
117 
118 void
120 {
121  NS_LOG_FUNCTION (this << reqHdr << recipient);
122  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
123  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
124  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
125  /* For now we assume that originator doesn't use this field. Use of this field
126  is mandatory only for recipient */
127  agreement.SetBufferSize (64);
128  agreement.SetWinEnd ((agreement.GetStartingSequence () + agreement.GetBufferSize () - 1) % 4096);
129  agreement.SetTimeout (reqHdr->GetTimeout ());
130  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
131  agreement.SetHtSupported (m_stationManager->HasHtSupported ());
132  if (reqHdr->IsImmediateBlockAck ())
133  {
134  agreement.SetImmediateBlockAck ();
135  }
136  else
137  {
138  agreement.SetDelayedBlockAck ();
139  }
140  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
141  PacketQueue queue (0);
142  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
143  m_agreements.insert (std::make_pair (key, value));
144  m_blockPackets (recipient, reqHdr->GetTid ());
145 }
146 
147 void
149 {
150  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid);
151  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
152  if (it != m_agreements.end ())
153  {
154  for (std::list<PacketQueueI>::const_iterator i = m_retryPackets.begin (); i != m_retryPackets.end (); )
155  {
156  if ((*i)->hdr.GetAddr1 () == recipient && (*i)->hdr.GetQosTid () == tid)
157  {
158  i = m_retryPackets.erase (i);
159  }
160  else
161  {
162  i++;
163  }
164  }
165  m_agreements.erase (it);
166  //remove scheduled bar
167  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
168  {
169  if (i->recipient == recipient && i->tid == tid)
170  {
171  i = m_bars.erase (i);
172  }
173  else
174  {
175  i++;
176  }
177  }
178  }
179 }
180 
181 void
183 {
184  NS_LOG_FUNCTION (this << respHdr << recipient);
185  uint8_t tid = respHdr->GetTid ();
186  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
187  if (it != m_agreements.end ())
188  {
189  OriginatorBlockAckAgreement& agreement = it->second.first;
190  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
191  agreement.SetTimeout (respHdr->GetTimeout ());
192  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
193  if (respHdr->IsImmediateBlockAck ())
194  {
195  agreement.SetImmediateBlockAck ();
196  }
197  else
198  {
199  agreement.SetDelayedBlockAck ();
200  }
202  if (agreement.GetTimeout () != 0)
203  {
204  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
205  agreement.m_inactivityEvent = Simulator::Schedule (timeout,
207  this,
208  recipient, tid);
209  }
210  }
211  m_unblockPackets (recipient, tid);
212 }
213 
214 void
216 {
217  NS_LOG_FUNCTION (this << packet << hdr << tStamp);
218  NS_ASSERT (hdr.IsQosData ());
219 
220  uint8_t tid = hdr.GetQosTid ();
221  Mac48Address recipient = hdr.GetAddr1 ();
222 
223  Item item (packet, hdr, tStamp);
224  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
225  NS_ASSERT (it != m_agreements.end ());
226  PacketQueueI queueIt = it->second.second.begin ();
227  for (; queueIt != it->second.second.end (); )
228  {
229  if (((hdr.GetSequenceNumber () - queueIt->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
230  {
231  queueIt = it->second.second.insert (queueIt, item);
232  break;
233  }
234  else
235  {
236  queueIt++;
237  }
238  }
239  if (queueIt == it->second.second.end ())
240  {
241  it->second.second.push_back (item);
242  }
243 }
244 
245 void
247 {
248  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
249  NS_ASSERT (it != m_agreements.end ());
250  OriginatorBlockAckAgreement &agreement = (*it).second.first;
251  agreement.CompleteExchange ();
252 }
253 
256 {
257  NS_LOG_FUNCTION (this << &hdr);
258  Ptr<const Packet> packet = 0;
259  uint8_t tid;
260  Mac48Address recipient;
261  CleanupBuffers ();
262  if (!m_retryPackets.empty ())
263  {
264  NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets.size ());
265  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
266  while (it != m_retryPackets.end ())
267  {
268  if ((*it)->hdr.IsQosData ())
269  {
270  tid = (*it)->hdr.GetQosTid ();
271  }
272  else
273  {
274  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
275  }
276  recipient = (*it)->hdr.GetAddr1 ();
277  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
278  NS_ASSERT (agreement != m_agreements.end ());
279  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
280  {
281  //Standard says the originator should not send a packet with seqnum < winstart
282  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
283  agreement->second.second.erase ((*it));
284  it = m_retryPackets.erase (it);
285  continue;
286  }
287  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
288  {
289  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
290  }
291  packet = (*it)->packet->Copy ();
292  hdr = (*it)->hdr;
293  hdr.SetRetry ();
294  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
295  if (hdr.IsQosData ())
296  {
297  tid = hdr.GetQosTid ();
298  }
299  else
300  {
301  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
302  }
303  recipient = hdr.GetAddr1 ();
304  if (!agreement->second.first.IsHtSupported ()
306  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
307  {
309  }
310  else
311  {
312  /* From section 9.10.3 in IEEE802.11e standard:
313  * In order to improve efficiency, originators using the Block Ack facility
314  * may send MPDU frames with the Ack Policy subfield in QoS control frames
315  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
316  * When there are sufficient number of MPDUs, the originator may switch back to
317  * the use of Block Ack.
318  */
320  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
321  i->second.second.erase (*it);
322  }
323  it = m_retryPackets.erase (it);
324  NS_LOG_DEBUG ("Removed one packet, retry buffer size = " << m_retryPackets.size () );
325  break;
326  }
327  }
328  return packet;
329 }
330 
333 {
334  NS_LOG_FUNCTION (this << &hdr);
335  Ptr<const Packet> packet = 0;
336  uint8_t tid;
337  Mac48Address recipient;
338  CleanupBuffers ();
339  if (!m_retryPackets.empty ())
340  {
341  NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets.size ());
342  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
343  while (it != m_retryPackets.end ())
344  {
345  if ((*it)->hdr.IsQosData ())
346  {
347  tid = (*it)->hdr.GetQosTid ();
348  }
349  else
350  {
351  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
352  }
353  recipient = (*it)->hdr.GetAddr1 ();
354  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
355  NS_ASSERT (agreement != m_agreements.end ());
356  packet = (*it)->packet->Copy ();
357  hdr = (*it)->hdr;
358  hdr.SetRetry ();
359  if (hdr.IsQosData ())
360  {
361  tid = hdr.GetQosTid ();
362  }
363  else
364  {
365  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
366  }
367  recipient = hdr.GetAddr1 ();
368  if (!agreement->second.first.IsHtSupported ()
370  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
371  {
373  }
374  else
375  {
376  /* From section 9.10.3 in IEEE802.11e standard:
377  * In order to improve efficiency, originators using the Block Ack facility
378  * may send MPDU frames with the Ack Policy subfield in QoS control frames
379  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
380  * When there are sufficient number of MPDUs, the originator may switch back to
381  * the use of Block Ack.
382  */
384  }
385  break;
386  }
387  }
388  return packet;
389 }
390 
393 {
394  NS_LOG_FUNCTION (this);
395  Ptr<const Packet> packet = 0;
396  CleanupBuffers ();
397  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
398  NS_ASSERT (agreement != m_agreements.end ());
399  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
400  for (; it != m_retryPackets.end (); it++)
401  {
402  if (!(*it)->hdr.IsQosData ())
403  {
404  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
405  }
406  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
407  {
408  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
409  {
410  //standard says the originator should not send a packet with seqnum < winstart
411  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
412  agreement->second.second.erase ((*it));
413  it = m_retryPackets.erase (it);
414  it--;
415  continue;
416  }
417  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
418  {
419  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
420  }
421  packet = (*it)->packet->Copy ();
422  hdr = (*it)->hdr;
423  hdr.SetRetry ();
424  *tstamp = (*it)->timestamp;
425  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
426  Mac48Address recipient = hdr.GetAddr1 ();
427  if (!agreement->second.first.IsHtSupported ()
429  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
430  {
432  }
433  else
434  {
435  /* From section 9.10.3 in IEEE802.11e standard:
436  * In order to improve efficiency, originators using the Block Ack facility
437  * may send MPDU frames with the Ack Policy subfield in QoS control frames
438  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
439  * When there are sufficient number of MPDUs, the originator may switch back to
440  * the use of Block Ack.
441  */
443  }
444  NS_LOG_DEBUG ("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
445  return packet;
446  }
447  }
448  return packet;
449 }
450 
451 bool
452 BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
453 {
454 
455  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
456  for (; it != m_retryPackets.end (); it++)
457  {
458  if (!(*it)->hdr.IsQosData ())
459  {
460  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
461  }
462  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber)
463  {
464  WifiMacHeader hdr = (*it)->hdr;
465  uint8_t tid = hdr.GetQosTid ();
466  Mac48Address recipient = hdr.GetAddr1 ();
467 
468  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
469  i->second.second.erase ((*it));
470 
471  m_retryPackets.erase (it);
472  NS_LOG_DEBUG ("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << (uint16_t)tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
473  return true;
474  }
475  }
476  return false;
477 }
478 
479 bool
481 {
482  NS_LOG_FUNCTION (this << &bar);
483  if (m_bars.size () > 0)
484  {
485  bar = m_bars.front ();
486  m_bars.pop_front ();
487  return true;
488  }
489  return false;
490 }
491 
492 bool
494 {
495  NS_LOG_FUNCTION (this);
496  return (m_retryPackets.size () > 0 || m_bars.size () > 0);
497 }
498 
499 uint32_t
501 {
502  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid);
503  uint32_t nPackets = 0;
504  if (ExistsAgreement (recipient, tid))
505  {
506  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
507  PacketQueueCI queueIt = (*it).second.second.begin ();
508  uint16_t currentSeq = 0;
509  while (queueIt != (*it).second.second.end ())
510  {
511  currentSeq = (*queueIt).hdr.GetSequenceNumber ();
512  nPackets++;
513  /* a fragmented packet must be counted as one packet */
514  while (queueIt != (*it).second.second.end () && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
515  {
516  queueIt++;
517  }
518  }
519  return nPackets;
520  }
521  return 0;
522 }
523 
524 uint32_t
526 {
527  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid);
528  uint32_t nPackets = 0;
529  uint16_t currentSeq = 0;
530  if (ExistsAgreement (recipient, tid))
531  {
532  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
533  while (it != m_retryPackets.end ())
534  {
535  if (!(*it)->hdr.IsQosData ())
536  {
537  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
538  }
539  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
540  {
541  currentSeq = (*it)->hdr.GetSequenceNumber ();
542  nPackets++;
543  /* a fragmented packet must be counted as one packet */
544  while (it != m_retryPackets.end () && (*it)->hdr.GetSequenceNumber () == currentSeq)
545  {
546  it++;
547  }
548  }
549  //go to next packet
550  else
551  {
552  it++;
553  }
554  }
555  }
556  return nPackets;
557 }
558 
559 void
561 {
562  NS_LOG_FUNCTION (this << (uint16_t)nPackets);
563  m_blockAckThreshold = nPackets;
564 }
565 
566 void
568 {
569  NS_LOG_FUNCTION (this << manager);
570  m_stationManager = manager;
571 }
572 
573 bool
574 BlockAckManager::AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid) const
575 {
576  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
577  while (it != m_retryPackets.end ())
578  {
579  NS_LOG_FUNCTION (this << (*it)->hdr.GetType ());
580  if (!(*it)->hdr.IsQosData ())
581  {
582  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
583  }
584  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
585  {
586  return true;
587  }
588  it++;
589  }
590  return false;
591 }
592 
593 void
594 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
595 {
596  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
597  uint16_t sequenceFirstLost = 0;
598  if (!blockAck->IsMultiTid ())
599  {
600  uint8_t tid = blockAck->GetTidInfo ();
602  {
603  bool foundFirstLost = false;
604  uint32_t nSuccessfulMpdus = 0;
605  uint32_t nFailedMpdus = 0;
606  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
607  PacketQueueI queueEnd = it->second.second.end ();
608 
609  if (it->second.first.m_inactivityEvent.IsRunning ())
610  {
611  /* Upon reception of a block ack frame, the inactivity timer at the
612  originator must be reset.
613  For more details see section 11.5.3 in IEEE802.11e standard */
614  it->second.first.m_inactivityEvent.Cancel ();
615  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
616  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
618  this,
619  recipient, tid);
620  }
621  if (blockAck->IsBasic ())
622  {
623  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
624  {
625  if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
626  (*queueIt).hdr.GetFragmentNumber ()))
627  {
628  nSuccessfulMpdus++;
629  RemoveFromRetryQueue (recipient, tid, (*queueIt).hdr.GetSequenceNumber ());
630  queueIt = it->second.second.erase (queueIt);
631  }
632  else
633  {
634  if (!foundFirstLost)
635  {
636  foundFirstLost = true;
637  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
638  (*it).second.first.SetStartingSequence (sequenceFirstLost);
639  }
640  nFailedMpdus++;
641  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
642  {
643  InsertInRetryQueue (queueIt);
644  }
645  queueIt++;
646  }
647  }
648  }
649  else if (blockAck->IsCompressed ())
650  {
651  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
652  {
653  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
654  if (blockAck->IsPacketReceived (currentSeq))
655  {
656  while (queueIt != queueEnd
657  && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
658  {
659  nSuccessfulMpdus++;
660  if (!m_txOkCallback.IsNull ())
661  {
662  m_txOkCallback ((*queueIt).hdr);
663  }
664  RemoveFromRetryQueue (recipient, tid, currentSeq);
665  queueIt = it->second.second.erase (queueIt);
666  }
667  }
668  else
669  {
670  if (!foundFirstLost)
671  {
672  foundFirstLost = true;
673  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
674  (*it).second.first.SetStartingSequence (sequenceFirstLost);
675  }
676  nFailedMpdus++;
677  if (!m_txFailedCallback.IsNull ())
678  {
679  m_txFailedCallback ((*queueIt).hdr);
680  }
681  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
682  {
683  InsertInRetryQueue (queueIt);
684  }
685  queueIt++;
686  }
687  }
688  }
689  m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
690  uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
691  if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
692  || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
693  {
694  it->second.first.CompleteExchange ();
695  }
696  }
697  }
698  else
699  {
700  //NOT SUPPORTED FOR NOW
701  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
702  }
703 }
704 
705 void
707 {
708  NS_LOG_FUNCTION (this << bAckType);
709  m_blockAckType = bAckType;
710 }
711 
714 {
715  /* This method checks if a BlockAckRequest frame should be send to the recipient station.
716  Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
717  this number could be incorrect. In fact is possible that a block ack agreement exists for n
718  packets but some of these packets are dropped due to MSDU lifetime expiration.
719  */
720  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
721  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
722  NS_ASSERT (it != m_agreements.end ());
723 
724  if ((*it).second.first.IsBlockAckRequestNeeded ()
725  || (GetNRetryNeededPackets (recipient, tid) == 0
726  && m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) == 0))
727  {
728  OriginatorBlockAckAgreement &agreement = (*it).second.first;
729  agreement.CompleteExchange ();
730 
731  CtrlBAckRequestHeader reqHdr;
733  {
734  reqHdr.SetType (m_blockAckType);
735  reqHdr.SetTidInfo (agreement.GetTid ());
736  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
737  }
739  {
740  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
741  }
742  else
743  {
744  NS_FATAL_ERROR ("Invalid block ack type.");
745  }
746  Ptr<Packet> bar = Create<Packet> ();
747  bar->AddHeader (reqHdr);
748  return bar;
749  }
750  return 0;
751 }
752 
753 void
755 {
756  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
757  m_blockAckInactivityTimeout (recipient, tid, true);
758 }
759 
760 void
761 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
762 {
763  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << startingSeq);
764  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
765  NS_ASSERT (it != m_agreements.end ());
766 
767  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
768  it->second.first.SetStartingSequence (startingSeq);
769 }
770 
771 void
773 {
774  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid));
775  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
776  NS_ASSERT (it != m_agreements.end ());
777  if (it != m_agreements.end ())
778  {
779  it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
780  }
781 }
782 
783 void
784 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
785 {
786  NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << nextSeqNumber);
787  Ptr<Packet> bar = 0;
788  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
789  NS_ASSERT (it != m_agreements.end ());
790 
791  uint16_t nextSeq;
792  if (GetNRetryNeededPackets (recipient, tid) > 0)
793  {
794  nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
795  }
796  else
797  {
798  nextSeq = nextSeqNumber;
799  }
800  it->second.first.NotifyMpduTransmission (nextSeq);
801  if (policy == WifiMacHeader::BLOCK_ACK)
802  {
803  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
804  if (bar != 0)
805  {
806  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
807  m_bars.push_back (request);
808  }
809  }
810 }
811 
812 void
814 {
815  NS_LOG_FUNCTION (this << queue);
816  m_queue = queue;
817 }
818 
819 bool
820 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
821 {
822  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid << startingSeq);
824  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
825  {
826  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) +
827  GetNBufferedPackets (recipient, tid);
828  if (packets >= m_blockAckThreshold)
829  {
830  NotifyAgreementEstablished (recipient, tid, startingSeq);
831  return true;
832  }
833  }
834  return false;
835 }
836 
837 void
839 {
840  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid);
841  DestroyAgreement (recipient, tid);
842 }
843 
844 bool
845 BlockAckManager::HasOtherFragments (uint16_t sequenceNumber) const
846 {
847  NS_LOG_FUNCTION (this << sequenceNumber);
848  bool retVal = false;
849  if (m_retryPackets.size () > 0)
850  {
851  Item next = *(m_retryPackets.front ());
852  if (next.hdr.GetSequenceNumber () == sequenceNumber)
853  {
854  retVal = true;
855  }
856  }
857  return retVal;
858 }
859 
860 uint32_t
862 {
863  NS_LOG_FUNCTION (this);
864  uint32_t size = 0;
865  if (m_retryPackets.size () > 0)
866  {
867  Item next = *(m_retryPackets.front ());
868  size = next.packet->GetSize ();
869  }
870  return size;
871 }
872 
873 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
874 {
875  //The standard says the BAR gets discarded when all MSDUs lifetime expires
876  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
877  NS_ASSERT (it != m_agreements.end ());
878  CleanupBuffers ();
879  if ((seqNumber + 63) < it->second.first.GetStartingSequence ())
880  {
881  return false;
882  }
883  else
884  {
885  return true;
886  }
887 }
888 
889 void
891 {
892  /* remove retry packet iterator if it's present in retry queue */
893  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
894  while (it != m_retryPackets.end ())
895  {
896  if ((*it)->hdr.GetAddr1 () == address
897  && (*it)->hdr.GetQosTid () == tid
898  && (*it)->hdr.GetSequenceNumber () == seq)
899  {
900  it = m_retryPackets.erase (it);
901  }
902  else
903  {
904  it++;
905  }
906  }
907 }
908 
909 void
911 {
912  NS_LOG_FUNCTION (this);
913  for (AgreementsI j = m_agreements.begin (); j != m_agreements.end (); j++)
914  {
915  if (j->second.second.empty ())
916  {
917  continue;
918  }
919  Time now = Simulator::Now ();
920  PacketQueueI end = j->second.second.begin ();
921  for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
922  {
923  if (i->timestamp + m_maxDelay > now)
924  {
925  end = i;
926  break;
927  }
928  else
929  {
930  RemoveFromRetryQueue (j->second.first.GetPeer (),
931  j->second.first.GetTid (),
932  i->hdr.GetSequenceNumber ());
933  }
934  }
935  j->second.second.erase (j->second.second.begin (), end);
936  j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
937  }
938 }
939 
940 void
942 {
943  NS_LOG_FUNCTION (this << maxDelay);
944  m_maxDelay = maxDelay;
945 }
946 
947 void
949 {
950  NS_LOG_FUNCTION (this << &callback);
951  m_blockAckInactivityTimeout = callback;
952 }
953 
954 void
956 {
957  NS_LOG_FUNCTION (this << &callback);
958  m_blockPackets = callback;
959 }
960 
961 void
963 {
964  NS_LOG_FUNCTION (this << &callback);
965  m_unblockPackets = callback;
966 }
967 
968 void
970 {
971  NS_LOG_FUNCTION (this << txMiddle);
972  m_txMiddle = txMiddle;
973 }
974 
975 uint16_t
977 {
978  NS_LOG_FUNCTION (this << recipient << (uint16_t)tid);
979  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
980  while (it != m_retryPackets.end ())
981  {
982  if (!(*it)->hdr.IsQosData ())
983  {
984  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
985  }
986  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
987  {
988  return (*it)->hdr.GetSequenceNumber ();
989  }
990  it++;
991  }
992  return 4096;
993 }
994 
995 void
997 {
998  m_txOkCallback = callback;
999 }
1000 
1001 void
1003 {
1004  m_txFailedCallback = callback;
1005 }
1006 
1007 void
1009 {
1010  NS_LOG_INFO ("Adding to retry queue " << (*item).hdr.GetSequenceNumber ());
1011  if (m_retryPackets.size () == 0)
1012  {
1013  m_retryPackets.push_back (item);
1014  }
1015  else
1016  {
1017  for (std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
1018  {
1019  if (((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
1020  {
1021  it = m_retryPackets.insert (it, item);
1022  break;
1023  }
1024  else
1025  {
1026  it++;
1027  if (it == m_retryPackets.end ())
1028  {
1029  m_retryPackets.push_back (item);
1030  }
1031  }
1032  }
1033  }
1034 }
1035 
1036 } //namespace ns3
void SetRetry(void)
Set the Retry bit in the Frame Control field.
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
uint16_t GetBufferSize(void) const
Return the buffer size.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
void NotifyGotBlockAck(const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
Callback template class.
Definition: callback.h:1176
std::list< Item > PacketQueue
typedef for a list of Item struct.
Maintains the state and information about transmitted MPDUs with ack policy block ack for an originat...
uint16_t GetTimeout(void) const
Return the timeout.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::const_iterator AgreementsCI
typedef for a const iterator for Agreements.
void CreateAgreement(const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient)
Ptr< const Packet > PeekNextPacketByTidAndAddress(WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *timestamp)
Peek in retransmit queue and get the next packet having address indicated by type equals to addr...
void StorePacket(Ptr< const Packet > packet, const WifiMacHeader &hdr, Time tStamp)
uint8_t m_blockAckThreshold
bock ack threshold
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, tid), a set of packets for whi...
Implement the header for management frames of type add block ack request.
Definition: mgt-headers.h:758
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 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:796
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.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:277
#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:97
TxOk m_txOkCallback
transmit ok callback
void SetType(BlockAckType type)
Set the block ACK type.
uint16_t GetStartingSequence(void) const
Return the starting squence number.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
void RemoveFromRetryQueue(Mac48Address address, uint8_t tid, uint16_t seq)
Remove items from retransmission queue.
void SetTxFailedCallback(TxFailed callback)
Ptr< Packet > ScheduleBlockAckReqIfNeeded(Mac48Address recipient, uint8_t tid)
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
WifiMacHeader hdr
header
bool AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid) const
Checks if the packet already exists in the retransmit queue or not if it does then it doesn't add it ...
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:1375
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
void SetQueue(const Ptr< WifiMacQueue > queue)
uint32_t GetNRetryNeededPackets(Mac48Address recipient, uint8_t tid) const
uint32_t GetNextPacketSize(void) const
void SetBlockAckType(BlockAckType bAckType)
void SetWifiRemoteStationManager(const Ptr< WifiRemoteStationManager > manager)
Set up WifiRemoteStationManager associated with this BlockAckManager.
uint16_t GetSeqNumOfNextRetryPacket(Mac48Address recipient, uint8_t tid) const
void NotifyAgreementUnsuccessful(Mac48Address recipient, uint8_t tid)
static TypeId GetTypeId(void)
Get the type ID.
void InsertInRetryQueue(PacketQueueI item)
bool HasOtherFragments(uint16_t sequenceNumber) const
std::string GetUniqueName(void) const
Definition: wifi-mode.cc:450
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:190
Ptr< MacTxMiddle > m_txMiddle
the MacTxMiddle
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)
Set block destination callback.
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
uint8_t GetTid(void) const
Return the Traffic ID (TID).
void SetState(State state)
Set the current state.
void SetTxOkCallback(TxOk callback)
bool HasBar(Bar &bar)
Returns true if the BAR is scheduled.
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
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.
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
bool RemovePacket(uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
Remove a packet after you peek in the queue and get it.
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
block ack inactivity timeout callback
QosAckPolicy
ACK policy for QoS frames.
bool IsBasic(void) const
Check if the current ACK policy is basic (i.e.
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
an EUI-48 address
Definition: mac48-address.h:43
Ptr< const Packet > GetNextPacket(WifiMacHeader &hdr)
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:249
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity 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.
EventId m_inactivityEvent
inactivity event
bool NeedBarRetransmission(uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
This function returns true if the lifetime of the packets a BAR refers to didn'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
unblock packets callback
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
uint32_t GetNBufferedPackets(Mac48Address recipient, uint8_t tid) const
std::list< Bar > m_bars
list of BARs
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 SetTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set the MacTxMiddle.
void SetBlockAckThreshold(uint8_t nPackets)
Implement the header for management frames of type add block ack response.
Definition: mgt-headers.h:890
void CompleteAmpduExchange(Mac48Address recipient, uint8_t tid)
BlockAckType m_blockAckType
bock ack type
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:269
State
Represents the state for this agreement.
void SetImmediateBlockAck(void)
Set Block ACK policy to immediate ACK.
Time m_maxDelay
maximum delay
void SetTimeout(uint16_t timeout)
Set timeout.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1009
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
void ReportAmpduTxStatus(Mac48Address address, uint8_t tid, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
A base class which provides memory management and object aggregation.
Definition: object.h:87
tuple address
Definition: first.py:37
Manages all block ack agreements for an originator station.
Headers for Block ack request.
Definition: ctrl-headers.h:50
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
TxFailed m_txFailedCallback
transmit failed callback
Ptr< WifiRemoteStationManager > m_stationManager
the station manager
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.
a unique identifier for an interface.
Definition: type-id.h:58
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:914
bool IsMultiTid(void) const
Check if the current ACK policy has multiple TID.
Ptr< const Packet > packet
packet
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Implements the IEEE 802.11 MAC header.
void TearDownBlockAck(Mac48Address recipient, uint8_t tid)
Ptr< WifiMacQueue > m_queue
queue
void CompleteExchange(void)
Complete exchange function.
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.
void SetQosAckPolicy(QosAckPolicy policy)
Set the QoS ACK policy in the QoS control field.