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 "wifi-utils.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#include <optional>
31
32namespace ns3 {
33
34NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
35
37{
38 NS_LOG_FUNCTION (this);
39}
40
41Bar::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
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}
70
72{
73 NS_LOG_FUNCTION (this);
74}
75
76void
78{
79 NS_LOG_FUNCTION (this);
80 m_agreements.clear ();
81 m_bars.clear ();
82 m_queue = nullptr;
83}
84
85bool
86BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
87{
88 NS_LOG_FUNCTION (this << recipient << +tid);
89 return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
90}
91
92bool
95{
96 AgreementsCI it;
97 it = m_agreements.find (std::make_pair (recipient, tid));
98 if (it != m_agreements.end ())
99 {
100 switch (state)
101 {
103 return it->second.first.IsEstablished ();
105 return it->second.first.IsPending ();
107 return it->second.first.IsRejected ();
109 return it->second.first.IsNoReply ();
111 return it->second.first.IsReset ();
112 default:
113 NS_FATAL_ERROR ("Invalid state for block ack agreement");
114 }
115 }
116 return false;
117}
118
119void
120BlockAckManager::CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient, bool htSupported)
121{
122 NS_LOG_FUNCTION (this << reqHdr << recipient << htSupported);
123 std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
124 OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
125 agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
126 /* For now we assume that originator doesn't use this field. Use of this field
127 is mandatory only for recipient */
128 agreement.SetBufferSize (reqHdr->GetBufferSize());
129 agreement.SetTimeout (reqHdr->GetTimeout ());
130 agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
131 agreement.SetHtSupported (htSupported);
132 if (reqHdr->IsImmediateBlockAck ())
133 {
134 agreement.SetImmediateBlockAck ();
135 }
136 else
137 {
138 agreement.SetDelayedBlockAck ();
139 }
140 uint8_t tid = reqHdr->GetTid ();
143 PacketQueue queue;
144 std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
145 if (ExistsAgreement (recipient, tid))
146 {
147 // Delete agreement if it exists and in RESET state
149 m_agreements.erase (key);
150 }
151 m_agreements.insert (std::make_pair (key, value));
152 m_blockPackets (recipient, reqHdr->GetTid ());
153}
154
155void
157{
158 NS_LOG_FUNCTION (this << recipient << +tid);
159 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
160 if (it != m_agreements.end ())
161 {
162 m_agreements.erase (it);
163 //remove scheduled BAR
164 for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
165 {
166 if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
167 {
168 i = m_bars.erase (i);
169 }
170 else
171 {
172 i++;
173 }
174 }
175 }
176}
177
178void
180 uint16_t startingSeq)
181{
182 NS_LOG_FUNCTION (this << respHdr << recipient << startingSeq);
183 uint8_t tid = respHdr->GetTid ();
184 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
185 if (it != m_agreements.end ())
186 {
187 OriginatorBlockAckAgreement& agreement = it->second.first;
188 agreement.SetBufferSize (respHdr->GetBufferSize ());
189 agreement.SetTimeout (respHdr->GetTimeout ());
190 agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
191 agreement.SetStartingSequence (startingSeq);
192 agreement.InitTxWindow ();
193 if (respHdr->IsImmediateBlockAck ())
194 {
195 agreement.SetImmediateBlockAck ();
196 }
197 else
198 {
199 agreement.SetDelayedBlockAck ();
200 }
201 if (!it->second.first.IsEstablished ())
202 {
204 }
206 if (agreement.GetTimeout () != 0)
207 {
208 Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
211 this,
212 recipient, tid);
213 }
214 }
215 m_unblockPackets (recipient, tid);
216}
217
218void
220{
221 NS_LOG_FUNCTION (this << *mpdu);
222 NS_ASSERT (mpdu->GetHeader ().IsQosData ());
223
224 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
225 Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
226
227 AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
228 NS_ASSERT (agreementIt != m_agreements.end ());
229
230 uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
231
232 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
233 {
234 NS_LOG_DEBUG ("Got an old packet. Do nothing");
235 return;
236 }
237
238 // store the packet and keep the list sorted in increasing order of sequence number
239 // with respect to the starting sequence number
240 auto it = agreementIt->second.second.rbegin ();
241 while (it != agreementIt->second.second.rend ())
242 {
243 if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
244 {
245 NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
246 return;
247 }
248
249 uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
250
251 if (mpduDist > dist ||
252 (mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () > (*it)->GetHeader ().GetFragmentNumber ()))
253 {
254 break;
255 }
256
257 it++;
258 }
259 agreementIt->second.second.insert (it.base (), mpdu);
260 agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
261 mpdu->SetInFlight ();
262}
263
266{
267 Time now = Simulator::Now ();
269 // remove all expired MPDUs from the head of the MAC queue, so that
270 // BlockAckRequest frames (if needed) are scheduled
271 m_queue->IsEmpty ();
272
273 auto nextBar = m_bars.begin ();
274
275 while (nextBar != m_bars.end ())
276 {
277 Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
278
279 if (address != Mac48Address::GetBroadcast () && tid != 8
280 && (!nextBar->bar->GetHeader ().IsBlockAckReq ()
281 || address != recipient || tid != nextBar->tid))
282 {
283 // we can only return a BAR addressed to the given station and for the given TID
284 nextBar++;
285 continue;
286 }
287 if (nextBar->bar->GetHeader ().IsBlockAckReq ())
288 {
289 AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
290 if (it == m_agreements.end ())
291 {
292 // BA agreement was torn down; remove this BAR and continue
293 nextBar = m_bars.erase (nextBar);
294 continue;
295 }
296 if (nextBar->skipIfNoDataQueued
297 && m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == nullptr)
298 {
299 // skip this BAR as there is no data queued
300 nextBar++;
301 continue;
302 }
303 // remove expired outstanding MPDUs and update the starting sequence number
304 for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
305 {
306 if (!(*mpduIt)->IsQueued ())
307 {
308 // the MPDU is no longer in the EDCA queue
309 mpduIt = it->second.second.erase (mpduIt);
310 continue;
311 }
312
313 if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= now)
314 {
315 // MPDU expired
316 it->second.first.NotifyDiscardedMpdu (*mpduIt);
317 // Remove from the EDCA queue and fire the Expired trace source, but the
318 // consequent call to NotifyDiscardedMpdu does nothing (in particular,
319 // does not schedule a BAR) because we have advanced the transmit window
320 // and hence this MPDU became an old packet
321 m_queue->TtlExceeded (*mpduIt, now);
322 mpduIt = it->second.second.erase (mpduIt);
323 }
324 else
325 {
326 // MPDUs are typically in increasing order of remaining lifetime
327 break;
328 }
329 }
330 // update BAR if the starting sequence number changed
332 nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
333 if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
334 {
335 reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
336 Ptr<Packet> packet = Create<Packet> ();
337 packet->AddHeader (reqHdr);
338 nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
339 }
340 }
341
342 bar = nextBar->bar;
343 if (remove)
344 {
345 m_bars.erase (nextBar);
346 }
347 break;
348 }
349 return bar;
350}
351
354{
355 NS_LOG_FUNCTION (this << recipient << +tid);
356 AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
357 if (it == m_agreements.end ())
358 {
359 return 0;
360 }
361 return it->second.second.size ();
362}
363
364void
366{
367 NS_LOG_FUNCTION (this << +nPackets);
368 m_blockAckThreshold = nPackets;
369}
370
373 const AgreementsI& it, const Time& now)
374{
375 NS_LOG_FUNCTION (this << **mpduIt << +static_cast<uint8_t> (status));
376
377 if (!(*mpduIt)->IsQueued ())
378 {
379 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
380 // removed by another method), remove from the queue of in flight MPDUs
381 NS_LOG_DEBUG ("MPDU is not stored in the EDCA queue, drop MPDU");
382 return it->second.second.erase (mpduIt);
383 }
384
385 if (status == ACKNOWLEDGED)
386 {
387 // the MPDU has to be dequeued from the EDCA queue
388 m_queue->DequeueIfQueued (*mpduIt);
389 return it->second.second.erase (mpduIt);
390 }
391
392 WifiMacHeader& hdr = (*mpduIt)->GetHeader ();
393
394 NS_ASSERT (hdr.GetAddr1 () == it->first.first);
395 NS_ASSERT (hdr.IsQosData () && hdr.GetQosTid () == it->first.second);
396
397 if (it->second.first.GetDistance (hdr.GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
398 {
399 NS_LOG_DEBUG ("Old packet. Remove from the EDCA queue, too");
401 {
402 m_droppedOldMpduCallback (*mpduIt);
403 }
404 m_queue->Remove (*mpduIt, false);
405 return it->second.second.erase (mpduIt);
406 }
407
408 std::optional<PacketQueueI> prevIt;
409 if (mpduIt != it->second.second.begin ())
410 {
411 prevIt = std::prev (mpduIt);
412 }
413
414 if (m_queue->TtlExceeded (*mpduIt, now))
415 {
416 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
417 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
418 // which removed this MPDU (and possibly others) from the in flight queue as well
419 NS_LOG_DEBUG ("MSDU lifetime expired, drop MPDU");
420 return (prevIt.has_value () ? std::next (prevIt.value ()) : it->second.second.begin ());
421 }
422
423 if (status == STAY_INFLIGHT)
424 {
425 // the MPDU has to stay in flight, do nothing
426 return ++mpduIt;
427 }
428
429 NS_ASSERT (status == TO_RETRANSMIT);
430 (*mpduIt)->GetHeader ().SetRetry ();
431 (*mpduIt)->ResetInFlight (); // no longer in flight; will be if retransmitted
432
433 return it->second.second.erase (mpduIt);
434}
435
436void
438{
439 NS_LOG_FUNCTION (this << *mpdu);
440 NS_ASSERT (mpdu->GetHeader ().IsQosData ());
441
442 Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
443 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
445
446 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
447 NS_ASSERT (it != m_agreements.end ());
448
449 it->second.first.NotifyAckedMpdu (mpdu);
450
451 // remove the acknowledged frame from the queue of outstanding packets
452 for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); ++queueIt)
453 {
454 if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
455 {
457 break;
458 }
459 }
460}
461
462void
464{
465 NS_LOG_FUNCTION (this << *mpdu);
466 NS_ASSERT (mpdu->GetHeader ().IsQosData ());
467
468 Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
469 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
471
472 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
473 NS_ASSERT (it != m_agreements.end ());
474
475 // remove the frame from the queue of outstanding packets (it will be re-inserted
476 // if retransmitted)
477 for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); ++queueIt)
478 {
479 if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
480 {
482 break;
483 }
484 }
485}
486
487std::pair<uint16_t,uint16_t>
489 const std::set<uint8_t>& tids, size_t index)
490{
491 NS_LOG_FUNCTION (this << blockAck << recipient << index);
492 uint16_t nSuccessfulMpdus = 0;
493 uint16_t nFailedMpdus = 0;
494
495 NS_ABORT_MSG_IF (blockAck.IsBasic (), "Basic Block Ack is not supported");
496 NS_ABORT_MSG_IF (blockAck.IsMultiTid (), "Multi-TID Block Ack is not supported");
497
498 uint8_t tid = blockAck.GetTidInfo (index);
499 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
500 // use the TID passed by the caller.
501 if (tid == 14)
502 {
503 NS_ASSERT (blockAck.GetAckType (index) && tids.size () == 1);
504 tid = *tids.begin ();
505 }
507 {
508 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
509
510 if (it->second.first.m_inactivityEvent.IsRunning ())
511 {
512 /* Upon reception of a BlockAck frame, the inactivity timer at the
513 originator must be reset.
514 For more details see section 11.5.3 in IEEE802.11e standard */
515 it->second.first.m_inactivityEvent.Cancel ();
516 Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
517 it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
519 this,
520 recipient, tid);
521 }
522
523 NS_ASSERT (blockAck.IsCompressed () || blockAck.IsExtendedCompressed () || blockAck.IsMultiSta ());
524 Time now = Simulator::Now ();
525
526 for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); )
527 {
528 uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
529 if (blockAck.IsPacketReceived (currentSeq, index))
530 {
531 it->second.first.NotifyAckedMpdu (*queueIt);
532 nSuccessfulMpdus++;
533 if (!m_txOkCallback.IsNull ())
534 {
535 m_txOkCallback (*queueIt);
536 }
537 queueIt = HandleInFlightMpdu (queueIt, ACKNOWLEDGED, it, now);
538 }
539 else
540 {
541 nFailedMpdus++;
543 {
544 m_txFailedCallback (*queueIt);
545 }
546 queueIt = HandleInFlightMpdu (queueIt, TO_RETRANSMIT, it, now);
547 }
548 }
549 }
550 return {nSuccessfulMpdus, nFailedMpdus};
551}
552
553void
555{
556 NS_LOG_FUNCTION (this << recipient << +tid);
558 {
559 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
560 Time now = Simulator::Now ();
561
562 // remove all packets from the queue of outstanding packets (they will be
563 // re-inserted if retransmitted)
564 for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
565 {
566 mpduIt = HandleInFlightMpdu (mpduIt, TO_RETRANSMIT, it, now);
567 }
568 }
569}
570
571void
573{
574 NS_LOG_FUNCTION (this << *mpdu);
575
576 if (!mpdu->GetHeader ().IsQosData ())
577 {
578 NS_LOG_DEBUG ("Not a QoS Data frame");
579 return;
580 }
581
582 if (!mpdu->GetHeader ().IsRetry () && !mpdu->IsInFlight ())
583 {
584 NS_LOG_DEBUG ("This frame has never been transmitted");
585 return;
586 }
587
588 Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
589 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
591 {
592 NS_LOG_DEBUG ("No established Block Ack agreement");
593 return;
594 }
595
596 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
597 uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
598 if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
599 {
600 NS_LOG_DEBUG ("Discarded an old frame");
601 return;
602 }
603
604 // actually advance the transmit window
605 it->second.first.NotifyDiscardedMpdu (mpdu);
606
607 // remove old MPDUs from the EDCA queue and from the in flight queue
608 // (including the given MPDU which became old after advancing the transmit window)
609 for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
610 {
611 if (it->second.first.GetDistance ((*mpduIt)->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
612 {
613 NS_LOG_DEBUG ("Dropping old MPDU: " << **mpduIt);
614 m_queue->DequeueIfQueued (*mpduIt);
616 {
617 m_droppedOldMpduCallback (*mpduIt);
618 }
619 mpduIt = it->second.second.erase (mpduIt);
620 }
621 else
622 {
623 break; // MPDUs are in increasing order of sequence number in the in flight queue
624 }
625 }
626
627 // schedule a BlockAckRequest
628 NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
629 Ptr<Packet> bar = Create<Packet> ();
630 bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
631
632 WifiMacHeader hdr;
634 hdr.SetAddr1 (recipient);
635 hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
636 hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
637 hdr.SetDsNotTo ();
638 hdr.SetDsNotFrom ();
639 hdr.SetNoRetry ();
640 hdr.SetNoMoreFragments ();
641
642 ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
643}
644
647{
648 NS_LOG_FUNCTION (this << recipient << +tid);
649 AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
650 NS_ASSERT (it != m_agreements.end ());
651
653 reqHdr.SetType ((*it).second.first.GetBlockAckReqType ());
654 reqHdr.SetTidInfo (tid);
655 reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
656 return reqHdr;
657}
658
659void
661{
662 NS_LOG_FUNCTION (this << *bar);
663 NS_ASSERT (bar->GetHeader ().IsBlockAckReq () || bar->GetHeader ().IsTrigger ());
664
665 uint8_t tid = 0;
666 if (bar->GetHeader ().IsBlockAckReq ())
667 {
669 bar->GetPacket ()->PeekHeader (reqHdr);
670 tid = reqHdr.GetTidInfo ();
671 }
672#ifdef NS3_BUILD_PROFILE_DEBUG
673 else
674 {
675 CtrlTriggerHeader triggerHdr;
676 bar->GetPacket ()->PeekHeader (triggerHdr);
677 NS_ASSERT (triggerHdr.IsMuBar ());
678 }
679#endif
680 Bar request (bar, tid, skipIfNoDataQueued);
681
682 // if a BAR for the given agreement is present, replace it with the new one
683 std::list<Bar>::const_iterator i = m_bars.end ();
684
685 if (bar->GetHeader ().IsBlockAckReq ())
686 {
687 for (i = m_bars.begin (); i != m_bars.end (); i++)
688 {
689 if (i->bar->GetHeader ().IsBlockAckReq ()
690 && i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
691 {
692 i = m_bars.erase (i);
693 break;
694 }
695 }
696 }
697
698 if (bar->GetHeader ().IsRetry ())
699 {
700 m_bars.push_front (request);
701 }
702 else
703 {
704 m_bars.insert (i, request);
705 }
706}
707
708void
710{
711 NS_LOG_FUNCTION (this << recipient << +tid);
712 m_blockAckInactivityTimeout (recipient, tid, true);
713}
714
715void
716BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
717{
718 NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
719 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
720 NS_ASSERT (it != m_agreements.end ());
721 if (!it->second.first.IsEstablished ())
722 {
724 }
725 it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
726 it->second.first.SetStartingSequence (startingSeq);
727}
728
729void
731{
732 NS_LOG_FUNCTION (this << recipient << +tid);
733 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
734 NS_ASSERT (it != m_agreements.end ());
735 if (!it->second.first.IsRejected ())
736 {
738 }
739 it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
740}
741
742void
744{
745 NS_LOG_FUNCTION (this << recipient << +tid);
746 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
747 NS_ASSERT (it != m_agreements.end ());
748 if (!it->second.first.IsNoReply ())
749 {
751 }
752 it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
753 m_unblockPackets (recipient, tid);
754}
755
756void
758{
759 NS_LOG_FUNCTION (this << recipient << +tid);
760 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
761 NS_ASSERT (it != m_agreements.end ());
762 if (!it->second.first.IsReset ())
763 {
765 }
766 it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
767}
768
769void
771{
772 NS_LOG_FUNCTION (this << queue);
773 m_queue = queue;
774}
775
776bool
777BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
778{
779 NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
781 if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
782 {
783 uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
784 GetNBufferedPackets (recipient, tid);
785 if (packets >= m_blockAckThreshold)
786 {
787 NotifyAgreementEstablished (recipient, tid, startingSeq);
788 return true;
789 }
790 }
791 return false;
792}
793
795{
797 {
798 AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
799 NS_ASSERT (it != m_agreements.end ());
800
801 Time now = Simulator::Now ();
802
803 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
804 for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
805 {
806 // remove MPDU if old or with expired lifetime
807 mpduIt = HandleInFlightMpdu (mpduIt, STAY_INFLIGHT, it, now);
808
809 if (mpduIt != it->second.second.begin ())
810 {
811 // the MPDU has not been removed
812 return true;
813 }
814 }
815 }
816
817 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
818 // has destroyed the agreement, hence we get here and correctly return false
819 return false;
820}
821
822void
824{
825 NS_LOG_FUNCTION (this << &callback);
827}
828
829void
831{
832 NS_LOG_FUNCTION (this << &callback);
833 m_blockPackets = callback;
834}
835
836void
838{
839 NS_LOG_FUNCTION (this << &callback);
840 m_unblockPackets = callback;
841}
842
843void
845{
846 m_txOkCallback = callback;
847}
848
849void
851{
852 m_txFailedCallback = callback;
853}
854
855void
857{
858 m_droppedOldMpduCallback = callback;
859}
860
861uint16_t
863{
864 uint16_t size = 0;
865 AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
866 if (it != m_agreements.end ())
867 {
868 size = it->second.first.GetBufferSize ();
869 }
870 return size;
871}
872
875{
876 AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
877 NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
878 return it->second.first.GetBlockAckReqType ();
879}
880
882BlockAckManager::GetBlockAckType (Mac48Address recipient, uint8_t tid) const
883{
884 AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
885 NS_ABORT_MSG_IF (it == m_agreements.end (), "No established Block Ack agreement");
886 return it->second.first.GetBlockAckType ();
887}
888
889uint16_t
891{
892 uint16_t seqNum = 0;
893 AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
894 if (it != m_agreements.end ())
895 {
896 seqNum = it->second.first.GetStartingSequence ();
897 }
898 return seqNum;
899}
900
901} //namespace ns3
void SetImmediateBlockAck(void)
Set block ack policy to immediate Ack.
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
void SetDelayedBlockAck(void)
Set block ack policy to delayed Ack.
uint16_t GetTimeout(void) const
Return the timeout.
EventId m_inactivityEvent
inactivity event
void SetBufferSize(uint16_t bufferSize)
Set buffer size.
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
void SetTimeout(uint16_t timeout)
Set timeout.
void SetHtSupported(bool htSupported)
Enable or disable HT support.
Manages all block ack agreements for an originator station.
void StorePacket(Ptr< WifiMacQueueItem > mpdu)
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
void SetTxFailedCallback(TxFailed callback)
void NotifyAgreementRejected(Mac48Address recipient, uint8_t tid)
CtrlBAckRequestHeader GetBlockAckReqHeader(Mac48Address recipient, uint8_t tid) const
Callback< void, Mac48Address, uint8_t > m_unblockPackets
unblock packets callback
void SetQueue(const Ptr< WifiMacQueue > queue)
void SetTxOkCallback(TxOk callback)
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
uint8_t m_blockAckThreshold
block ack threshold
void SetBlockAckThreshold(uint8_t nPackets)
DroppedOldMpdu m_droppedOldMpduCallback
the dropped MPDU callback
std::list< Ptr< WifiMacQueueItem > > PacketQueue
typedef for a list of WifiMacQueueItem.
void NotifyAgreementEstablished(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
void SetDroppedOldMpduCallback(DroppedOldMpdu callback)
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
void NotifyDiscardedMpdu(Ptr< const WifiMacQueueItem > mpdu)
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...
TxFailed m_txFailedCallback
transmit failed callback
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
Ptr< WifiMacQueue > m_queue
queue
std::pair< uint16_t, uint16_t > NotifyGotBlockAck(const CtrlBAckResponseHeader &blockAck, Mac48Address recipient, const std::set< uint8_t > &tids, size_t index=0)
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent to the recipient.
void NotifyAgreementReset(Mac48Address recipient, uint8_t tid)
void NotifyMissedAck(Ptr< WifiMacQueueItem > mpdu)
Invoked upon missed reception of an Ack frame after the transmission of a QoS data frame sent under a...
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_agreementState
The trace source fired when a state transition occurred.
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient, uint16_t startingSeq)
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.
uint16_t GetRecipientBufferSize(Mac48Address recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
void NotifyAgreementNoReply(Mac48Address recipient, uint8_t tid)
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...
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent by the recipient.
static TypeId GetTypeId(void)
Get the type ID.
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, TID), a set of packets for whi...
void CreateAgreement(const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient, bool htSupported=true)
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
BlockAck inactivity timeout callback.
TxOk m_txOkCallback
transmit OK callback
MpduStatus
Enumeration for the statuses of a buffered MPDU.
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::const_iterator AgreementsCI
typedef for a const iterator for Agreements.
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::iterator AgreementsI
typedef for an iterator for Agreements.
void DoDispose() override
Destructor implementation.
uint32_t GetNBufferedPackets(Mac48Address recipient, uint8_t tid) const
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
uint16_t GetOriginatorStartingSequence(Mac48Address recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
std::list< Bar > m_bars
list of BARs
std::list< Ptr< WifiMacQueueItem > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
PacketQueueI HandleInFlightMpdu(PacketQueueI mpduIt, MpduStatus status, const AgreementsI &it, const Time &now)
Handle the given in flight MPDU based on its given status.
Callback template class.
Definition: callback.h:1279
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1386
Headers for BlockAckRequest.
Definition: ctrl-headers.h:49
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
Headers for BlockAck response.
Definition: ctrl-headers.h:202
bool IsCompressed(void) const
Check if the current BA policy is Compressed Block Ack.
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.
bool IsBasic(void) const
Check if the current BA policy is Basic Block Ack.
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...
bool IsExtendedCompressed(void) const
Check if the current BA policy is Extended Compressed Block Ack.
bool IsMultiTid(void) const
Check if the current BA policy is Multi-TID Block Ack.
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
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...
Headers for Trigger frames.
Definition: ctrl-headers.h:886
bool IsMuBar(void) const
Check if this is a MU-BAR Trigger frame.
an EUI-48 address
Definition: mac48-address.h:44
static Mac48Address GetBroadcast(void)
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:1300
uint16_t GetTimeout(void) const
Return the timeout.
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
uint16_t GetBufferSize(void) const
Return the buffer size.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1432
bool IsImmediateBlockAck(void) const
Return whether the Block Ack policy is immediate Block Ack.
bool IsAmsduSupported(void) const
Return whether A-MSDU capability is supported.
uint16_t GetBufferSize(void) const
Return the buffer size.
uint16_t GetTimeout(void) const
Return the timeout.
uint8_t GetTid(void) const
Return the Traffic ID (TID).
A base class which provides memory management and object aggregation.
Definition: object.h:88
Maintains the state and information about transmitted MPDUs with Ack Policy set to Block Ack for an o...
void InitTxWindow(void)
Initialize the originator's transmit window by setting its size and starting sequence number equal to...
void SetState(State state)
Set the current state.
State
Represents the state for this agreement.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:555
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Implements the IEEE 802.11 MAC header.
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
void SetNoRetry(void)
Un-set the Retry bit in the Frame Control field.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetNoMoreFragments(void)
Un-set the More Fragment bit in the Frame Control Field.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
#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_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1261
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
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
address
Definition: first.py:40
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr uint16_t SEQNO_SPACE_HALF_SIZE
Size of the half the space of sequence numbers (used to determine old packets)
Definition: wifi-utils.h:134
@ WIFI_MAC_CTL_BACKREQ
ns3::Time timeout
BlockAckRequest frame information.
uint8_t tid
TID (unused if MU-BAR)
bool skipIfNoDataQueued
do not send if there is no data queued (unused if MU-BAR)
Ptr< const WifiMacQueueItem > bar
BlockAckRequest or MU-BAR Trigger Frame.
The different BlockAckRequest variants.
The different BlockAck variants.
uint32_t prev