A Discrete-Event Network Simulator
API
block-ack-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009, 2010 MIRKO BANCHI
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Mirko Banchi <mk.banchi@gmail.com>
18 */
19
20#include "block-ack-manager.h"
21
22#include "ctrl-headers.h"
23#include "mgt-headers.h"
24#include "qos-utils.h"
25#include "wifi-mac-queue.h"
26#include "wifi-tx-vector.h"
27#include "wifi-utils.h"
28
29#include "ns3/log.h"
30#include "ns3/simulator.h"
31
32#include <optional>
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("BlockAckManager");
38
40{
41 NS_LOG_FUNCTION(this);
42}
43
44Bar::Bar(Ptr<const WifiMpdu> bar, uint8_t tid, bool skipIfNoDataQueued)
45 : bar(bar),
46 tid(tid),
47 skipIfNoDataQueued(skipIfNoDataQueued)
48{
50}
51
53
56{
57 static TypeId tid =
58 TypeId("ns3::BlockAckManager")
60 .SetGroupName("Wifi")
61 .AddConstructor<BlockAckManager>()
62 .AddTraceSource("AgreementState",
63 "The state of the ADDBA handshake",
65 "ns3::BlockAckManager::AgreementStateTracedCallback");
66 return tid;
67}
68
70{
71 NS_LOG_FUNCTION(this);
72}
73
75{
76 NS_LOG_FUNCTION(this);
77}
78
79void
81{
82 NS_LOG_FUNCTION(this);
83 m_agreements.clear();
84 m_bars.clear();
85 m_queue = nullptr;
86 m_bamMap.clear();
87}
88
89void
91{
92 m_bamMap = bamMap;
93}
94
95bool
97{
98 NS_LOG_FUNCTION(this << recipient << +tid);
99 return (m_agreements.find(std::make_pair(recipient, tid)) != m_agreements.end());
100}
101
102bool
104 uint8_t tid,
106{
107 AgreementsCI it;
108 it = m_agreements.find(std::make_pair(recipient, tid));
109 if (it != m_agreements.end())
110 {
111 switch (state)
112 {
114 return it->second.first.IsEstablished();
116 return it->second.first.IsPending();
118 return it->second.first.IsRejected();
120 return it->second.first.IsNoReply();
122 return it->second.first.IsReset();
123 default:
124 NS_FATAL_ERROR("Invalid state for block ack agreement");
125 }
126 }
127 return false;
128}
129
130void
132 Mac48Address recipient,
133 bool htSupported)
134{
135 NS_LOG_FUNCTION(this << reqHdr << recipient << htSupported);
136 std::pair<Mac48Address, uint8_t> key(recipient, reqHdr->GetTid());
137 OriginatorBlockAckAgreement agreement(recipient, reqHdr->GetTid());
138 agreement.SetStartingSequence(reqHdr->GetStartingSequence());
139 /* For now we assume that originator doesn't use this field. Use of this field
140 is mandatory only for recipient */
141 agreement.SetBufferSize(reqHdr->GetBufferSize());
142 agreement.SetTimeout(reqHdr->GetTimeout());
143 agreement.SetAmsduSupport(reqHdr->IsAmsduSupported());
144 agreement.SetHtSupported(htSupported);
145 if (reqHdr->IsImmediateBlockAck())
146 {
147 agreement.SetImmediateBlockAck();
148 }
149 else
150 {
151 agreement.SetDelayedBlockAck();
152 }
153 uint8_t tid = reqHdr->GetTid();
156 PacketQueue queue;
157 std::pair<OriginatorBlockAckAgreement, PacketQueue> value(agreement, queue);
158 if (ExistsAgreement(recipient, tid))
159 {
160 // Delete agreement if it exists and in RESET state
162 m_agreements.erase(key);
163 }
164 m_agreements.insert(std::make_pair(key, value));
165 m_blockPackets(recipient, reqHdr->GetTid());
166}
167
168void
170{
171 NS_LOG_FUNCTION(this << recipient << +tid);
172 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
173 if (it != m_agreements.end())
174 {
175 m_agreements.erase(it);
176 // remove scheduled BAR
177 for (std::list<Bar>::const_iterator i = m_bars.begin(); i != m_bars.end();)
178 {
179 if (i->bar->GetHeader().GetAddr1() == recipient && i->tid == tid)
180 {
181 i = m_bars.erase(i);
182 }
183 else
184 {
185 i++;
186 }
187 }
188 }
189}
190
191void
193 Mac48Address recipient,
194 uint16_t startingSeq)
195{
196 NS_LOG_FUNCTION(this << respHdr << recipient << startingSeq);
197 uint8_t tid = respHdr->GetTid();
198 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
199 if (it != m_agreements.end())
200 {
201 OriginatorBlockAckAgreement& agreement = it->second.first;
202 agreement.SetBufferSize(respHdr->GetBufferSize());
203 agreement.SetTimeout(respHdr->GetTimeout());
204 agreement.SetAmsduSupport(respHdr->IsAmsduSupported());
205 agreement.SetStartingSequence(startingSeq);
206 agreement.InitTxWindow();
207 if (respHdr->IsImmediateBlockAck())
208 {
209 agreement.SetImmediateBlockAck();
210 }
211 else
212 {
213 agreement.SetDelayedBlockAck();
214 }
215 if (!it->second.first.IsEstablished())
216 {
218 recipient,
219 tid,
221 }
223 if (agreement.GetTimeout() != 0)
224 {
225 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
228 this,
229 recipient,
230 tid);
231 }
232 }
233 m_unblockPackets(recipient, tid);
234}
235
236void
238{
239 NS_LOG_FUNCTION(this << *mpdu);
240 NS_ASSERT(mpdu->GetHeader().IsQosData());
241
242 uint8_t tid = mpdu->GetHeader().GetQosTid();
243 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
244
245 AgreementsI agreementIt = m_agreements.find(std::make_pair(recipient, tid));
246 NS_ASSERT(agreementIt != m_agreements.end());
247
248 uint16_t mpduDist =
249 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
250
251 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
252 {
253 NS_LOG_DEBUG("Got an old packet. Do nothing");
254 return;
255 }
256
257 // store the packet and keep the list sorted in increasing order of sequence number
258 // with respect to the starting sequence number
259 auto it = agreementIt->second.second.rbegin();
260 while (it != agreementIt->second.second.rend())
261 {
262 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
263 {
264 NS_LOG_DEBUG("Packet already in the queue of the BA agreement");
265 return;
266 }
267
268 uint16_t dist =
269 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
270
271 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
272 (*it)->GetHeader().GetFragmentNumber()))
273 {
274 break;
275 }
276
277 it++;
278 }
279 agreementIt->second.second.insert(it.base(), mpdu);
280 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
281 mpdu->SetInFlight();
282}
283
286{
287 Time now = Simulator::Now();
289 // remove all expired MPDUs from the MAC queue, so that
290 // BlockAckRequest frames (if needed) are scheduled
291 m_queue->WipeAllExpiredMpdus();
292
293 auto nextBar = m_bars.begin();
294
295 while (nextBar != m_bars.end())
296 {
297 Mac48Address recipient = nextBar->bar->GetHeader().GetAddr1();
298
299 if (address != Mac48Address::GetBroadcast() && tid != 8 &&
300 (!nextBar->bar->GetHeader().IsBlockAckReq() || address != recipient ||
301 tid != nextBar->tid))
302 {
303 // we can only return a BAR addressed to the given station and for the given TID
304 nextBar++;
305 continue;
306 }
307 if (nextBar->bar->GetHeader().IsBlockAckReq())
308 {
309 auto bam = m_bamMap.at(QosUtilsMapTidToAc(nextBar->tid));
310 AgreementsI it = bam->m_agreements.find(std::make_pair(recipient, nextBar->tid));
311 if (it == m_agreements.end())
312 {
313 // BA agreement was torn down; remove this BAR and continue
314 nextBar = m_bars.erase(nextBar);
315 continue;
316 }
317 if (nextBar->skipIfNoDataQueued &&
318 !m_queue->PeekByTidAndAddress(nextBar->tid, recipient))
319 {
320 // skip this BAR as there is no data queued
321 nextBar++;
322 continue;
323 }
324 // update BAR if the starting sequence number changed
326 nextBar->bar->GetPacket()->PeekHeader(reqHdr);
327 if (reqHdr.GetStartingSequence() != it->second.first.GetStartingSequence())
328 {
329 reqHdr.SetStartingSequence(it->second.first.GetStartingSequence());
330 Ptr<Packet> packet = Create<Packet>();
331 packet->AddHeader(reqHdr);
332 nextBar->bar = Create<const WifiMpdu>(packet, nextBar->bar->GetHeader());
333 }
334 }
335
336 bar = nextBar->bar;
337 if (remove)
338 {
339 m_bars.erase(nextBar);
340 }
341 break;
342 }
343 return bar;
344}
345
348{
349 NS_LOG_FUNCTION(this << recipient << +tid);
350 AgreementsCI it = m_agreements.find(std::make_pair(recipient, tid));
351 if (it == m_agreements.end())
352 {
353 return 0;
354 }
355 return it->second.second.size();
356}
357
358void
360{
361 NS_LOG_FUNCTION(this << +nPackets);
362 m_blockAckThreshold = nPackets;
363}
364
367 MpduStatus status,
368 const AgreementsI& it,
369 const Time& now)
370{
371 NS_LOG_FUNCTION(this << **mpduIt << +static_cast<uint8_t>(status));
372
373 if (!(*mpduIt)->IsQueued())
374 {
375 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
376 // removed by another method), remove from the queue of in flight MPDUs
377 NS_LOG_DEBUG("MPDU is not stored in the EDCA queue, drop MPDU");
378 return it->second.second.erase(mpduIt);
379 }
380
381 if (status == ACKNOWLEDGED)
382 {
383 // the MPDU has to be dequeued from the EDCA queue
384 return it->second.second.erase(mpduIt);
385 }
386
387 WifiMacHeader& hdr = (*mpduIt)->GetHeader();
388
389 NS_ASSERT(hdr.GetAddr1() == it->first.first);
390 NS_ASSERT(hdr.IsQosData() && hdr.GetQosTid() == it->first.second);
391
392 if (it->second.first.GetDistance(hdr.GetSequenceNumber()) >= SEQNO_SPACE_HALF_SIZE)
393 {
394 NS_LOG_DEBUG("Old packet. Remove from the EDCA queue, too");
396 {
398 }
399 m_queue->Remove(*mpduIt);
400 return it->second.second.erase(mpduIt);
401 }
402
403 std::optional<PacketQueueI> prevIt;
404 if (mpduIt != it->second.second.begin())
405 {
406 prevIt = std::prev(mpduIt);
407 }
408
409 if (m_queue->TtlExceeded(*mpduIt, now))
410 {
411 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
412 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
413 // which removed this MPDU (and possibly others) from the in flight queue as well
414 NS_LOG_DEBUG("MSDU lifetime expired, drop MPDU");
415 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
416 }
417
418 if (status == STAY_INFLIGHT)
419 {
420 // the MPDU has to stay in flight, do nothing
421 return ++mpduIt;
422 }
423
424 NS_ASSERT(status == TO_RETRANSMIT);
425 (*mpduIt)->GetHeader().SetRetry();
426 (*mpduIt)->ResetInFlight(); // no longer in flight; will be if retransmitted
427
428 return it->second.second.erase(mpduIt);
429}
430
431void
433{
434 NS_LOG_FUNCTION(this << *mpdu);
435 NS_ASSERT(mpdu->GetHeader().IsQosData());
436
437 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
438 uint8_t tid = mpdu->GetHeader().GetQosTid();
440
441 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
442 NS_ASSERT(it != m_agreements.end());
443
444 it->second.first.NotifyAckedMpdu(mpdu);
445
446 // remove the acknowledged frame from the queue of outstanding packets
447 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
448 {
449 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
450 {
451 m_queue->DequeueIfQueued({*queueIt});
453 break;
454 }
455 }
456}
457
458void
460{
461 NS_LOG_FUNCTION(this << *mpdu);
462 NS_ASSERT(mpdu->GetHeader().IsQosData());
463
464 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
465 uint8_t tid = mpdu->GetHeader().GetQosTid();
467
468 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
469 NS_ASSERT(it != m_agreements.end());
470
471 // remove the frame from the queue of outstanding packets (it will be re-inserted
472 // if retransmitted)
473 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
474 {
475 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
476 {
478 break;
479 }
480 }
481}
482
483std::pair<uint16_t, uint16_t>
485 Mac48Address recipient,
486 const std::set<uint8_t>& tids,
487 size_t index)
488{
489 NS_LOG_FUNCTION(this << blockAck << recipient << index);
490 uint16_t nSuccessfulMpdus = 0;
491 uint16_t nFailedMpdus = 0;
492
493 NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
494 NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
495
496 uint8_t tid = blockAck.GetTidInfo(index);
497 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
498 // use the TID passed by the caller.
499 if (tid == 14)
500 {
501 NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
502 tid = *tids.begin();
503 }
505 {
506 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
507
508 if (it->second.first.m_inactivityEvent.IsRunning())
509 {
510 /* Upon reception of a BlockAck frame, the inactivity timer at the
511 originator must be reset.
512 For more details see section 11.5.3 in IEEE802.11e standard */
513 it->second.first.m_inactivityEvent.Cancel();
514 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
515 it->second.first.m_inactivityEvent =
518 this,
519 recipient,
520 tid);
521 }
522
523 NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() ||
524 blockAck.IsMultiSta());
525 Time now = Simulator::Now();
526 std::list<Ptr<const WifiMpdu>> acked;
527
528 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
529 {
530 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
531 NS_LOG_DEBUG("Current seq=" << currentSeq);
532 if (blockAck.IsPacketReceived(currentSeq, index))
533 {
534 it->second.first.NotifyAckedMpdu(*queueIt);
535 nSuccessfulMpdus++;
536 if (!m_txOkCallback.IsNull())
537 {
538 m_txOkCallback(*queueIt);
539 }
540 acked.emplace_back(*queueIt);
541 queueIt = HandleInFlightMpdu(queueIt, ACKNOWLEDGED, it, now);
542 }
543 else
544 {
545 ++queueIt;
546 }
547 }
548
549 // Dequeue all acknowledged MPDUs at once
550 m_queue->DequeueIfQueued(acked);
551
552 // Remaining outstanding MPDUs have not been acknowledged
553 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
554 {
555 nFailedMpdus++;
557 {
558 m_txFailedCallback(*queueIt);
559 }
560 queueIt = HandleInFlightMpdu(queueIt, TO_RETRANSMIT, it, now);
561 }
562 }
563 return {nSuccessfulMpdus, nFailedMpdus};
564}
565
566void
568{
569 NS_LOG_FUNCTION(this << recipient << +tid);
571 {
572 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
573 Time now = Simulator::Now();
574
575 // remove all packets from the queue of outstanding packets (they will be
576 // re-inserted if retransmitted)
577 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
578 {
579 mpduIt = HandleInFlightMpdu(mpduIt, TO_RETRANSMIT, it, now);
580 }
581 }
582}
583
584void
586{
587 NS_LOG_FUNCTION(this << *mpdu);
588
589 if (!mpdu->GetHeader().IsQosData())
590 {
591 NS_LOG_DEBUG("Not a QoS Data frame");
592 return;
593 }
594
595 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
596 {
597 NS_LOG_DEBUG("This frame has never been transmitted");
598 return;
599 }
600
601 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
602 uint8_t tid = mpdu->GetHeader().GetQosTid();
604 {
605 NS_LOG_DEBUG("No established Block Ack agreement");
606 return;
607 }
608
609 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
610 uint16_t currStartingSeq = it->second.first.GetStartingSequence();
611 if (QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
612 {
613 NS_LOG_DEBUG("Discarded an old frame");
614 return;
615 }
616
617 // actually advance the transmit window
618 it->second.first.NotifyDiscardedMpdu(mpdu);
619
620 // remove old MPDUs from the EDCA queue and from the in flight queue
621 // (including the given MPDU which became old after advancing the transmit window)
622 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
623 {
624 if (it->second.first.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
626 {
627 NS_LOG_DEBUG("Dropping old MPDU: " << **mpduIt);
628 m_queue->DequeueIfQueued({*mpduIt});
630 {
632 }
633 mpduIt = it->second.second.erase(mpduIt);
634 }
635 else
636 {
637 break; // MPDUs are in increasing order of sequence number in the in flight queue
638 }
639 }
640
641 // schedule a BlockAckRequest
642 NS_LOG_DEBUG("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid
643 << ")");
644 Ptr<Packet> bar = Create<Packet>();
645 bar->AddHeader(GetBlockAckReqHeader(recipient, tid));
646
647 WifiMacHeader hdr;
649 hdr.SetAddr1(recipient);
650 hdr.SetAddr2(mpdu->GetHeader().GetAddr2());
651 hdr.SetAddr3(mpdu->GetHeader().GetAddr3());
652 hdr.SetDsNotTo();
653 hdr.SetDsNotFrom();
654 hdr.SetNoRetry();
655 hdr.SetNoMoreFragments();
656
657 ScheduleBar(Create<const WifiMpdu>(bar, hdr));
658}
659
662{
663 NS_LOG_FUNCTION(this << recipient << +tid);
664 AgreementsCI it = m_agreements.find(std::make_pair(recipient, tid));
665 NS_ASSERT(it != m_agreements.end());
666
668 reqHdr.SetType((*it).second.first.GetBlockAckReqType());
669 reqHdr.SetTidInfo(tid);
670 reqHdr.SetStartingSequence((*it).second.first.GetStartingSequence());
671 return reqHdr;
672}
673
674void
676{
677 NS_LOG_FUNCTION(this << *bar);
678 NS_ASSERT(bar->GetHeader().IsBlockAckReq() || bar->GetHeader().IsTrigger());
679
680 uint8_t tid = 0;
681 if (bar->GetHeader().IsBlockAckReq())
682 {
684 bar->GetPacket()->PeekHeader(reqHdr);
685 tid = reqHdr.GetTidInfo();
686 }
687#ifdef NS3_BUILD_PROFILE_DEBUG
688 else
689 {
690 CtrlTriggerHeader triggerHdr;
691 bar->GetPacket()->PeekHeader(triggerHdr);
692 NS_ASSERT(triggerHdr.IsMuBar());
693 }
694#endif
695 Bar request(bar, tid, skipIfNoDataQueued);
696
697 // if a BAR for the given agreement is present, replace it with the new one
698 std::list<Bar>::const_iterator i = m_bars.end();
699
700 if (bar->GetHeader().IsBlockAckReq())
701 {
702 for (i = m_bars.begin(); i != m_bars.end(); i++)
703 {
704 if (i->bar->GetHeader().IsBlockAckReq() &&
705 i->bar->GetHeader().GetAddr1() == bar->GetHeader().GetAddr1() && i->tid == tid)
706 {
707 i = m_bars.erase(i);
708 break;
709 }
710 }
711 }
712
713 if (bar->GetHeader().IsRetry())
714 {
715 m_bars.push_front(request);
716 }
717 else
718 {
719 m_bars.insert(i, request);
720 }
721}
722
723void
725{
726 NS_LOG_FUNCTION(this << recipient << +tid);
727 m_blockAckInactivityTimeout(recipient, tid, true);
728}
729
730void
732 uint8_t tid,
733 uint16_t startingSeq)
734{
735 NS_LOG_FUNCTION(this << recipient << +tid << startingSeq);
736 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
737 NS_ASSERT(it != m_agreements.end());
738 if (!it->second.first.IsEstablished())
739 {
741 recipient,
742 tid,
744 }
745 it->second.first.SetState(OriginatorBlockAckAgreement::ESTABLISHED);
746 it->second.first.SetStartingSequence(startingSeq);
747}
748
749void
751{
752 NS_LOG_FUNCTION(this << recipient << +tid);
753 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
754 NS_ASSERT(it != m_agreements.end());
755 if (!it->second.first.IsRejected())
756 {
758 }
759 it->second.first.SetState(OriginatorBlockAckAgreement::REJECTED);
760}
761
762void
764{
765 NS_LOG_FUNCTION(this << recipient << +tid);
766 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
767 NS_ASSERT(it != m_agreements.end());
768 if (!it->second.first.IsNoReply())
769 {
771 }
772 it->second.first.SetState(OriginatorBlockAckAgreement::NO_REPLY);
773 m_unblockPackets(recipient, tid);
774}
775
776void
778{
779 NS_LOG_FUNCTION(this << recipient << +tid);
780 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
781 NS_ASSERT(it != m_agreements.end());
782 if (!it->second.first.IsReset())
783 {
785 }
786 it->second.first.SetState(OriginatorBlockAckAgreement::RESET);
787}
788
789void
791{
792 NS_LOG_FUNCTION(this << queue);
793 m_queue = queue;
794}
795
796bool
797BlockAckManager::SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
798{
799 NS_LOG_FUNCTION(this << recipient << +tid << startingSeq);
802 ExistsAgreement(recipient, tid))
803 {
804 WifiContainerQueueId queueId{WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
805 uint32_t packets = m_queue->GetNPackets(queueId) + GetNBufferedPackets(recipient, tid);
806 if (packets >= m_blockAckThreshold)
807 {
808 NotifyAgreementEstablished(recipient, tid, startingSeq);
809 return true;
810 }
811 }
812 return false;
813}
814
815bool
817{
819 {
820 AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
821 NS_ASSERT(it != m_agreements.end());
822
823 Time now = Simulator::Now();
824
825 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
826 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
827 {
828 // remove MPDU if old or with expired lifetime
829 mpduIt = HandleInFlightMpdu(mpduIt, STAY_INFLIGHT, it, now);
830
831 if (mpduIt != it->second.second.begin())
832 {
833 // the MPDU has not been removed
834 return true;
835 }
836 }
837 }
838
839 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
840 // has destroyed the agreement, hence we get here and correctly return false
841 return false;
842}
843
844void
846{
847 NS_LOG_FUNCTION(this << &callback);
849}
850
851void
853{
854 NS_LOG_FUNCTION(this << &callback);
855 m_blockPackets = callback;
856}
857
858void
860{
861 NS_LOG_FUNCTION(this << &callback);
862 m_unblockPackets = callback;
863}
864
865void
867{
868 m_txOkCallback = callback;
869}
870
871void
873{
874 m_txFailedCallback = callback;
875}
876
877void
879{
880 m_droppedOldMpduCallback = callback;
881}
882
883uint16_t
885{
886 uint16_t size = 0;
887 AgreementsCI it = m_agreements.find(std::make_pair(recipient, tid));
888 if (it != m_agreements.end())
889 {
890 size = it->second.first.GetBufferSize();
891 }
892 return size;
893}
894
897{
898 AgreementsCI it = m_agreements.find(std::make_pair(recipient, tid));
899 NS_ABORT_MSG_IF(it == m_agreements.end(), "No established Block Ack agreement");
900 return it->second.first.GetBlockAckReqType();
901}
902
905{
906 AgreementsCI it = m_agreements.find(std::make_pair(recipient, tid));
907 NS_ABORT_MSG_IF(it == m_agreements.end(), "No established Block Ack agreement");
908 return it->second.first.GetBlockAckType();
909}
910
911uint16_t
913{
914 uint16_t seqNum = 0;
915 AgreementsCI it = m_agreements.find(std::make_pair(recipient, tid));
916 if (it != m_agreements.end())
917 {
918 seqNum = it->second.first.GetStartingSequence();
919 }
920 return seqNum;
921}
922
923} // namespace ns3
uint16_t GetTimeout() const
Return the timeout.
void SetImmediateBlockAck()
Set block ack policy to immediate Ack.
void SetStartingSequence(uint16_t seq)
Set starting sequence number.
EventId m_inactivityEvent
inactivity event
void SetBufferSize(uint16_t bufferSize)
Set buffer size.
void SetDelayedBlockAck()
Set block ack policy to delayed Ack.
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 SetTxFailedCallback(TxFailed callback)
void NotifyAgreementRejected(Mac48Address recipient, uint8_t tid)
std::map< AcIndex, Ptr< BlockAckManager > > m_bamMap
AC-indexed map of all Block Ack Managers.
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
std::list< Ptr< WifiMpdu > > PacketQueue
typedef for a list of WifiMpdu.
static TypeId GetTypeId()
Get the type ID.
void SetBlockAckThreshold(uint8_t nPackets)
DroppedOldMpdu m_droppedOldMpduCallback
the dropped MPDU callback
void NotifyAgreementEstablished(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
void SetDroppedOldMpduCallback(DroppedOldMpdu callback)
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
void NotifyGotAck(Ptr< const WifiMpdu > 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)
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)
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.
void SetBlockAckManagerMap(const std::map< AcIndex, Ptr< BlockAckManager > > &bamMap)
Provide information about all the Block Ack Managers installed on this device.
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.
void StorePacket(Ptr< WifiMpdu > mpdu)
void NotifyDiscardedMpdu(Ptr< const WifiMpdu > mpdu)
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, TID), a set of packets for whi...
void ScheduleBar(Ptr< const WifiMpdu > bar, bool skipIfNoDataQueued=false)
void CreateAgreement(const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient, bool htSupported=true)
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
std::list< Ptr< WifiMpdu > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
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.
Ptr< const WifiMpdu > 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.
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
void NotifyMissedAck(Ptr< WifiMpdu > mpdu)
Invoked upon missed reception of an Ack frame after the transmission of a QoS data frame sent under a...
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
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:443
bool IsNull() const
Check for null implementation.
Definition: callback.h:556
Headers for BlockAckRequest.
Definition: ctrl-headers.h:51
uint16_t GetStartingSequence() const
Return the starting sequence number.
uint8_t GetTidInfo() const
Return the Traffic ID (TID).
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
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 IsExtendedCompressed() const
Check if the current BA policy is Extended 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.
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 IsBasic() const
Check if the current BA policy is Basic Block Ack.
bool IsCompressed() const
Check if the current BA policy is Compressed Block Ack.
bool IsMultiTid() const
Check if the current BA policy is Multi-TID 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...
bool IsMultiSta() const
Check if the BlockAck frame variant is Multi-STA Block Ack.
Headers for Trigger frames.
Definition: ctrl-headers.h:886
bool IsMuBar() const
Check if this is a MU-BAR Trigger frame.
an EUI-48 address
Definition: mac48-address.h:46
static Mac48Address GetBroadcast()
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:1476
uint16_t GetBufferSize() const
Return the buffer size.
uint16_t GetTimeout() const
Return the timeout.
uint8_t GetTid() const
Return the Traffic ID (TID).
uint16_t GetStartingSequence() const
Return the starting sequence number.
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
bool IsImmediateBlockAck() const
Return whether the Block Ack policy is immediate Block Ack.
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1607
uint16_t GetBufferSize() const
Return the buffer size.
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
uint8_t GetTid() const
Return the Traffic ID (TID).
bool IsImmediateBlockAck() const
Return whether the Block Ack policy is immediate Block Ack.
uint16_t GetTimeout() const
Return the timeout.
A base class which provides memory management and object aggregation.
Definition: object.h:89
Maintains the state and information about transmitted MPDUs with Ack Policy set to Block Ack for an o...
void SetState(State state)
Set the current state.
State
Represents the state for this agreement.
void InitTxWindow()
Initialize the originator'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:268
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
uint16_t GetSequenceNumber() const
Return the sequence number of the header.
void SetNoMoreFragments()
Un-set the More Fragment bit in the Frame Control Field.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
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 SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
void SetNoRetry()
Un-set the Retry bit in the Frame Control 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:66
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:160
#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:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:1362
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:132
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:184
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:74
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:136
std::tuple< WifiContainerQueueType, Mac48Address, uint8_t > WifiContainerQueueId
Tuple (queue type, Address, TID) identifying a container queue.
@ WIFI_MAC_CTL_BACKREQ
@ WIFI_QOSDATA_UNICAST_QUEUE
value
Definition: second.py:41
ns3::Time timeout
BlockAckRequest frame information.
Ptr< const WifiMpdu > bar
BlockAckRequest or MU-BAR Trigger Frame.
uint8_t tid
TID (unused if MU-BAR)
bool skipIfNoDataQueued
do not send if there is no data queued (unused if MU-BAR)
The different BlockAckRequest variants.
The different BlockAck variants.
uint32_t prev