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"
25 #include "ctrl-headers.h"
26 #include "mgt-headers.h"
27 #include "wifi-mac-queue.h"
28 #include "mac-tx-middle.h"
29 #include "qos-utils.h"
30 #include "wifi-tx-vector.h"
31 
32 namespace ns3 {
33 
34 NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
35 
37 {
38  NS_LOG_FUNCTION (this);
39 }
40 
41 Bar::Bar (Ptr<const WifiMacQueueItem> bar, uint8_t tid, bool skipIfNoDataQueued)
42  : bar (bar),
43  tid (tid),
44  skipIfNoDataQueued (skipIfNoDataQueued)
45 {
46  NS_LOG_FUNCTION (this << *bar << +tid << skipIfNoDataQueued);
47 }
48 
50 
51 TypeId
53 {
54  static TypeId tid = TypeId ("ns3::BlockAckManager")
55  .SetParent<Object> ()
56  .SetGroupName ("Wifi")
57  .AddConstructor<BlockAckManager> ()
58  .AddTraceSource ("AgreementState",
59  "The state of the ADDBA handshake",
61  "ns3::BlockAckManager::AgreementStateTracedCallback")
62  ;
63  return tid;
64 }
65 
67 {
68  NS_LOG_FUNCTION (this);
69  m_retryPackets = CreateObject<WifiMacQueue> ();
70  m_retryPackets->TraceConnectWithoutContext ("Expired", MakeCallback (&BlockAckManager::NotifyDiscardedMpdu, this));
71 }
72 
74 {
75  NS_LOG_FUNCTION (this);
76  m_queue = 0;
77  m_agreements.clear ();
78  m_retryPackets = 0;
79 }
80 
81 bool
82 BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
83 {
84  NS_LOG_FUNCTION (this << recipient << +tid);
85  return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
86 }
87 
88 bool
91 {
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.IsEstablished ();
101  return it->second.first.IsPending ();
103  return it->second.first.IsRejected ();
105  return it->second.first.IsNoReply ();
107  return it->second.first.IsReset ();
108  default:
109  NS_FATAL_ERROR ("Invalid state for block ack agreement");
110  }
111  }
112  return false;
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this << reqHdr << recipient);
119  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
120  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
121  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
122  /* For now we assume that originator doesn't use this field. Use of this field
123  is mandatory only for recipient */
124  agreement.SetBufferSize (reqHdr->GetBufferSize());
125  agreement.SetTimeout (reqHdr->GetTimeout ());
126  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
127  agreement.SetHtSupported (m_stationManager->GetHtSupported () && m_stationManager->GetHtSupported (recipient));
128  if (reqHdr->IsImmediateBlockAck ())
129  {
130  agreement.SetImmediateBlockAck ();
131  }
132  else
133  {
134  agreement.SetDelayedBlockAck ();
135  }
136  uint8_t tid = reqHdr->GetTid ();
138  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
139  PacketQueue queue;
140  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
141  if (ExistsAgreement (recipient, tid))
142  {
143  // Delete agreement if it exists and in RESET state
145  m_agreements.erase (key);
146  }
147  m_agreements.insert (std::make_pair (key, value));
148  m_blockPackets (recipient, reqHdr->GetTid ());
149 }
150 
151 void
153 {
154  NS_LOG_FUNCTION (this << recipient << +tid);
155  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
156  if (it != m_agreements.end ())
157  {
158  for (WifiMacQueue::ConstIterator i = m_retryPackets->begin (); i != m_retryPackets->end (); )
159  {
160  if ((*i)->GetHeader ().GetAddr1 () == recipient && (*i)->GetHeader ().GetQosTid () == tid)
161  {
162  i = m_retryPackets->Remove (i);
163  }
164  else
165  {
166  i++;
167  }
168  }
169  m_agreements.erase (it);
170  //remove scheduled BAR
171  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
172  {
173  if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
174  {
175  i = m_bars.erase (i);
176  }
177  else
178  {
179  i++;
180  }
181  }
182  }
183 }
184 
185 void
187  uint16_t startingSeq)
188 {
189  NS_LOG_FUNCTION (this << respHdr << recipient << startingSeq);
190  uint8_t tid = respHdr->GetTid ();
191  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
192  if (it != m_agreements.end ())
193  {
194  OriginatorBlockAckAgreement& agreement = it->second.first;
195  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
196  agreement.SetTimeout (respHdr->GetTimeout ());
197  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
198  agreement.SetStartingSequence (startingSeq);
199  agreement.InitTxWindow ();
200  if (respHdr->IsImmediateBlockAck ())
201  {
202  agreement.SetImmediateBlockAck ();
203  }
204  else
205  {
206  agreement.SetDelayedBlockAck ();
207  }
208  if (!it->second.first.IsEstablished ())
209  {
211  }
213  if (agreement.GetTimeout () != 0)
214  {
215  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
218  this,
219  recipient, tid);
220  }
221  }
222  m_unblockPackets (recipient, tid);
223 }
224 
227 {
228  return m_retryPackets;
229 }
230 
231 void
233 {
234  NS_LOG_FUNCTION (this << *mpdu);
235  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
236 
237  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
238  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
239 
240  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
241  NS_ASSERT (agreementIt != m_agreements.end ());
242 
243  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
244 
245  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
246  {
247  NS_LOG_DEBUG ("Got an old packet. Do nothing");
248  return;
249  }
250 
251  // store the packet and keep the list sorted in increasing order of sequence number
252  // with respect to the starting sequence number
253  PacketQueueI it = agreementIt->second.second.begin ();
254  while (it != agreementIt->second.second.end ())
255  {
256  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
257  {
258  NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
259  return;
260  }
261 
262  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
263 
264  if (mpduDist < dist ||
265  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
266  {
267  break;
268  }
269 
270  it++;
271  }
272  agreementIt->second.second.insert (it, mpdu);
273  agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
274 }
275 
278 {
280  // remove all expired MPDUs in the retransmission queue, so that Block Ack Requests
281  // (if needed) are scheduled
282  m_retryPackets->Remove (WifiMacQueue::EMPTY, true);
283 
284  auto nextBar = m_bars.begin ();
285 
286  while (nextBar != m_bars.end ())
287  {
288  if (nextBar->bar->GetHeader ().IsBlockAckReq ())
289  {
290  Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
291  AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
292  if (it == m_agreements.end ())
293  {
294  // BA agreement was torn down; remove this BAR and continue
295  nextBar = m_bars.erase (nextBar);
296  continue;
297  }
298  if (nextBar->skipIfNoDataQueued
299  && m_retryPackets->PeekByTidAndAddress (nextBar->tid, recipient) == m_retryPackets->end ()
300  && m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == m_queue->end ())
301  {
302  // skip this BAR as there is no data queued
303  nextBar++;
304  continue;
305  }
306  // remove expired outstanding MPDUs and update the starting sequence number
307  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
308  {
309  if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= Simulator::Now ())
310  {
311  // MPDU expired
312  it->second.first.NotifyDiscardedMpdu (*mpduIt);
313  mpduIt = it->second.second.erase (mpduIt);
314  }
315  else
316  {
317  mpduIt++;
318  }
319  }
320  // update BAR if the starting sequence number changed
321  CtrlBAckRequestHeader reqHdr;
322  nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
323  if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
324  {
325  reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
326  Ptr<Packet> packet = Create<Packet> ();
327  packet->AddHeader (reqHdr);
328  nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
329  }
330  }
331 
332  bar = nextBar->bar;
333  if (remove)
334  {
335  m_bars.erase (nextBar);
336  }
337  break;
338  }
339  return bar;
340 }
341 
342 bool
344 {
345  NS_LOG_FUNCTION (this);
346  return (!m_retryPackets->IsEmpty () || GetBar (false) != 0);
347 }
348 
349 uint32_t
351 {
352  NS_LOG_FUNCTION (this << recipient << +tid);
353  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
354  if (it == m_agreements.end ())
355  {
356  return 0;
357  }
358  uint32_t nPackets = 0;
359  PacketQueueCI queueIt = (*it).second.second.begin ();
360  while (queueIt != (*it).second.second.end ())
361  {
362  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
363  nPackets++;
364  /* a fragmented packet must be counted as one packet */
365  while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
366  {
367  queueIt++;
368  }
369  }
370  return nPackets;
371 }
372 
373 void
375 {
376  NS_LOG_FUNCTION (this << +nPackets);
377  m_blockAckThreshold = nPackets;
378 }
379 
380 void
382 {
383  NS_LOG_FUNCTION (this << manager);
384  m_stationManager = manager;
385 }
386 
387 void
389 {
390  NS_LOG_FUNCTION (this << *mpdu);
391  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
392 
393  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
394  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
396 
397  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
398  NS_ASSERT (it != m_agreements.end ());
399 
400  // remove the acknowledged frame from the queue of outstanding packets
401  PacketQueueI queueIt = it->second.second.begin ();
402  while (queueIt != it->second.second.end ())
403  {
404  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
405  {
406  queueIt = it->second.second.erase (queueIt);
407  }
408  else
409  {
410  queueIt++;
411  }
412  }
413 
414  it->second.first.NotifyAckedMpdu (mpdu);
415 }
416 
417 void
419 {
420  NS_LOG_FUNCTION (this << *mpdu);
421  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
422 
423  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
424  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
426 
427  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
428  NS_ASSERT (it != m_agreements.end ());
429 
430  // remove the frame from the queue of outstanding packets (it will be re-inserted
431  // if retransmitted)
432  PacketQueueI queueIt = it->second.second.begin ();
433  while (queueIt != it->second.second.end ())
434  {
435  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
436  {
437  queueIt = it->second.second.erase (queueIt);
438  }
439  else
440  {
441  queueIt++;
442  }
443  }
444 
445  // insert in the retransmission queue
446  InsertInRetryQueue (mpdu);
447 }
448 
449 void
450 BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
451 {
452  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << dataSnr << dataTxVector);
453  if (!blockAck->IsMultiTid ())
454  {
455  uint8_t tid = blockAck->GetTidInfo ();
457  {
458  bool foundFirstLost = false;
459  uint8_t nSuccessfulMpdus = 0;
460  uint8_t nFailedMpdus = 0;
461  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
462  PacketQueueI queueEnd = it->second.second.end ();
463 
464  if (it->second.first.m_inactivityEvent.IsRunning ())
465  {
466  /* Upon reception of a BlockAck frame, the inactivity timer at the
467  originator must be reset.
468  For more details see section 11.5.3 in IEEE802.11e standard */
469  it->second.first.m_inactivityEvent.Cancel ();
470  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
471  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
473  this,
474  recipient, tid);
475  }
476 
477  uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
478  uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
479 
480  if (blockAck->IsBasic ())
481  {
482  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
483  {
484  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
485  if (blockAck->IsFragmentReceived (currentSeq,
486  (*queueIt)->GetHeader ().GetFragmentNumber ()))
487  {
488  nSuccessfulMpdus++;
489  }
490  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
491  {
492  if (!foundFirstLost)
493  {
494  foundFirstLost = true;
495  RemoveOldPackets (recipient, tid, currentSeq);
496  }
497  nFailedMpdus++;
498  InsertInRetryQueue (*queueIt);
499  }
500  // in any case, this packet is no longer outstanding
501  queueIt = it->second.second.erase (queueIt);
502  }
503  // If all frames were acknowledged, move the transmit window past the last one
504  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
505  {
506  RemoveOldPackets (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
507  }
508  }
509  else if (blockAck->IsCompressed () || blockAck->IsExtendedCompressed ())
510  {
511  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
512  {
513  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
514  if (blockAck->IsPacketReceived (currentSeq))
515  {
516  it->second.first.NotifyAckedMpdu (*queueIt);
517  nSuccessfulMpdus++;
518  if (!m_txOkCallback.IsNull ())
519  {
520  m_txOkCallback ((*queueIt)->GetHeader ());
521  }
522  }
523  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
524  {
525  nFailedMpdus++;
526  if (!m_txFailedCallback.IsNull ())
527  {
528  m_txFailedCallback ((*queueIt)->GetHeader ());
529  }
530  InsertInRetryQueue (*queueIt);
531  }
532  // in any case, this packet is no longer outstanding
533  queueIt = it->second.second.erase (queueIt);
534  }
535  }
536  m_stationManager->ReportAmpduTxStatus (recipient, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr, dataTxVector);
537  }
538  }
539  else
540  {
541  //NOT SUPPORTED FOR NOW
542  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
543  }
544 }
545 
546 void
548 {
549  NS_LOG_FUNCTION (this << recipient << +tid);
551  {
552  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
553  for (auto& item : it->second.second)
554  {
555  // Queue previously transmitted packets that do not already exist in the retry queue.
556  InsertInRetryQueue (item);
557  }
558  // remove all packets from the queue of outstanding packets (they will be
559  // re-inserted if retransmitted)
560  it->second.second.clear ();
561  }
562 }
563 
564 void
566 {
567  NS_LOG_FUNCTION (this << recipient << +tid);
569  {
570  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
571  while (!it->second.second.empty ())
572  {
573  Ptr<WifiMacQueueItem> mpdu = it->second.second.front ();
574  if (it->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
575  {
576  // old packet
577  it->second.second.pop_front ();
578  }
579  else
580  {
581  NotifyDiscardedMpdu (mpdu);
582  }
583  }
584  }
585 }
586 
587 void
589 {
590  NS_LOG_FUNCTION (this << *mpdu);
591 
592  if (!mpdu->GetHeader ().IsQosData ())
593  {
594  NS_LOG_DEBUG ("Not a QoS Data frame");
595  return;
596  }
597 
598  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
599  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
601  {
602  NS_LOG_DEBUG ("No established Block Ack agreement");
603  return;
604  }
605 
606  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
607  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
608  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
609  {
610  NS_LOG_DEBUG ("Discarded an old frame");
611  return;
612  }
613 
614  // remove outstanding frames and frames in the retransmit queue with a sequence
615  // number less than or equal to the discarded MPDU
616  RemoveOldPackets (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
617  // actually advance the transmit window
618  it->second.first.NotifyDiscardedMpdu (mpdu);
619 
620  // schedule a BlockAckRequest
621  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
622  Ptr<Packet> bar = Create<Packet> ();
623  bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
624 
625  WifiMacHeader hdr;
627  hdr.SetAddr1 (recipient);
628  hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
629  hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
630  hdr.SetDsNotTo ();
631  hdr.SetDsNotFrom ();
632  hdr.SetNoRetry ();
633  hdr.SetNoMoreFragments ();
634 
635  ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
636 }
637 
640 {
641  NS_LOG_FUNCTION (this << recipient << +tid);
642  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
643  NS_ASSERT (it != m_agreements.end ());
644 
645  CtrlBAckRequestHeader reqHdr;
646  reqHdr.SetType ((*it).second.first.GetBlockAckReqType ());
647  reqHdr.SetTidInfo (tid);
648  reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
649  return reqHdr;
650 }
651 
652 void
654 {
655  NS_LOG_FUNCTION (this << *bar);
656  NS_ASSERT (bar->GetHeader ().IsBlockAckReq ());
657 
658  CtrlBAckRequestHeader reqHdr;
659  bar->GetPacket ()->PeekHeader (reqHdr);
660  uint8_t tid = reqHdr.GetTidInfo ();
661  Bar request (bar, tid, skipIfNoDataQueued);
662 
663  // if a BAR for the given agreement is present, replace it with the new one
664  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); i++)
665  {
666  if (i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
667  {
668  i = m_bars.erase (i);
669  m_bars.insert (i, request);
670  return;
671  }
672  }
673 
674  if (bar->GetHeader ().IsRetry ())
675  {
676  m_bars.push_front (request);
677  }
678  else
679  {
680  m_bars.push_back (request);
681  }
682 }
683 
684 void
686 {
687  NS_LOG_FUNCTION (this << recipient << +tid);
688  m_blockAckInactivityTimeout (recipient, tid, true);
689 }
690 
691 void
692 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
693 {
694  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
695  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
696  NS_ASSERT (it != m_agreements.end ());
697  if (!it->second.first.IsEstablished ())
698  {
700  }
701  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
702  it->second.first.SetStartingSequence (startingSeq);
703 }
704 
705 void
707 {
708  NS_LOG_FUNCTION (this << recipient << +tid);
709  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
710  NS_ASSERT (it != m_agreements.end ());
711  if (!it->second.first.IsRejected ())
712  {
714  }
715  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
716 }
717 
718 void
720 {
721  NS_LOG_FUNCTION (this << recipient << +tid);
722  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
723  NS_ASSERT (it != m_agreements.end ());
724  if (!it->second.first.IsNoReply ())
725  {
727  }
728  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
729  m_unblockPackets (recipient, tid);
730 }
731 
732 void
734 {
735  NS_LOG_FUNCTION (this << recipient << +tid);
736  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
737  NS_ASSERT (it != m_agreements.end ());
738  if (!it->second.first.IsReset ())
739  {
741  }
742  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
743 }
744 
745 void
747 {
748  NS_LOG_FUNCTION (this << queue);
749  m_queue = queue;
750 }
751 
752 bool
753 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
754 {
755  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
757  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
758  {
759  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
760  GetNBufferedPackets (recipient, tid);
761  if (packets >= m_blockAckThreshold)
762  {
763  NotifyAgreementEstablished (recipient, tid, startingSeq);
764  return true;
765  }
766  }
767  return false;
768 }
769 
771 {
773  {
774  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
775  NS_ASSERT (it != m_agreements.end ());
776 
777  // A BAR needs to be retransmitted if there is at least a non-expired outstanding MPDU
778  for (auto& mpdu : it->second.second)
779  {
780  if (mpdu->GetTimeStamp () + m_queue->GetMaxDelay () > Simulator::Now ())
781  {
782  return true;
783  }
784  }
785  }
786 
787  // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
788  // has destroyed the agreement, hence we get here and correctly return false
789  return false;
790 }
791 
792 void
794 {
795  RemoveFromRetryQueue (address, tid, seq, seq);
796 }
797 
798 void
799 BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
800 {
801  NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
802 
803  AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
804  NS_ASSERT (agreementIt != m_agreements.end ());
805 
806  /* remove retry packet iterators if they are present in retry queue */
807  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
808 
809  while (it != m_retryPackets->end ())
810  {
811  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
812 
813  if (agreementIt->second.first.GetDistance (itSeq) >= agreementIt->second.first.GetDistance (startSeq)
814  && agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (endSeq))
815  {
816  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
817  it = m_retryPackets->Remove (it);
818  it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
819  }
820  else
821  {
822  it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
823  }
824  }
825 }
826 
827 void
828 BlockAckManager::RemoveOldPackets (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
829 {
830  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
831 
832  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
833  NS_ASSERT (agreementIt != m_agreements.end ());
834  uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
835 
836  NS_ABORT_MSG_IF (agreementIt->second.first.GetDistance (startingSeq) >= SEQNO_SPACE_HALF_SIZE,
837  "The new starting sequence number is an old sequence number");
838 
839  if (startingSeq == currStartingSeq)
840  {
841  return;
842  }
843 
844  // remove packets that will become old from the retransmission queue
845  uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
846  RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
847 
848  // remove packets that will become old from the queue of outstanding packets
849  PacketQueueI it = agreementIt->second.second.begin ();
850  while (it != agreementIt->second.second.end ())
851  {
852  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
853 
854  if (agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (lastRemovedSeq))
855  {
856  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
857  it = agreementIt->second.second.erase (it);
858  }
859  else
860  {
861  it++;
862  }
863  }
864 }
865 
866 void
868 {
869  NS_LOG_FUNCTION (this << &callback);
870  m_blockAckInactivityTimeout = callback;
871 }
872 
873 void
875 {
876  NS_LOG_FUNCTION (this << &callback);
877  m_blockPackets = callback;
878 }
879 
880 void
882 {
883  NS_LOG_FUNCTION (this << &callback);
884  m_unblockPackets = callback;
885 }
886 
887 void
889 {
890  NS_LOG_FUNCTION (this << txMiddle);
891  m_txMiddle = txMiddle;
892 }
893 
894 void
896 {
897  m_txOkCallback = callback;
898 }
899 
900 void
902 {
903  m_txFailedCallback = callback;
904 }
905 
906 void
908 {
909  NS_LOG_INFO ("Adding to retry queue " << *mpdu);
910  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
911 
912  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
913  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
914 
915  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
916  NS_ASSERT (agreementIt != m_agreements.end ());
917 
918  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
919 
920  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
921  {
922  NS_LOG_DEBUG ("Got an old packet. Do nothing");
923  return;
924  }
925 
926  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
927 
928  while (it != m_retryPackets->end ())
929  {
930  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
931  {
932  NS_LOG_DEBUG ("Packet already in the retransmit queue");
933  return;
934  }
935 
936  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
937 
938  if (mpduDist < dist ||
939  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
940  {
941  break;
942  }
943 
944  it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
945  }
946  mpdu->GetHeader ().SetRetry ();
947  m_retryPackets->Insert (it, mpdu);
948 }
949 
950 uint16_t
952 {
953  uint16_t size = 0;
954  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
955  if (it != m_agreements.end ())
956  {
957  size = it->second.first.GetBufferSize ();
958  }
959  return size;
960 }
961 
963 BlockAckManager::GetBlockAckReqType (Mac48Address recipient, uint8_t tid) const
964 {
965  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
966  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
967  return it->second.first.GetBlockAckReqType ();
968 }
969 
971 BlockAckManager::GetBlockAckType (Mac48Address recipient, uint8_t tid) const
972 {
973  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
974  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
975  return it->second.first.GetBlockAckType ();
976 }
977 
978 uint16_t
980 {
981  uint16_t seqNum = 0;
982  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
983  if (it != m_agreements.end ())
984  {
985  seqNum = it->second.first.GetStartingSequence ();
986  }
987  return seqNum;
988 }
989 
990 } //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.
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:557
uint16_t GetTimeout(void) const
Return the timeout.
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent by the recipient.
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#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:1278
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
Maintains the state and information about transmitted MPDUs with Ack Policy set to Block Ack for an o...
void RemoveOldPackets(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
Remove packets from the retransmit queue and from the queue of outstanding packets that become old af...
std::list< Ptr< WifiMacQueueItem > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
#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)
uint32_t GetNBufferedPackets(Mac48Address recipient, uint8_t tid) const
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_agreementState
The trace source fired when a state transition occurred.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint8_t m_blockAckThreshold
block ack threshold
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, TID), a set of packets for whi...
void NotifyMissedAck(Ptr< WifiMacQueueItem > mpdu)
Invoked upon missed reception of an Ack frame after the transmission of a QoS data frame sent under a...
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:1003
void SetNoMoreFragments(void)
Un-set the More Fragment bit in the Frame Control Field.
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
#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
const uint16_t SEQNO_SPACE_HALF_SIZE
Size of the half the space of sequence numbers (used to determine old packets)
Definition: wifi-utils.h:218
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
uint16_t GetBufferSize(void) const
Return the buffer size.
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::iterator AgreementsI
typedef for an iterator for Agreements.
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent to the recipient.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
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:105
uint16_t GetBufferSize(void) const
Return the buffer size.
ns3::Time timeout
The different BlockAckRequest variants.
CtrlBAckRequestHeader GetBlockAckReqHeader(Mac48Address recipient, uint8_t tid) const
BlockAckRequest frame information.
uint16_t GetTimeout(void) const
Return the timeout.
bool IsExtendedCompressed(void) const
Check if the current BA policy is Extended Compressed Block Ack.
TxOk m_txOkCallback
transmit OK callback
bool IsBasic(void) const
Check if the current BA policy is Basic Block Ack.
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
void RemoveFromRetryQueue(Mac48Address address, uint8_t tid, uint16_t seq)
Remove an item from retransmission queue.
void SetTxFailedCallback(TxFailed callback)
uint8_t GetTid(void) const
Return the Traffic ID (TID).
void NotifyDiscardedMpdu(Ptr< const WifiMacQueueItem > mpdu)
Ptr< WifiMacQueue > GetRetransmitQueue(void)
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
const WifiMacHeader & GetHeader(void) const
Get the header stored in this item.
bool IsCompressed(void) const
Check if the current BA policy is Compressed Block Ack.
void NotifyAgreementEstablished(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
uint16_t GetTimeout(void) const
Return the timeout.
void SetQueue(const Ptr< WifiMacQueue > queue)
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
void SetWifiRemoteStationManager(const Ptr< WifiRemoteStationManager > manager)
Set up WifiRemoteStationManager associated with this BlockAckManager.
static TypeId GetTypeId(void)
Get the type ID.
bool GetHtSupported(void) const
Return whether the device has HT capability support enabled.
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
bool IsPacketReceived(uint16_t seq) const
Check if the packet with the given sequence number was acknowledged in this BlockAck response...
Headers for BlockAck response.
Definition: ctrl-headers.h:194
void NotifyAgreementRejected(Mac48Address recipient, uint8_t tid)
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
std::list< Ptr< WifiMacQueueItem > >::const_iterator PacketQueueCI
typedef for a const iterator for PacketQueue.
Ptr< MacTxMiddle > m_txMiddle
the MacTxMiddle
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
bool NeedBarRetransmission(uint8_t tid, Mac48Address recipient)
This function returns true if a block ack agreement is established with the given recipient for the g...
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
static const ConstIterator EMPTY
Invalid iterator to signal an empty queue.
void SetState(State state)
Set the current state.
void SetTxOkCallback(TxOk callback)
Ptr< const WifiMacQueueItem > GetBar(bool remove=true)
Returns the next BlockAckRequest to send, if any.
bool HasPackets(void)
Returns true if there are packets that need of retransmission or at least a BAR is scheduled...
uint16_t GetRecipientBufferSize(Mac48Address recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void InsertInRetryQueue(Ptr< WifiMacQueueItem > mpdu)
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
void SetNoRetry(void)
Un-set the Retry bit in the Frame Control field.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
address
Definition: first.py:44
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
BlockAck inactivity timeout callback.
void NotifyGotAck(Ptr< const WifiMacQueueItem > mpdu)
Invoked upon receipt of an Ack frame after the transmission of a QoS data frame sent under an establi...
void DiscardOutstandingMpdus(Mac48Address recipient, uint8_t tid)
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
void StorePacket(Ptr< WifiMacQueueItem > mpdu)
an EUI-48 address
Definition: mac48-address.h:43
std::list< Ptr< WifiMacQueueItem > > PacketQueue
typedef for a list of WifiMacQueueItem.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
Ptr< WifiMacQueue > m_retryPackets
This list contains all iterators to stored packets that need to be retransmitted. ...
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
State
Represents the state for this agreement.
void NotifyAgreementReset(Mac48Address recipient, uint8_t tid)
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
uint16_t GetOriginatorStartingSequence(Mac48Address recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
void NotifyGotBlockAck(const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
bool IsFragmentReceived(uint16_t seq, uint8_t frag) const
Check if the packet with the given sequence number and fragment number was acknowledged in this Block...
void SetDelayedBlockAck(void)
Set block ack policy to delayed Ack.
EventId m_inactivityEvent
inactivity event
uint8_t GetTid(void) const
Return the Traffic ID (TID).
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
Callback< void, Mac48Address, uint8_t > m_unblockPackets
unblock packets callback
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
The different BlockAck variants.
std::list< Bar > m_bars
list of BARs
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
Ptr< const WifiMacQueueItem > bar
BlockAckRequest.
void SetTxMiddle(const Ptr< MacTxMiddle > txMiddle)
Set the MacTxMiddle.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint8_t tid
TID.
void SetBlockAckThreshold(uint8_t nPackets)
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1135
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient, uint16_t startingSeq)
bool IsMultiTid(void) const
Check if the current BA policy is Multi-TID Block Ack.
void NotifyAgreementNoReply(Mac48Address recipient, uint8_t tid)
const uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:215
void SetImmediateBlockAck(void)
Set block ack policy to immediate Ack.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data...
void SetTimeout(uint16_t timeout)
Set timeout.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1305
A base class which provides memory management and object aggregation.
Definition: object.h:87
Manages all block ack agreements for an originator station.
Headers for BlockAckRequest.
Definition: ctrl-headers.h:42
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1386
TxFailed m_txFailedCallback
transmit failed callback
uint8_t GetFragmentNumber(void) const
Return the fragment number of the header.
Ptr< WifiRemoteStationManager > m_stationManager
the station manager
void SetBufferSize(uint16_t bufferSize)
Set buffer size.
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.
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
bool skipIfNoDataQueued
do not send if there is no data queued
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
void InitTxWindow(void)
Initialize the originator&#39;s transmit window by setting its size and starting sequence number equal to...
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
uint16_t GetSequenceControl(void) const
Return the raw Sequence Control field.
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
void ReportAmpduTxStatus(Mac48Address address, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...