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  : packet (packet),
34  hdr (hdr),
35  timestamp (tStamp)
36 {
37  NS_LOG_FUNCTION (this << packet << hdr << tStamp);
38 }
39 
41 {
42  NS_LOG_FUNCTION (this);
43 }
44 
45 Bar::Bar (Ptr<const Packet> bar, Mac48Address recipient, uint8_t tid, bool immediate)
46  : bar (bar),
47  recipient (recipient),
48  tid (tid),
49  immediate (immediate)
50 {
51  NS_LOG_FUNCTION (this << bar << recipient << +tid << immediate);
52 }
53 
55 
56 TypeId
58 {
59  static TypeId tid = TypeId ("ns3::BlockAckManager")
60  .SetParent<Object> ()
61  .SetGroupName ("Wifi")
62  .AddConstructor<BlockAckManager> ()
63  ;
64  return tid;
65 }
66 
68 {
69  NS_LOG_FUNCTION (this);
70 }
71 
73 {
74  NS_LOG_FUNCTION (this);
75  m_queue = 0;
76  m_agreements.clear ();
77  m_retryPackets.clear ();
78 }
79 
80 bool
81 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
82 {
83  NS_LOG_FUNCTION (this << recipient << +tid);
84  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
85 }
86 
87 bool
90 {
91  NS_LOG_FUNCTION (this << recipient << +tid << state);
92  AgreementsCI it;
93  it = m_agreements.find (std::make_pair (recipient, tid));
94  if (it != m_agreements.end ())
95  {
96  switch (state)
97  {
99  return it->second.first.IsInactive ();
101  return it->second.first.IsEstablished ();
103  return it->second.first.IsPending ();
105  return it->second.first.IsUnsuccessful ();
106  default:
107  NS_FATAL_ERROR ("Invalid state for block ack agreement");
108  }
109  }
110  return false;
111 }
112 
113 void
115 {
116  NS_LOG_FUNCTION (this << reqHdr << recipient);
117  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
118  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
119  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
120  /* For now we assume that originator doesn't use this field. Use of this field
121  is mandatory only for recipient */
122  agreement.SetBufferSize (64);
123  agreement.SetWinEnd ((agreement.GetStartingSequence () + agreement.GetBufferSize () - 1) % 4096);
124  agreement.SetTimeout (reqHdr->GetTimeout ());
125  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
126  agreement.SetHtSupported (m_stationManager->HasHtSupported ());
127  if (reqHdr->IsImmediateBlockAck ())
128  {
129  agreement.SetImmediateBlockAck ();
130  }
131  else
132  {
133  agreement.SetDelayedBlockAck ();
134  }
135  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
136  PacketQueue queue;
137  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
138  m_agreements.insert (std::make_pair (key, value));
139  m_blockPackets (recipient, reqHdr->GetTid ());
140 }
141 
142 void
144 {
145  NS_LOG_FUNCTION (this << recipient << +tid);
146  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
147  if (it != m_agreements.end ())
148  {
149  for (std::list<PacketQueueI>::const_iterator i = m_retryPackets.begin (); i != m_retryPackets.end (); )
150  {
151  if ((*i)->hdr.GetAddr1 () == recipient && (*i)->hdr.GetQosTid () == tid)
152  {
153  i = m_retryPackets.erase (i);
154  }
155  else
156  {
157  i++;
158  }
159  }
160  m_agreements.erase (it);
161  //remove scheduled bar
162  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
163  {
164  if (i->recipient == recipient && i->tid == tid)
165  {
166  i = m_bars.erase (i);
167  }
168  else
169  {
170  i++;
171  }
172  }
173  }
174 }
175 
176 void
178 {
179  NS_LOG_FUNCTION (this << respHdr << recipient);
180  uint8_t tid = respHdr->GetTid ();
181  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
182  if (it != m_agreements.end ())
183  {
184  OriginatorBlockAckAgreement& agreement = it->second.first;
185  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
186  agreement.SetTimeout (respHdr->GetTimeout ());
187  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
188  if (respHdr->IsImmediateBlockAck ())
189  {
190  agreement.SetImmediateBlockAck ();
191  }
192  else
193  {
194  agreement.SetDelayedBlockAck ();
195  }
197  if (agreement.GetTimeout () != 0)
198  {
199  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
200  agreement.m_inactivityEvent = Simulator::Schedule (timeout,
202  this,
203  recipient, tid);
204  }
205  }
206  m_unblockPackets (recipient, tid);
207 }
208 
209 void
211 {
212  NS_LOG_FUNCTION (this << packet << hdr << tStamp);
213  NS_ASSERT (hdr.IsQosData ());
214 
215  uint8_t tid = hdr.GetQosTid ();
216  Mac48Address recipient = hdr.GetAddr1 ();
217 
218  Item item (packet, hdr, tStamp);
219  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
220  NS_ASSERT (it != m_agreements.end ());
221  PacketQueueI queueIt = it->second.second.begin ();
222  for (; queueIt != it->second.second.end (); )
223  {
224  if (((hdr.GetSequenceNumber () - queueIt->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
225  {
226  queueIt = it->second.second.insert (queueIt, item);
227  break;
228  }
229  else
230  {
231  queueIt++;
232  }
233  }
234  if (queueIt == it->second.second.end ())
235  {
236  it->second.second.push_back (item);
237  }
238 }
239 
240 void
242 {
243  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
244  NS_ASSERT (it != m_agreements.end ());
245  OriginatorBlockAckAgreement &agreement = (*it).second.first;
246  agreement.CompleteExchange ();
247 }
248 
251 {
252  NS_LOG_FUNCTION (this << &hdr);
253  Ptr<const Packet> packet = 0;
254  uint8_t tid;
255  Mac48Address recipient;
256  CleanupBuffers ();
257  if (!m_retryPackets.empty ())
258  {
259  NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets.size ());
260  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
261  while (it != m_retryPackets.end ())
262  {
263  if ((*it)->hdr.IsQosData ())
264  {
265  tid = (*it)->hdr.GetQosTid ();
266  }
267  else
268  {
269  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
270  }
271  recipient = (*it)->hdr.GetAddr1 ();
272  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
273  NS_ASSERT (agreement != m_agreements.end ());
274  if (removePacket)
275  {
276  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
277  {
278  //Standard says the originator should not send a packet with seqnum < winstart
279  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
280  agreement->second.second.erase ((*it));
281  it = m_retryPackets.erase (it);
282  continue;
283  }
284  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
285  {
286  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
287  }
288  }
289  packet = (*it)->packet->Copy ();
290  hdr = (*it)->hdr;
291  hdr.SetRetry ();
292  if (hdr.IsQosData ())
293  {
294  tid = hdr.GetQosTid ();
295  }
296  else
297  {
298  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
299  }
300  recipient = hdr.GetAddr1 ();
301  if (!agreement->second.first.IsHtSupported ()
303  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
304  {
306  }
307  else
308  {
309  /* From section 9.10.3 in IEEE802.11e standard:
310  * In order to improve efficiency, originators using the Block Ack facility
311  * may send MPDU frames with the Ack Policy subfield in QoS control frames
312  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
313  * When there are sufficient number of MPDUs, the originator may switch back to
314  * the use of Block Ack.
315  */
317  if (removePacket)
318  {
319  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
320  i->second.second.erase (*it);
321  }
322  }
323  if (removePacket)
324  {
325  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
326  it = m_retryPackets.erase (it);
327  NS_LOG_DEBUG ("Removed one packet, retry buffer size = " << m_retryPackets.size ());
328  }
329  break;
330  }
331  }
332  return packet;
333 }
334 
337 {
338  NS_LOG_FUNCTION (this);
339  Ptr<const Packet> packet = 0;
340  CleanupBuffers ();
341  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
342  NS_ASSERT (agreement != m_agreements.end ());
343  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
344  for (; it != m_retryPackets.end (); it++)
345  {
346  if (!(*it)->hdr.IsQosData ())
347  {
348  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
349  }
350  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
351  {
352  if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
353  {
354  //standard says the originator should not send a packet with seqnum < winstart
355  NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
356  agreement->second.second.erase ((*it));
357  it = m_retryPackets.erase (it);
358  it--;
359  continue;
360  }
361  else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
362  {
363  agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
364  }
365  packet = (*it)->packet->Copy ();
366  hdr = (*it)->hdr;
367  hdr.SetRetry ();
368  *tstamp = (*it)->timestamp;
369  NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
370  Mac48Address recipient = hdr.GetAddr1 ();
371  if (!agreement->second.first.IsHtSupported ()
373  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
374  {
376  }
377  else
378  {
379  /* From section 9.10.3 in IEEE802.11e standard:
380  * In order to improve efficiency, originators using the Block Ack facility
381  * may send MPDU frames with the Ack Policy subfield in QoS control frames
382  * set to Normal Ack if only a few MPDUs are available for transmission.[...]
383  * When there are sufficient number of MPDUs, the originator may switch back to
384  * the use of Block Ack.
385  */
387  }
388  NS_LOG_DEBUG ("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
389  return packet;
390  }
391  }
392  return packet;
393 }
394 
395 bool
396 BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
397 {
398 
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 && (*it)->hdr.GetSequenceNumber () == seqnumber)
407  {
408  WifiMacHeader hdr = (*it)->hdr;
409  uint8_t tid = hdr.GetQosTid ();
410  Mac48Address recipient = hdr.GetAddr1 ();
411 
412  AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
413  i->second.second.erase ((*it));
414 
415  m_retryPackets.erase (it);
416  NS_LOG_DEBUG ("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << +tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
417  return true;
418  }
419  }
420  return false;
421 }
422 
423 bool
425 {
426  NS_LOG_FUNCTION (this << &bar);
427  if (m_bars.size () > 0)
428  {
429  bar = m_bars.front ();
430  m_bars.pop_front ();
431  return true;
432  }
433  return false;
434 }
435 
436 bool
438 {
439  NS_LOG_FUNCTION (this);
440  return (m_retryPackets.size () > 0 || m_bars.size () > 0);
441 }
442 
443 uint32_t
445 {
446  NS_LOG_FUNCTION (this << recipient << +tid);
447  uint32_t nPackets = 0;
448  if (ExistsAgreement (recipient, tid))
449  {
450  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
451  PacketQueueCI queueIt = (*it).second.second.begin ();
452  uint16_t currentSeq = 0;
453  while (queueIt != (*it).second.second.end ())
454  {
455  currentSeq = (*queueIt).hdr.GetSequenceNumber ();
456  nPackets++;
457  /* a fragmented packet must be counted as one packet */
458  while (queueIt != (*it).second.second.end () && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
459  {
460  queueIt++;
461  }
462  }
463  return nPackets;
464  }
465  return 0;
466 }
467 
468 uint32_t
470 {
471  NS_LOG_FUNCTION (this << recipient << +tid);
472  uint32_t nPackets = 0;
473  uint16_t currentSeq = 0;
474  if (ExistsAgreement (recipient, tid))
475  {
476  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
477  while (it != m_retryPackets.end ())
478  {
479  if (!(*it)->hdr.IsQosData ())
480  {
481  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
482  }
483  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
484  {
485  currentSeq = (*it)->hdr.GetSequenceNumber ();
486  nPackets++;
487  /* a fragmented packet must be counted as one packet */
488  while (it != m_retryPackets.end () && (*it)->hdr.GetSequenceNumber () == currentSeq)
489  {
490  it++;
491  }
492  }
493  //go to next packet
494  else
495  {
496  it++;
497  }
498  }
499  }
500  return nPackets;
501 }
502 
503 void
505 {
506  NS_LOG_FUNCTION (this << +nPackets);
507  m_blockAckThreshold = nPackets;
508 }
509 
510 void
512 {
513  NS_LOG_FUNCTION (this << manager);
514  m_stationManager = manager;
515 }
516 
517 bool
518 BlockAckManager::AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid) const
519 {
520  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
521  while (it != m_retryPackets.end ())
522  {
523  NS_LOG_FUNCTION (this << (*it)->hdr.GetType ());
524  if (!(*it)->hdr.IsQosData ())
525  {
526  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
527  }
528  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
529  {
530  return true;
531  }
532  it++;
533  }
534  return false;
535 }
536 
537 void
538 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
539 {
540  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
541  uint16_t sequenceFirstLost = 0;
542  if (!blockAck->IsMultiTid ())
543  {
544  uint8_t tid = blockAck->GetTidInfo ();
546  {
547  bool foundFirstLost = false;
548  uint8_t nSuccessfulMpdus = 0;
549  uint8_t nFailedMpdus = 0;
550  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
551  PacketQueueI queueEnd = it->second.second.end ();
552 
553  if (it->second.first.m_inactivityEvent.IsRunning ())
554  {
555  /* Upon reception of a block ack frame, the inactivity timer at the
556  originator must be reset.
557  For more details see section 11.5.3 in IEEE802.11e standard */
558  it->second.first.m_inactivityEvent.Cancel ();
559  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
560  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
562  this,
563  recipient, tid);
564  }
565  if (blockAck->IsBasic ())
566  {
567  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
568  {
569  if (blockAck->IsFragmentReceived ((*queueIt).hdr.GetSequenceNumber (),
570  (*queueIt).hdr.GetFragmentNumber ()))
571  {
572  nSuccessfulMpdus++;
573  RemoveFromRetryQueue (recipient, tid, (*queueIt).hdr.GetSequenceNumber ());
574  queueIt = it->second.second.erase (queueIt);
575  }
576  else
577  {
578  if (!foundFirstLost)
579  {
580  foundFirstLost = true;
581  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
582  (*it).second.first.SetStartingSequence (sequenceFirstLost);
583  }
584  nFailedMpdus++;
585  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
586  {
587  InsertInRetryQueue (queueIt);
588  }
589  queueIt++;
590  }
591  }
592  }
593  else if (blockAck->IsCompressed ())
594  {
595  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
596  {
597  uint16_t currentSeq = (*queueIt).hdr.GetSequenceNumber ();
598  if (blockAck->IsPacketReceived (currentSeq))
599  {
600  while (queueIt != queueEnd
601  && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
602  {
603  nSuccessfulMpdus++;
604  if (!m_txOkCallback.IsNull ())
605  {
606  m_txOkCallback ((*queueIt).hdr);
607  }
608  RemoveFromRetryQueue (recipient, tid, currentSeq);
609  queueIt = it->second.second.erase (queueIt);
610  }
611  }
612  else
613  {
614  if (!foundFirstLost)
615  {
616  foundFirstLost = true;
617  sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
618  (*it).second.first.SetStartingSequence (sequenceFirstLost);
619  }
620  nFailedMpdus++;
621  if (!m_txFailedCallback.IsNull ())
622  {
623  m_txFailedCallback ((*queueIt).hdr);
624  }
625  if (!AlreadyExists ((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
626  {
627  InsertInRetryQueue (queueIt);
628  }
629  queueIt++;
630  }
631  }
632  }
633  m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
634  uint16_t newSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
635  if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
636  || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
637  {
638  it->second.first.CompleteExchange ();
639  }
640  }
641  }
642  else
643  {
644  //NOT SUPPORTED FOR NOW
645  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
646  }
647 }
648 
649 void
651 {
652  NS_LOG_FUNCTION (this << bAckType);
653  m_blockAckType = bAckType;
654 }
655 
658 {
659  /* This method checks if a BlockAckRequest frame should be send to the recipient station.
660  Number of packets under block ack is specified in OriginatorBlockAckAgreement object but sometimes
661  this number could be incorrect. In fact is possible that a block ack agreement exists for n
662  packets but some of these packets are dropped due to MSDU lifetime expiration.
663  */
664  NS_LOG_FUNCTION (this << recipient << +tid);
665  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
666  NS_ASSERT (it != m_agreements.end ());
667 
668  if ((*it).second.first.IsBlockAckRequestNeeded ()
669  || (GetNRetryNeededPackets (recipient, tid) == 0
670  && m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) == 0))
671  {
672  OriginatorBlockAckAgreement &agreement = (*it).second.first;
673  agreement.CompleteExchange ();
674 
675  CtrlBAckRequestHeader reqHdr;
677  {
678  reqHdr.SetType (m_blockAckType);
679  reqHdr.SetTidInfo (agreement.GetTid ());
680  reqHdr.SetStartingSequence (agreement.GetStartingSequence ());
681  }
683  {
684  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
685  }
686  else
687  {
688  NS_FATAL_ERROR ("Invalid block ack type.");
689  }
690  Ptr<Packet> bar = Create<Packet> ();
691  bar->AddHeader (reqHdr);
692  return bar;
693  }
694  return 0;
695 }
696 
697 void
699 {
700  NS_LOG_FUNCTION (this << recipient << +tid);
701  m_blockAckInactivityTimeout (recipient, tid, true);
702 }
703 
704 void
705 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
706 {
707  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
708  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
709  NS_ASSERT (it != m_agreements.end ());
710  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
711  it->second.first.SetStartingSequence (startingSeq);
712 }
713 
714 void
716 {
717  NS_LOG_FUNCTION (this << recipient << +tid);
718  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
719  NS_ASSERT (it != m_agreements.end ());
720  if (it != m_agreements.end ())
721  {
722  it->second.first.SetState (OriginatorBlockAckAgreement::UNSUCCESSFUL);
723  }
724 }
725 
726 void
727 BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy)
728 {
729  NS_LOG_FUNCTION (this << recipient << +tid << nextSeqNumber);
730  Ptr<Packet> bar = 0;
731  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
732  NS_ASSERT (it != m_agreements.end ());
733  uint16_t nextSeq;
734  if (GetNRetryNeededPackets (recipient, tid) > 0)
735  {
736  nextSeq = GetSeqNumOfNextRetryPacket (recipient, tid);
737  }
738  else
739  {
740  nextSeq = nextSeqNumber;
741  }
742  it->second.first.NotifyMpduTransmission (nextSeq);
743  if (policy == WifiMacHeader::BLOCK_ACK)
744  {
745  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
746  if (bar != 0)
747  {
748  Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
749  m_bars.push_back (request);
750  }
751  }
752 }
753 
754 void
756 {
757  NS_LOG_FUNCTION (this << queue);
758  m_queue = queue;
759 }
760 
761 bool
762 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
763 {
764  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
766  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::UNSUCCESSFUL) && ExistsAgreement (recipient, tid))
767  {
768  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient) +
769  GetNBufferedPackets (recipient, tid);
770  if (packets >= m_blockAckThreshold)
771  {
772  NotifyAgreementEstablished (recipient, tid, startingSeq);
773  return true;
774  }
775  }
776  return false;
777 }
778 
779 bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
780 {
781  //The standard says the BAR gets discarded when all MSDUs lifetime expires
782  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
783  NS_ASSERT (it != m_agreements.end ());
784  CleanupBuffers ();
785  if ((seqNumber + 63) < it->second.first.GetStartingSequence ())
786  {
787  return false;
788  }
789  else
790  {
791  return true;
792  }
793 }
794 
795 void
797 {
798  /* remove retry packet iterator if it's present in retry queue */
799  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
800  while (it != m_retryPackets.end ())
801  {
802  if ((*it)->hdr.GetAddr1 () == address
803  && (*it)->hdr.GetQosTid () == tid
804  && (*it)->hdr.GetSequenceNumber () == seq)
805  {
806  it = m_retryPackets.erase (it);
807  }
808  else
809  {
810  it++;
811  }
812  }
813 }
814 
815 void
817 {
818  NS_LOG_FUNCTION (this);
819  for (AgreementsI j = m_agreements.begin (); j != m_agreements.end (); j++)
820  {
821  if (j->second.second.empty ())
822  {
823  continue;
824  }
825  Time now = Simulator::Now ();
826  PacketQueueI end = j->second.second.begin ();
827  for (PacketQueueI i = j->second.second.begin (); i != j->second.second.end (); i++)
828  {
829  if (i->timestamp + m_maxDelay > now)
830  {
831  end = i;
832  break;
833  }
834  else
835  {
836  RemoveFromRetryQueue (j->second.first.GetPeer (),
837  j->second.first.GetTid (),
838  i->hdr.GetSequenceNumber ());
839  }
840  }
841  j->second.second.erase (j->second.second.begin (), end);
842  j->second.first.SetStartingSequence (end->hdr.GetSequenceNumber ());
843  }
844 }
845 
846 void
848 {
849  NS_LOG_FUNCTION (this << maxDelay);
850  m_maxDelay = maxDelay;
851 }
852 
853 void
855 {
856  NS_LOG_FUNCTION (this << &callback);
857  m_blockAckInactivityTimeout = callback;
858 }
859 
860 void
862 {
863  NS_LOG_FUNCTION (this << &callback);
864  m_blockPackets = callback;
865 }
866 
867 void
869 {
870  NS_LOG_FUNCTION (this << &callback);
871  m_unblockPackets = callback;
872 }
873 
874 void
876 {
877  NS_LOG_FUNCTION (this << txMiddle);
878  m_txMiddle = txMiddle;
879 }
880 
881 uint16_t
883 {
884  NS_LOG_FUNCTION (this << recipient << +tid);
885  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
886  while (it != m_retryPackets.end ())
887  {
888  if (!(*it)->hdr.IsQosData ())
889  {
890  NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data");
891  }
892  if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
893  {
894  return (*it)->hdr.GetSequenceNumber ();
895  }
896  it++;
897  }
898  return 4096;
899 }
900 
901 void
903 {
904  m_txOkCallback = callback;
905 }
906 
907 void
909 {
910  m_txFailedCallback = callback;
911 }
912 
913 void
915 {
916  NS_LOG_INFO ("Adding to retry queue " << (*item).hdr.GetSequenceNumber ());
917  if (m_retryPackets.size () == 0)
918  {
919  m_retryPackets.push_back (item);
920  }
921  else
922  {
923  for (std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin (); it != m_retryPackets.end (); )
924  {
925  if (((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
926  {
927  it = m_retryPackets.insert (it, item);
928  break;
929  }
930  else
931  {
932  it++;
933  if (it == m_retryPackets.end ())
934  {
935  m_retryPackets.push_back (item);
936  }
937  }
938  }
939  }
940 }
941 
942 } //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:983
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.
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:80
bool HasPackets(void) const
Returns true if there are packets that need of retransmission or at least a BAR is scheduled...
Ptr< const Packet > GetNextPacket(WifiMacHeader &hdr, bool removePacket)
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
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).
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
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)
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).
Item(Ptr< const Packet > packet, const WifiMacHeader &hdr, Time tStamp)
Constructor.
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
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:1115
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:1023
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.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Implements the IEEE 802.11 MAC header.
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.