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 "qos-utils.h"
29 #include "wifi-tx-vector.h"
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
34 
36 {
37  NS_LOG_FUNCTION (this);
38 }
39 
40 Bar::Bar (Ptr<const WifiMacQueueItem> bar, uint8_t tid, bool skipIfNoDataQueued)
41  : bar (bar),
42  tid (tid),
43  skipIfNoDataQueued (skipIfNoDataQueued)
44 {
45  NS_LOG_FUNCTION (this << *bar << +tid << skipIfNoDataQueued);
46 }
47 
49 
50 TypeId
52 {
53  static TypeId tid = TypeId ("ns3::BlockAckManager")
54  .SetParent<Object> ()
55  .SetGroupName ("Wifi")
56  .AddConstructor<BlockAckManager> ()
57  .AddTraceSource ("AgreementState",
58  "The state of the ADDBA handshake",
60  "ns3::BlockAckManager::AgreementStateTracedCallback")
61  ;
62  return tid;
63 }
64 
66 {
67  NS_LOG_FUNCTION (this);
68  m_retryPackets = CreateObject<WifiMacQueue> ();
69  m_retryPackets->TraceConnectWithoutContext ("Expired", MakeCallback (&BlockAckManager::NotifyDiscardedMpdu, this));
70 }
71 
73 {
74  NS_LOG_FUNCTION (this);
75  m_queue = 0;
76  m_agreements.clear ();
77  m_retryPackets = 0;
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  AgreementsCI it;
92  it = m_agreements.find (std::make_pair (recipient, tid));
93  if (it != m_agreements.end ())
94  {
95  switch (state)
96  {
98  return it->second.first.IsEstablished ();
100  return it->second.first.IsPending ();
102  return it->second.first.IsRejected ();
104  return it->second.first.IsNoReply ();
106  return it->second.first.IsReset ();
107  default:
108  NS_FATAL_ERROR ("Invalid state for block ack agreement");
109  }
110  }
111  return false;
112 }
113 
114 void
116 {
117  NS_LOG_FUNCTION (this << reqHdr << recipient);
118  std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
119  OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
120  agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
121  /* For now we assume that originator doesn't use this field. Use of this field
122  is mandatory only for recipient */
123  agreement.SetBufferSize (reqHdr->GetBufferSize());
124  agreement.SetTimeout (reqHdr->GetTimeout ());
125  agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
126  agreement.SetHtSupported (m_stationManager->GetHtSupported () && m_stationManager->GetHtSupported (recipient));
127  if (reqHdr->IsImmediateBlockAck ())
128  {
129  agreement.SetImmediateBlockAck ();
130  }
131  else
132  {
133  agreement.SetDelayedBlockAck ();
134  }
135  uint8_t tid = reqHdr->GetTid ();
137  agreement.SetState (OriginatorBlockAckAgreement::PENDING);
138  PacketQueue queue;
139  std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
140  if (ExistsAgreement (recipient, tid))
141  {
142  // Delete agreement if it exists and in RESET state
144  m_agreements.erase (key);
145  }
146  m_agreements.insert (std::make_pair (key, value));
147  m_blockPackets (recipient, reqHdr->GetTid ());
148 }
149 
150 void
152 {
153  NS_LOG_FUNCTION (this << recipient << +tid);
154  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
155  if (it != m_agreements.end ())
156  {
157  for (WifiMacQueue::ConstIterator i = m_retryPackets->begin (); i != m_retryPackets->end (); )
158  {
159  if ((*i)->GetHeader ().GetAddr1 () == recipient && (*i)->GetHeader ().GetQosTid () == tid)
160  {
161  i = m_retryPackets->Remove (i);
162  }
163  else
164  {
165  i++;
166  }
167  }
168  m_agreements.erase (it);
169  //remove scheduled BAR
170  for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
171  {
172  if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
173  {
174  i = m_bars.erase (i);
175  }
176  else
177  {
178  i++;
179  }
180  }
181  }
182 }
183 
184 void
186  uint16_t startingSeq)
187 {
188  NS_LOG_FUNCTION (this << respHdr << recipient << startingSeq);
189  uint8_t tid = respHdr->GetTid ();
190  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
191  if (it != m_agreements.end ())
192  {
193  OriginatorBlockAckAgreement& agreement = it->second.first;
194  agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
195  agreement.SetTimeout (respHdr->GetTimeout ());
196  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
197  agreement.SetStartingSequence (startingSeq);
198  agreement.InitTxWindow ();
199  if (respHdr->IsImmediateBlockAck ())
200  {
201  agreement.SetImmediateBlockAck ();
202  }
203  else
204  {
205  agreement.SetDelayedBlockAck ();
206  }
207  if (!it->second.first.IsEstablished ())
208  {
210  }
212  if (agreement.GetTimeout () != 0)
213  {
214  Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
217  this,
218  recipient, tid);
219  }
220  }
221  m_unblockPackets (recipient, tid);
222 }
223 
226 {
227  return m_retryPackets;
228 }
229 
230 void
232 {
233  NS_LOG_FUNCTION (this << *mpdu);
234  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
235 
236  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
237  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
238 
239  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
240  NS_ASSERT (agreementIt != m_agreements.end ());
241 
242  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
243 
244  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
245  {
246  NS_LOG_DEBUG ("Got an old packet. Do nothing");
247  return;
248  }
249 
250  // store the packet and keep the list sorted in increasing order of sequence number
251  // with respect to the starting sequence number
252  PacketQueueI it = agreementIt->second.second.begin ();
253  while (it != agreementIt->second.second.end ())
254  {
255  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
256  {
257  NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
258  return;
259  }
260 
261  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
262 
263  if (mpduDist < dist ||
264  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
265  {
266  break;
267  }
268 
269  it++;
270  }
271  agreementIt->second.second.insert (it, mpdu);
272  agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
273 }
274 
276 BlockAckManager::GetBar (bool remove, uint8_t tid, Mac48Address address)
277 {
279  // remove all expired MPDUs in the retransmission queue, so that Block Ack Requests
280  // (if needed) are scheduled
281  m_retryPackets->Remove (WifiMacQueue::EMPTY, true);
282 
283  auto nextBar = m_bars.begin ();
284 
285  while (nextBar != m_bars.end ())
286  {
287  Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
288 
289  if (address != Mac48Address::GetBroadcast () && tid != 8
290  && (!nextBar->bar->GetHeader ().IsBlockAckReq ()
291  || address != recipient || tid != nextBar->tid))
292  {
293  // we can only return a BAR addressed to the given station and for the given TID
294  nextBar++;
295  continue;
296  }
297  if (nextBar->bar->GetHeader ().IsBlockAckReq ())
298  {
299  AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
300  if (it == m_agreements.end ())
301  {
302  // BA agreement was torn down; remove this BAR and continue
303  nextBar = m_bars.erase (nextBar);
304  continue;
305  }
306  if (nextBar->skipIfNoDataQueued
307  && m_retryPackets->PeekByTidAndAddress (nextBar->tid, recipient) == m_retryPackets->end ()
308  && m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == m_queue->end ())
309  {
310  // skip this BAR as there is no data queued
311  nextBar++;
312  continue;
313  }
314  // remove expired outstanding MPDUs and update the starting sequence number
315  for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
316  {
317  if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= Simulator::Now ())
318  {
319  // MPDU expired
320  it->second.first.NotifyDiscardedMpdu (*mpduIt);
321  mpduIt = it->second.second.erase (mpduIt);
322  }
323  else
324  {
325  mpduIt++;
326  }
327  }
328  // update BAR if the starting sequence number changed
329  CtrlBAckRequestHeader reqHdr;
330  nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
331  if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
332  {
333  reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
334  Ptr<Packet> packet = Create<Packet> ();
335  packet->AddHeader (reqHdr);
336  nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
337  }
338  }
339 
340  bar = nextBar->bar;
341  if (remove)
342  {
343  m_bars.erase (nextBar);
344  }
345  break;
346  }
347  return bar;
348 }
349 
350 bool
352 {
353  NS_LOG_FUNCTION (this);
354  return (!m_retryPackets->IsEmpty () || GetBar (false) != 0);
355 }
356 
357 uint32_t
359 {
360  NS_LOG_FUNCTION (this << recipient << +tid);
361  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
362  if (it == m_agreements.end ())
363  {
364  return 0;
365  }
366  uint32_t nPackets = 0;
367  PacketQueueCI queueIt = (*it).second.second.begin ();
368  while (queueIt != (*it).second.second.end ())
369  {
370  uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
371  nPackets++;
372  /* a fragmented packet must be counted as one packet */
373  while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
374  {
375  queueIt++;
376  }
377  }
378  return nPackets;
379 }
380 
381 void
383 {
384  NS_LOG_FUNCTION (this << +nPackets);
385  m_blockAckThreshold = nPackets;
386 }
387 
388 void
390 {
391  NS_LOG_FUNCTION (this << manager);
392  m_stationManager = manager;
393 }
394 
395 void
397 {
398  NS_LOG_FUNCTION (this << *mpdu);
399  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
400 
401  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
402  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
404 
405  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
406  NS_ASSERT (it != m_agreements.end ());
407 
408  // remove the acknowledged frame from the queue of outstanding packets
409  PacketQueueI queueIt = it->second.second.begin ();
410  while (queueIt != it->second.second.end ())
411  {
412  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
413  {
414  queueIt = it->second.second.erase (queueIt);
415  }
416  else
417  {
418  queueIt++;
419  }
420  }
421 
422  it->second.first.NotifyAckedMpdu (mpdu);
423 }
424 
425 void
427 {
428  NS_LOG_FUNCTION (this << *mpdu);
429  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
430 
431  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
432  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
434 
435  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
436  NS_ASSERT (it != m_agreements.end ());
437 
438  // remove the frame from the queue of outstanding packets (it will be re-inserted
439  // if retransmitted)
440  PacketQueueI queueIt = it->second.second.begin ();
441  while (queueIt != it->second.second.end ())
442  {
443  if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
444  {
445  queueIt = it->second.second.erase (queueIt);
446  }
447  else
448  {
449  queueIt++;
450  }
451  }
452 
453  // insert in the retransmission queue
454  InsertInRetryQueue (mpdu);
455 }
456 
457 void
459  const std::set<uint8_t>& tids, double rxSnr, double dataSnr,
460  const WifiTxVector& dataTxVector, size_t index)
461 {
462  NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << dataSnr << dataTxVector << index);
463  if (!blockAck.IsMultiTid ())
464  {
465  uint8_t tid = blockAck.GetTidInfo (index);
466  // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
467  // use the TID passed by the caller.
468  if (tid == 14)
469  {
470  NS_ASSERT (blockAck.GetAckType (index) && tids.size () == 1);
471  tid = *tids.begin ();
472  }
474  {
475  bool foundFirstLost = false;
476  uint16_t nSuccessfulMpdus = 0;
477  uint16_t nFailedMpdus = 0;
478  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
479  PacketQueueI queueEnd = it->second.second.end ();
480 
481  if (it->second.first.m_inactivityEvent.IsRunning ())
482  {
483  /* Upon reception of a BlockAck frame, the inactivity timer at the
484  originator must be reset.
485  For more details see section 11.5.3 in IEEE802.11e standard */
486  it->second.first.m_inactivityEvent.Cancel ();
487  Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
488  it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
490  this,
491  recipient, tid);
492  }
493 
494  uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
495  uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
496 
497  if (blockAck.IsBasic ())
498  {
499  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
500  {
501  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
502  if (blockAck.IsFragmentReceived (currentSeq,
503  (*queueIt)->GetHeader ().GetFragmentNumber ()))
504  {
505  nSuccessfulMpdus++;
506  }
507  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
508  {
509  if (!foundFirstLost)
510  {
511  foundFirstLost = true;
512  RemoveOldPackets (recipient, tid, currentSeq);
513  }
514  nFailedMpdus++;
515  InsertInRetryQueue (*queueIt);
516  }
517  // in any case, this packet is no longer outstanding
518  queueIt = it->second.second.erase (queueIt);
519  }
520  // If all frames were acknowledged, move the transmit window past the last one
521  if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
522  {
523  RemoveOldPackets (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
524  }
525  }
526  else if (blockAck.IsCompressed () || blockAck.IsExtendedCompressed () || blockAck.IsMultiSta ())
527  {
528  for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
529  {
530  currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
531  if (blockAck.IsPacketReceived (currentSeq, index))
532  {
533  it->second.first.NotifyAckedMpdu (*queueIt);
534  nSuccessfulMpdus++;
535  if (!m_txOkCallback.IsNull ())
536  {
537  m_txOkCallback (*queueIt);
538  }
539  }
540  else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
541  {
542  nFailedMpdus++;
543  if (!m_txFailedCallback.IsNull ())
544  {
545  m_txFailedCallback (*queueIt);
546  }
547  InsertInRetryQueue (*queueIt);
548  }
549  // in any case, this packet is no longer outstanding
550  queueIt = it->second.second.erase (queueIt);
551  }
552  }
553  m_stationManager->ReportAmpduTxStatus (recipient, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr, dataTxVector);
554  }
555  }
556  else
557  {
558  //NOT SUPPORTED FOR NOW
559  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
560  }
561 }
562 
563 void
565 {
566  NS_LOG_FUNCTION (this << recipient << +tid);
568  {
569  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
570  for (auto& item : it->second.second)
571  {
572  // Queue previously transmitted packets that do not already exist in the retry queue.
573  InsertInRetryQueue (item);
574  }
575  // remove all packets from the queue of outstanding packets (they will be
576  // re-inserted if retransmitted)
577  it->second.second.clear ();
578  }
579 }
580 
581 void
583 {
584  NS_LOG_FUNCTION (this << recipient << +tid);
586  {
587  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
588  while (!it->second.second.empty ())
589  {
590  Ptr<WifiMacQueueItem> mpdu = it->second.second.front ();
591  if (it->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
592  {
593  // old packet
594  it->second.second.pop_front ();
595  }
596  else
597  {
598  NotifyDiscardedMpdu (mpdu);
599  }
600  }
601  }
602 }
603 
604 void
606 {
607  NS_LOG_FUNCTION (this << *mpdu);
608 
609  if (!mpdu->GetHeader ().IsQosData ())
610  {
611  NS_LOG_DEBUG ("Not a QoS Data frame");
612  return;
613  }
614 
615  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
616  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
618  {
619  NS_LOG_DEBUG ("No established Block Ack agreement");
620  return;
621  }
622 
623  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
624  uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
625  if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
626  {
627  NS_LOG_DEBUG ("Discarded an old frame");
628  return;
629  }
630 
631  // remove outstanding frames and frames in the retransmit queue with a sequence
632  // number less than or equal to the discarded MPDU
633  RemoveOldPackets (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
634  // actually advance the transmit window
635  it->second.first.NotifyDiscardedMpdu (mpdu);
636 
637  // schedule a BlockAckRequest
638  NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
639  Ptr<Packet> bar = Create<Packet> ();
640  bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
641 
642  WifiMacHeader hdr;
644  hdr.SetAddr1 (recipient);
645  hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
646  hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
647  hdr.SetDsNotTo ();
648  hdr.SetDsNotFrom ();
649  hdr.SetNoRetry ();
650  hdr.SetNoMoreFragments ();
651 
652  ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
653 }
654 
657 {
658  NS_LOG_FUNCTION (this << recipient << +tid);
659  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
660  NS_ASSERT (it != m_agreements.end ());
661 
662  CtrlBAckRequestHeader reqHdr;
663  reqHdr.SetType ((*it).second.first.GetBlockAckReqType ());
664  reqHdr.SetTidInfo (tid);
665  reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
666  return reqHdr;
667 }
668 
669 void
671 {
672  NS_LOG_FUNCTION (this << *bar);
673  NS_ASSERT (bar->GetHeader ().IsBlockAckReq () || bar->GetHeader ().IsTrigger ());
674 
675  uint8_t tid = 0;
676  if (bar->GetHeader ().IsBlockAckReq ())
677  {
678  CtrlBAckRequestHeader reqHdr;
679  bar->GetPacket ()->PeekHeader (reqHdr);
680  tid = reqHdr.GetTidInfo ();
681  }
682 #ifdef NS3_BUILD_PROFILE_DEBUG
683  else
684  {
685  CtrlTriggerHeader triggerHdr;
686  bar->GetPacket ()->PeekHeader (triggerHdr);
687  NS_ASSERT (triggerHdr.IsMuBar ());
688  }
689 #endif
690  Bar request (bar, tid, skipIfNoDataQueued);
691 
692  // if a BAR for the given agreement is present, replace it with the new one
693  std::list<Bar>::const_iterator i = m_bars.end ();
694 
695  if (bar->GetHeader ().IsBlockAckReq ())
696  {
697  for (i = m_bars.begin (); i != m_bars.end (); i++)
698  {
699  if (i->bar->GetHeader ().IsBlockAckReq ()
700  && i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
701  {
702  i = m_bars.erase (i);
703  break;
704  }
705  }
706  }
707 
708  if (bar->GetHeader ().IsRetry ())
709  {
710  m_bars.push_front (request);
711  }
712  else
713  {
714  m_bars.insert (i, request);
715  }
716 }
717 
718 void
720 {
721  NS_LOG_FUNCTION (this << recipient << +tid);
722  m_blockAckInactivityTimeout (recipient, tid, true);
723 }
724 
725 void
726 BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
727 {
728  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
729  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
730  NS_ASSERT (it != m_agreements.end ());
731  if (!it->second.first.IsEstablished ())
732  {
734  }
735  it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
736  it->second.first.SetStartingSequence (startingSeq);
737 }
738 
739 void
741 {
742  NS_LOG_FUNCTION (this << recipient << +tid);
743  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
744  NS_ASSERT (it != m_agreements.end ());
745  if (!it->second.first.IsRejected ())
746  {
748  }
749  it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
750 }
751 
752 void
754 {
755  NS_LOG_FUNCTION (this << recipient << +tid);
756  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
757  NS_ASSERT (it != m_agreements.end ());
758  if (!it->second.first.IsNoReply ())
759  {
761  }
762  it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
763  m_unblockPackets (recipient, tid);
764 }
765 
766 void
768 {
769  NS_LOG_FUNCTION (this << recipient << +tid);
770  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
771  NS_ASSERT (it != m_agreements.end ());
772  if (!it->second.first.IsReset ())
773  {
775  }
776  it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
777 }
778 
779 void
781 {
782  NS_LOG_FUNCTION (this << queue);
783  m_queue = queue;
784 }
785 
786 bool
787 BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
788 {
789  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
791  if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
792  {
793  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
794  GetNBufferedPackets (recipient, tid);
795  if (packets >= m_blockAckThreshold)
796  {
797  NotifyAgreementEstablished (recipient, tid, startingSeq);
798  return true;
799  }
800  }
801  return false;
802 }
803 
805 {
807  {
808  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
809  NS_ASSERT (it != m_agreements.end ());
810 
811  // A BAR needs to be retransmitted if there is at least a non-expired outstanding MPDU
812  for (auto& mpdu : it->second.second)
813  {
814  if (mpdu->GetTimeStamp () + m_queue->GetMaxDelay () > Simulator::Now ())
815  {
816  return true;
817  }
818  }
819  }
820 
821  // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
822  // has destroyed the agreement, hence we get here and correctly return false
823  return false;
824 }
825 
826 void
828 {
829  RemoveFromRetryQueue (address, tid, seq, seq);
830 }
831 
832 void
833 BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
834 {
835  NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
836 
837  AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
838  NS_ASSERT (agreementIt != m_agreements.end ());
839 
840  /* remove retry packet iterators if they are present in retry queue */
841  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
842 
843  while (it != m_retryPackets->end ())
844  {
845  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
846 
847  if (agreementIt->second.first.GetDistance (itSeq) >= agreementIt->second.first.GetDistance (startSeq)
848  && agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (endSeq))
849  {
850  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
851  it = m_retryPackets->Remove (it);
852  it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
853  }
854  else
855  {
856  it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
857  }
858  }
859 }
860 
861 void
862 BlockAckManager::RemoveOldPackets (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
863 {
864  NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
865 
866  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
867  NS_ASSERT (agreementIt != m_agreements.end ());
868  uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
869 
870  NS_ABORT_MSG_IF (agreementIt->second.first.GetDistance (startingSeq) >= SEQNO_SPACE_HALF_SIZE,
871  "The new starting sequence number is an old sequence number");
872 
873  if (startingSeq == currStartingSeq)
874  {
875  return;
876  }
877 
878  // remove packets that will become old from the retransmission queue
879  uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
880  RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
881 
882  // remove packets that will become old from the queue of outstanding packets
883  PacketQueueI it = agreementIt->second.second.begin ();
884  while (it != agreementIt->second.second.end ())
885  {
886  uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
887 
888  if (agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (lastRemovedSeq))
889  {
890  NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
891  it = agreementIt->second.second.erase (it);
892  }
893  else
894  {
895  it++;
896  }
897  }
898 }
899 
900 void
902 {
903  NS_LOG_FUNCTION (this << &callback);
904  m_blockAckInactivityTimeout = callback;
905 }
906 
907 void
909 {
910  NS_LOG_FUNCTION (this << &callback);
911  m_blockPackets = callback;
912 }
913 
914 void
916 {
917  NS_LOG_FUNCTION (this << &callback);
918  m_unblockPackets = callback;
919 }
920 
921 void
923 {
924  m_txOkCallback = callback;
925 }
926 
927 void
929 {
930  m_txFailedCallback = callback;
931 }
932 
933 void
935 {
936  NS_LOG_INFO ("Adding to retry queue " << *mpdu);
937  NS_ASSERT (mpdu->GetHeader ().IsQosData ());
938 
939  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
940  Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
941 
942  AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
943  NS_ASSERT (agreementIt != m_agreements.end ());
944 
945  uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
946 
947  if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
948  {
949  NS_LOG_DEBUG ("Got an old packet. Do nothing");
950  return;
951  }
952 
953  WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
954 
955  while (it != m_retryPackets->end ())
956  {
957  if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
958  {
959  NS_LOG_DEBUG ("Packet already in the retransmit queue");
960  return;
961  }
962 
963  uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
964 
965  if (mpduDist < dist ||
966  (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
967  {
968  break;
969  }
970 
971  it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
972  }
973  mpdu->GetHeader ().SetRetry ();
974  m_retryPackets->Insert (it, mpdu);
975 }
976 
977 uint16_t
979 {
980  uint16_t size = 0;
981  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
982  if (it != m_agreements.end ())
983  {
984  size = it->second.first.GetBufferSize ();
985  }
986  return size;
987 }
988 
990 BlockAckManager::GetBlockAckReqType (Mac48Address recipient, uint8_t tid) const
991 {
992  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
993  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
994  return it->second.first.GetBlockAckReqType ();
995 }
996 
998 BlockAckManager::GetBlockAckType (Mac48Address recipient, uint8_t tid) const
999 {
1000  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
1001  NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
1002  return it->second.first.GetBlockAckType ();
1003 }
1004 
1005 uint16_t
1007 {
1008  uint16_t seqNum = 0;
1009  AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
1010  if (it != m_agreements.end ())
1011  {
1012  seqNum = it->second.first.GetStartingSequence ();
1013  }
1014  return seqNum;
1015 }
1016 
1017 } //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.
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
Headers for Trigger frames.
Definition: ctrl-headers.h:885
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:990
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
void ReportAmpduTxStatus(Mac48Address address, uint16_t nSuccessfulMpdus, uint16_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...
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:225
#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:178
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.
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
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)
void NotifyGotBlockAck(const CtrlBAckResponseHeader &blockAck, Mac48Address recipient, const std::set< uint8_t > &tids, double rxSnr, double dataSnr, const WifiTxVector &dataTxVector, size_t index=0)
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.
static Mac48Address GetBroadcast(void)
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
Headers for BlockAck response.
Definition: ctrl-headers.h:201
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.
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)
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
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
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.
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)
bool IsMuBar(void) const
Check if this is a MU-BAR Trigger frame.
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 or MU-BAR Trigger Frame.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
uint8_t tid
TID (unused if MU-BAR)
void SetBlockAckThreshold(uint8_t nPackets)
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1122
#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:222
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.
bool IsPacketReceived(uint16_t seq, std::size_t index=0) const
Check if the packet with the given sequence number was acknowledged in this BlockAck response...
Headers for BlockAckRequest.
Definition: ctrl-headers.h:48
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< const WifiMacQueueItem > GetBar(bool remove=true, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast())
Returns the next BlockAckRequest or MU-BAR Trigger Frame to send, if any.
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 (unused if MU-BAR)
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.