A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
block-ack-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009, 2010 MIRKO BANCHI
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mirko Banchi <mk.banchi@gmail.com>
7 */
8
9#include "block-ack-manager.h"
10
11#include "ctrl-headers.h"
12#include "mac-rx-middle.h"
13#include "mgt-action-headers.h"
14#include "qos-utils.h"
15#include "wifi-mac-queue.h"
16#include "wifi-tx-vector.h"
17#include "wifi-utils.h"
18
19#include "ns3/log.h"
20#include "ns3/simulator.h"
21
22#include <algorithm>
23#include <optional>
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("BlockAckManager");
29
30NS_OBJECT_ENSURE_REGISTERED(BlockAckManager);
31
32TypeId
34{
35 static TypeId tid =
36 TypeId("ns3::BlockAckManager")
38 .SetGroupName("Wifi")
39 .AddConstructor<BlockAckManager>()
40 .AddTraceSource("AgreementState",
41 "The state of the ADDBA handshake",
43 "ns3::BlockAckManager::AgreementStateTracedCallback");
44 return tid;
45}
46
51
56
57void
59{
60 NS_LOG_FUNCTION(this);
62 m_queue = nullptr;
63}
64
66BlockAckManager::GetAgreementAsOriginator(const Mac48Address& recipient, uint8_t tid) const
67{
68 if (auto it = m_originatorAgreements.find({recipient, tid}); it != m_originatorAgreements.end())
69 {
70 return std::cref(it->second.first);
71 }
72
73 return std::nullopt;
74}
75
77BlockAckManager::GetAgreementAsRecipient(const Mac48Address& originator, uint8_t tid) const
78{
79 if (auto it = m_recipientAgreements.find({originator, tid}); it != m_recipientAgreements.end())
80 {
81 return std::cref(it->second);
82 }
83
84 return std::nullopt;
85}
86
87void
89 const Mac48Address& recipient)
90{
91 NS_LOG_FUNCTION(this << reqHdr << recipient);
92 const auto tid = reqHdr.GetTid();
93
94 OriginatorBlockAckAgreement agreement(recipient, tid);
95 agreement.SetStartingSequence(reqHdr.GetStartingSequence());
96 /* For now we assume that originator doesn't use this field. Use of this field
97 is mandatory only for recipient */
98 agreement.SetBufferSize(reqHdr.GetBufferSize());
99 agreement.SetTimeout(reqHdr.GetTimeout());
100 agreement.SetAmsduSupport(reqHdr.IsAmsduSupported());
101 agreement.SetHtSupported(true);
102 if (reqHdr.IsImmediateBlockAck())
103 {
104 agreement.SetImmediateBlockAck();
105 }
106 else
107 {
108 agreement.SetDelayedBlockAck();
109 }
110 if (const auto gcrGroupAddr = reqHdr.GetGcrGroupAddress())
111 {
112 agreement.SetGcrGroupAddress(*gcrGroupAddr);
113 }
116 recipient,
117 tid,
119 if (auto existingAgreement = GetAgreementAsOriginator(recipient, tid))
120 {
121 NS_ASSERT_MSG(existingAgreement->get().IsReset(),
122 "Existing agreement must be in RESET state");
123 }
124 m_originatorAgreements.insert_or_assign({recipient, tid},
125 std::make_pair(std::move(agreement), PacketQueue{}));
126 m_blockPackets(recipient, tid);
127}
128
129void
131{
132 NS_LOG_FUNCTION(this << recipient << tid);
133 auto it = m_originatorAgreements.find({recipient, tid});
134 if (it != m_originatorAgreements.end())
135 {
136 m_originatorAgreements.erase(it);
137 }
138}
139
140void
142 const Mac48Address& recipient,
143 uint16_t startingSeq)
144{
145 NS_LOG_FUNCTION(this << respHdr << recipient << startingSeq);
146 uint8_t tid = respHdr.GetTid();
147 auto it = m_originatorAgreements.find({recipient, tid});
148 if (it != m_originatorAgreements.end())
149 {
150 OriginatorBlockAckAgreement& agreement = it->second.first;
151 agreement.SetBufferSize(respHdr.GetBufferSize());
152 agreement.SetTimeout(respHdr.GetTimeout());
153 agreement.SetAmsduSupport(respHdr.IsAmsduSupported());
154 agreement.SetStartingSequence(startingSeq);
155 agreement.InitTxWindow();
156 if (respHdr.IsImmediateBlockAck())
157 {
158 agreement.SetImmediateBlockAck();
159 }
160 else
161 {
162 agreement.SetDelayedBlockAck();
163 }
164 if (const auto gcrGroupAddr = respHdr.GetGcrGroupAddress())
165 {
166 agreement.SetGcrGroupAddress(*gcrGroupAddr);
167 }
168 if (!it->second.first.IsEstablished())
169 {
171 recipient,
172 tid,
174 }
176 if (agreement.GetTimeout() != 0)
177 {
178 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
181 this,
182 recipient,
183 tid);
184 }
185 }
186 m_unblockPackets(recipient, tid);
187}
188
189void
191 const Mac48Address& originator,
192 uint16_t startingSeq,
193 Ptr<MacRxMiddle> rxMiddle)
194{
195 NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << rxMiddle);
196 const auto tid = respHdr.GetTid();
197
198 RecipientBlockAckAgreement agreement(originator,
199 respHdr.IsAmsduSupported(),
200 tid,
201 respHdr.GetBufferSize(),
202 respHdr.GetTimeout(),
203 startingSeq,
204 true);
205
206 agreement.SetMacRxMiddle(rxMiddle);
207 if (respHdr.IsImmediateBlockAck())
208 {
209 agreement.SetImmediateBlockAck();
210 }
211 else
212 {
213 agreement.SetDelayedBlockAck();
214 }
215 if (const auto gcrGroupAddr = respHdr.GetGcrGroupAddress())
216 {
217 agreement.SetGcrGroupAddress(*gcrGroupAddr);
218 }
219
220 m_recipientAgreements.insert_or_assign({originator, tid}, agreement);
221}
222
223void
225{
226 NS_LOG_FUNCTION(this << originator << tid);
227
228 if (auto agreementIt = m_recipientAgreements.find({originator, tid});
229 agreementIt != m_recipientAgreements.end())
230 {
231 // forward up the buffered MPDUs before destroying the agreement
232 agreementIt->second.Flush();
233 m_recipientAgreements.erase(agreementIt);
234 }
235}
236
237void
239{
240 NS_LOG_FUNCTION(this << *mpdu);
241 NS_ASSERT(mpdu->GetHeader().IsQosData());
242
243 uint8_t tid = mpdu->GetHeader().GetQosTid();
244 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
245
246 auto agreementIt = m_originatorAgreements.find({recipient, tid});
247 NS_ASSERT(agreementIt != m_originatorAgreements.end());
248
249 uint16_t mpduDist =
250 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
251
252 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
253 {
254 NS_LOG_DEBUG("Got an old packet. Do nothing");
255 return;
256 }
257
258 // store the packet and keep the list sorted in increasing order of sequence number
259 // with respect to the starting sequence number
260 auto it = agreementIt->second.second.rbegin();
261 while (it != agreementIt->second.second.rend())
262 {
263 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
264 {
265 NS_LOG_DEBUG("Packet already in the queue of the BA agreement");
266 return;
267 }
268
269 uint16_t dist =
270 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
271
272 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
273 (*it)->GetHeader().GetFragmentNumber()))
274 {
275 break;
276 }
277
278 it++;
279 }
280 agreementIt->second.second.insert(it.base(), mpdu);
281 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
282}
283
285BlockAckManager::GetNBufferedPackets(const Mac48Address& recipient, uint8_t tid) const
286{
287 auto it = m_originatorAgreements.find({recipient, tid});
288 if (it == m_originatorAgreements.end())
289 {
290 return 0;
291 }
292 return it->second.second.size();
293}
294
295void
297{
298 NS_LOG_FUNCTION(this << nPackets);
299 m_blockAckThreshold = nPackets;
300}
301
304 PacketQueueI mpduIt,
305 MpduStatus status,
306 const OriginatorAgreementsI& it,
307 const Time& now)
308{
309 NS_LOG_FUNCTION(this << linkId << **mpduIt << static_cast<uint8_t>(status));
310
311 if (!(*mpduIt)->IsQueued())
312 {
313 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
314 // removed by another method), remove from the queue of in flight MPDUs
315 NS_LOG_DEBUG("MPDU is not stored in the EDCA queue, drop MPDU");
316 return it->second.second.erase(mpduIt);
317 }
318
319 if (status == ACKNOWLEDGED)
320 {
321 // the MPDU has to be dequeued from the EDCA queue
322 return it->second.second.erase(mpduIt);
323 }
324
325 const WifiMacHeader& hdr = (*mpduIt)->GetHeader();
326
327 NS_ASSERT(hdr.GetAddr1() == it->first.first);
328 NS_ASSERT(hdr.IsQosData() && hdr.GetQosTid() == it->first.second);
329
330 if (it->second.first.GetDistance(hdr.GetSequenceNumber()) >= SEQNO_SPACE_HALF_SIZE)
331 {
332 NS_LOG_DEBUG("Old packet. Remove from the EDCA queue, too");
335 m_queue->Remove(*mpduIt);
336 return it->second.second.erase(mpduIt);
337 }
338
339 std::optional<PacketQueueI> prevIt;
340 if (mpduIt != it->second.second.begin())
341 {
342 prevIt = std::prev(mpduIt);
343 }
344
345 if (m_queue->TtlExceeded(*mpduIt, now))
346 {
347 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
348 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
349 // which removed this MPDU (and possibly others) from the in flight queue as well
350 NS_LOG_DEBUG("MSDU lifetime expired, drop MPDU");
351 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
352 }
353
354 if (status == STAY_INFLIGHT)
355 {
356 // the MPDU has to stay in flight, do nothing
357 return ++mpduIt;
358 }
359
360 NS_ASSERT(status == TO_RETRANSMIT);
361 (*mpduIt)->GetHeader().SetRetry();
362 (*mpduIt)->ResetInFlight(linkId); // no longer in flight; will be if retransmitted
363
364 return it->second.second.erase(mpduIt);
365}
366
367void
369{
370 NS_LOG_FUNCTION(this << linkId << *mpdu);
371 NS_ASSERT(mpdu->GetHeader().IsQosData());
372
373 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
374 uint8_t tid = mpdu->GetHeader().GetQosTid();
375
376 auto it = m_originatorAgreements.find({recipient, tid});
378 NS_ASSERT(it->second.first.IsEstablished());
379
380 it->second.first.NotifyAckedMpdu(mpdu);
381
382 // remove the acknowledged frame from the queue of outstanding packets
383 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
384 {
385 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
386 {
387 m_queue->DequeueIfQueued({*queueIt});
388 HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, Simulator::Now());
389 break;
390 }
391 }
392}
393
394void
396{
397 NS_LOG_FUNCTION(this << linkId << *mpdu);
398 NS_ASSERT(mpdu->GetHeader().IsQosData());
399
400 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
401 uint8_t tid = mpdu->GetHeader().GetQosTid();
402
403 auto it = m_originatorAgreements.find({recipient, tid});
405 NS_ASSERT(it->second.first.IsEstablished());
406
407 // remove the frame from the queue of outstanding packets (it will be re-inserted
408 // if retransmitted)
409 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
410 {
411 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
412 {
413 HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, Simulator::Now());
414 break;
415 }
416 }
417}
418
419std::pair<uint16_t, uint16_t>
421 const CtrlBAckResponseHeader& blockAck,
422 const Mac48Address& recipient,
423 const std::set<uint8_t>& tids,
424 size_t index)
425{
426 NS_LOG_FUNCTION(this << linkId << blockAck << recipient << index);
427
428 NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
429 NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
430
431 uint8_t tid = blockAck.GetTidInfo(index);
432 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
433 // use the TID passed by the caller.
434 if (tid == 14)
435 {
436 NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
437 tid = *tids.begin();
438 }
439
440 auto it = m_originatorAgreements.find({recipient, tid});
441 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
442 {
443 return {0, 0};
444 }
445
446 uint16_t nSuccessfulMpdus = 0;
447 uint16_t nFailedMpdus = 0;
448
449 if (it->second.first.m_inactivityEvent.IsPending())
450 {
451 /* Upon reception of a BlockAck frame, the inactivity timer at the
452 originator must be reset.
453 For more details see section 11.5.3 in IEEE802.11e standard */
454 it->second.first.m_inactivityEvent.Cancel();
455 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
456 it->second.first.m_inactivityEvent =
458 }
459
460 NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() || blockAck.IsMultiSta());
461 Time now = Simulator::Now();
462 std::list<Ptr<const WifiMpdu>> acked;
463
464 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
465 {
466 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
467 NS_LOG_DEBUG("Current seq=" << currentSeq);
468 if (blockAck.IsPacketReceived(currentSeq, index))
469 {
470 it->second.first.NotifyAckedMpdu(*queueIt);
471 nSuccessfulMpdus++;
472 if (!m_txOkCallback.IsNull())
473 {
474 m_txOkCallback(*queueIt);
475 }
476 acked.emplace_back(*queueIt);
477 queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
478 }
479 else
480 {
481 ++queueIt;
482 }
483 }
484
485 // Dequeue all acknowledged MPDUs at once
486 m_queue->DequeueIfQueued(acked);
487
488 // Remaining outstanding MPDUs have not been acknowledged
489 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
490 {
491 // transmission actually failed if the MPDU is inflight only on the same link on
492 // which we received the BlockAck frame
493 auto linkIds = (*queueIt)->GetInFlightLinkIds();
494
495 if (linkIds.size() == 1 && *linkIds.begin() == linkId)
496 {
497 nFailedMpdus++;
499 {
500 m_txFailedCallback(*queueIt);
501 }
502 queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
503 continue;
504 }
505
506 queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now);
507 }
508
509 return {nSuccessfulMpdus, nFailedMpdus};
510}
511
512void
513BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, const Mac48Address& recipient, uint8_t tid)
514{
515 NS_LOG_FUNCTION(this << linkId << recipient << tid);
516
517 auto it = m_originatorAgreements.find({recipient, tid});
518 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
519 {
520 return;
521 }
522
523 Time now = Simulator::Now();
524
525 // remove all packets from the queue of outstanding packets (they will be
526 // re-inserted if retransmitted)
527 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
528 {
529 // MPDUs that were transmitted on another link shall stay inflight
530 auto linkIds = (*mpduIt)->GetInFlightLinkIds();
531 if (!linkIds.contains(linkId))
532 {
533 mpduIt = HandleInFlightMpdu(linkId, mpduIt, STAY_INFLIGHT, it, now);
534 continue;
535 }
536 mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
537 }
538}
539
540void
542{
543 NS_LOG_FUNCTION(this << *mpdu);
544
545 if (!mpdu->GetHeader().IsQosData())
546 {
547 NS_LOG_DEBUG("Not a QoS Data frame");
548 return;
549 }
550
551 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
552 {
553 NS_LOG_DEBUG("This frame has never been transmitted");
554 return;
555 }
556
557 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
558 uint8_t tid = mpdu->GetHeader().GetQosTid();
559 auto it = m_originatorAgreements.find({recipient, tid});
560 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
561 {
562 NS_LOG_DEBUG("No established Block Ack agreement");
563 return;
564 }
565
566 uint16_t currStartingSeq = it->second.first.GetStartingSequence();
567 if (QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
568 {
569 NS_LOG_DEBUG("Discarded an old frame");
570 return;
571 }
572
573 // actually advance the transmit window
574 it->second.first.NotifyDiscardedMpdu(mpdu);
575
576 // remove old MPDUs from the EDCA queue and from the in flight queue
577 // (including the given MPDU which became old after advancing the transmit window)
578 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
579 {
580 if (it->second.first.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
582 {
583 NS_LOG_DEBUG("Dropping old MPDU: " << **mpduIt);
584 m_queue->DequeueIfQueued({*mpduIt});
586 {
588 }
589 mpduIt = it->second.second.erase(mpduIt);
590 }
591 else
592 {
593 break; // MPDUs are in increasing order of sequence number in the in flight queue
594 }
595 }
596
597 // schedule a BlockAckRequest
598 NS_LOG_DEBUG("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid
599 << ")");
600
601 WifiMacHeader hdr;
603 hdr.SetAddr1(recipient);
604 hdr.SetAddr2(mpdu->GetOriginal()->GetHeader().GetAddr2());
605 hdr.SetDsNotTo();
606 hdr.SetDsNotFrom();
607 hdr.SetNoRetry();
608 hdr.SetNoMoreFragments();
609
610 ScheduleBar(GetBlockAckReqHeader(recipient, tid), hdr);
611}
612
613void
615 uint8_t tid,
616 uint16_t startingSeq)
617{
618 NS_LOG_FUNCTION(this << originator << tid << startingSeq);
619 auto it = m_recipientAgreements.find({originator, tid});
620 if (it == m_recipientAgreements.end())
621 {
622 return;
623 }
624 it->second.NotifyReceivedBar(startingSeq);
625}
626
627void
629{
630 NS_LOG_FUNCTION(this << *mpdu);
631 auto originator = mpdu->GetOriginal()->GetHeader().GetAddr2();
632 NS_ASSERT(mpdu->GetHeader().IsQosData());
633 auto tid = mpdu->GetHeader().GetQosTid();
634
635 auto it = m_recipientAgreements.find({originator, tid});
636 if (it == m_recipientAgreements.end())
637 {
638 return;
639 }
640 it->second.NotifyReceivedMpdu(mpdu);
641}
642
644BlockAckManager::GetBlockAckReqHeader(const Mac48Address& recipient, uint8_t tid) const
645{
646 auto it = m_originatorAgreements.find({recipient, tid});
649 reqHdr.SetType((*it).second.first.GetBlockAckReqType());
650 reqHdr.SetTidInfo(tid);
651 reqHdr.SetStartingSequence((*it).second.first.GetStartingSequence());
652 return reqHdr;
653}
654
655void
657{
658 NS_LOG_FUNCTION(this << reqHdr << hdr);
659
660 uint8_t tid = reqHdr.GetTidInfo();
661
662 WifiContainerQueueId queueId(WIFI_CTL_QUEUE, WIFI_UNICAST, hdr.GetAddr1(), std::nullopt);
663 auto pkt = Create<Packet>();
664 pkt->AddHeader(reqHdr);
665 Ptr<WifiMpdu> item = nullptr;
666
667 // if a BAR for the given agreement is present, replace it with the new one
668 while ((item = m_queue->PeekByQueueId(queueId, item)))
669 {
670 if (item->GetHeader().IsBlockAckReq() && item->GetHeader().GetAddr1() == hdr.GetAddr1())
671 {
672 CtrlBAckRequestHeader otherHdr;
673 item->GetPacket()->PeekHeader(otherHdr);
674 if (otherHdr.GetTidInfo() == tid)
675 {
676 auto bar = Create<WifiMpdu>(pkt, hdr, item->GetTimestamp());
677 // replace item with bar
678 m_queue->Replace(item, bar);
679 return;
680 }
681 }
682 }
683
684 m_queue->Enqueue(Create<WifiMpdu>(pkt, hdr));
685}
686
687const std::list<BlockAckManager::AgreementKey>&
692
693void
695{
696 NS_LOG_FUNCTION(this << recipient << tid);
697 // do nothing if the given pair is already in the list
698 if (std::find(m_sendBarIfDataQueued.begin(),
701 {
702 m_sendBarIfDataQueued.emplace_back(recipient, tid);
703 }
704}
705
706void
708{
709 NS_LOG_FUNCTION(this << recipient << tid);
710 m_sendBarIfDataQueued.remove({recipient, tid});
711}
712
713void
715{
716 NS_LOG_FUNCTION(this << recipient << tid);
717 m_blockAckInactivityTimeout(recipient, tid, true);
718}
719
720void
722{
723 NS_LOG_FUNCTION(this << recipient << tid);
724 auto it = m_originatorAgreements.find({recipient, tid});
726 if (!it->second.first.IsRejected())
727 {
729 recipient,
730 tid,
732 }
733 it->second.first.SetState(OriginatorBlockAckAgreement::REJECTED);
734 m_unblockPackets(recipient, tid);
735}
736
737void
739{
740 NS_LOG_FUNCTION(this << recipient << tid);
741 auto it = m_originatorAgreements.find({recipient, tid});
743 if (!it->second.first.IsNoReply())
744 {
746 recipient,
747 tid,
749 }
750 it->second.first.SetState(OriginatorBlockAckAgreement::NO_REPLY);
751 m_unblockPackets(recipient, tid);
752}
753
754void
756{
757 NS_LOG_FUNCTION(this << recipient << tid);
758 auto it = m_originatorAgreements.find({recipient, tid});
760 if (!it->second.first.IsReset())
761 {
763 recipient,
764 tid,
766 }
767 it->second.first.SetState(OriginatorBlockAckAgreement::RESET);
768}
769
770void
772{
773 NS_LOG_FUNCTION(this << queue);
774 m_queue = queue;
775}
776
777bool
779{
780 auto it = m_originatorAgreements.find({recipient, tid});
781 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
782 {
783 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
784 // has destroyed the agreement, hence we get here and correctly return false
785 return false;
786 }
787
788 Time now = Simulator::Now();
789
790 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
791 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
792 {
793 // remove MPDU if old or with expired lifetime
794 mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
795
796 if (mpduIt != it->second.second.begin())
797 {
798 // the MPDU has not been removed
799 return true;
800 }
801 }
802
803 return false;
804}
805
806void
812
813void
819
820void
826
827void
829{
830 m_txOkCallback = callback;
831}
832
833void
838
839void
844
845uint16_t
846BlockAckManager::GetRecipientBufferSize(const Mac48Address& recipient, uint8_t tid) const
847{
848 uint16_t size = 0;
849 auto it = m_originatorAgreements.find({recipient, tid});
850 if (it != m_originatorAgreements.end())
851 {
852 size = it->second.first.GetBufferSize();
853 }
854 return size;
855}
856
857uint16_t
859{
860 uint16_t seqNum = 0;
861 auto it = m_originatorAgreements.find({recipient, tid});
862 if (it != m_originatorAgreements.end())
863 {
864 seqNum = it->second.first.GetStartingSequence();
865 }
866 return seqNum;
867}
868
869} // namespace ns3
uint16_t GetTimeout() const
Return the timeout.
void SetGcrGroupAddress(const Mac48Address &gcrGroupAddress)
Set the GCR group address for this agreement.
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)
RecipientAgreementOptConstRef GetAgreementAsRecipient(const Mac48Address &originator, uint8_t tid) const
std::pair< Mac48Address, uint8_t > AgreementKey
agreement key typedef (MAC address and TID)
void UpdateOriginatorAgreement(const MgtAddBaResponseHeader &respHdr, const Mac48Address &recipient, uint16_t startingSeq)
Callback< void, Mac48Address, uint8_t > m_unblockPackets
unblock packets callback
OriginatorAgreements::iterator OriginatorAgreementsI
typedef for an iterator for Agreements
void SetQueue(const Ptr< WifiMacQueue > queue)
void DestroyRecipientAgreement(const Mac48Address &originator, uint8_t tid)
Destroy a recipient Block Ack agreement.
void SetTxOkCallback(TxOk callback)
void InactivityTimeout(const Mac48Address &recipient, uint8_t tid)
Inactivity timeout function.
uint8_t m_blockAckThreshold
block ack threshold
std::list< Ptr< WifiMpdu > > PacketQueue
typedef for a list of WifiMpdu.
RecipientAgreements m_recipientAgreements
Recipient Block Ack agreements.
static TypeId GetTypeId()
Get the type ID.
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_originatorAgreementState
The trace source fired when a state transition occurred.
void SetBlockAckThreshold(uint8_t nPackets)
DroppedOldMpdu m_droppedOldMpduCallback
the dropped MPDU callback
void SetDroppedOldMpduCallback(DroppedOldMpdu callback)
TxFailed m_txFailedCallback
transmit failed callback
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
std::optional< std::reference_wrapper< const OriginatorBlockAckAgreement > > OriginatorAgreementOptConstRef
optional const reference to OriginatorBlockAckAgreement
void NotifyOriginatorAgreementRejected(const Mac48Address &recipient, uint8_t tid)
Ptr< WifiMacQueue > m_queue
queue
uint16_t GetRecipientBufferSize(const Mac48Address &recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void CreateOriginatorAgreement(const MgtAddBaRequestHeader &reqHdr, const Mac48Address &recipient)
void CreateRecipientAgreement(const MgtAddBaResponseHeader &respHdr, const Mac48Address &originator, uint16_t startingSeq, Ptr< MacRxMiddle > rxMiddle)
void NotifyOriginatorAgreementNoReply(const Mac48Address &recipient, uint8_t tid)
void NotifyMissedBlockAck(uint8_t linkId, const Mac48Address &recipient, uint8_t tid)
OriginatorAgreements m_originatorAgreements
This data structure contains, for each originator block ack agreement (recipient, TID),...
void StorePacket(Ptr< WifiMpdu > mpdu)
void NotifyOriginatorAgreementReset(const Mac48Address &recipient, uint8_t tid)
void RemoveFromSendBarIfDataQueuedList(const Mac48Address &recipient, uint8_t tid)
Remove the given (recipient, TID) pair from the list of BA agreements for which a BAR shall only be s...
void NotifyGotAck(uint8_t linkId, Ptr< const WifiMpdu > mpdu)
Invoked upon receipt of an Ack frame on the given link after the transmission of a QoS data frame sen...
void AddToSendBarIfDataQueuedList(const Mac48Address &recipient, uint8_t tid)
Add the given (recipient, TID) pair to the list of BA agreements for which a BAR shall only be sent i...
void NotifyDiscardedMpdu(Ptr< const WifiMpdu > mpdu)
void NotifyGotMpdu(Ptr< const WifiMpdu > mpdu)
bool NeedBarRetransmission(uint8_t tid, const Mac48Address &recipient)
This function returns true if a block ack agreement is established with the given recipient for the g...
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
std::list< Ptr< WifiMpdu > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
std::list< AgreementKey > m_sendBarIfDataQueued
list of BA agreements for which a BAR shall only be sent if data is queued
uint32_t GetNBufferedPackets(const Mac48Address &recipient, uint8_t tid) const
PacketQueueI HandleInFlightMpdu(uint8_t linkId, PacketQueueI mpduIt, MpduStatus status, const OriginatorAgreementsI &it, const Time &now)
Handle the given in flight MPDU based on its given status.
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
uint16_t GetOriginatorStartingSequence(const Mac48Address &recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
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.
std::pair< uint16_t, uint16_t > NotifyGotBlockAck(uint8_t linkId, const CtrlBAckResponseHeader &blockAck, const Mac48Address &recipient, const std::set< uint8_t > &tids, size_t index=0)
void DoDispose() override
Destructor implementation.
std::optional< std::reference_wrapper< const RecipientBlockAckAgreement > > RecipientAgreementOptConstRef
optional const reference to RecipientBlockAckAgreement
void ScheduleBar(const CtrlBAckRequestHeader &reqHdr, const WifiMacHeader &hdr)
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
void DestroyOriginatorAgreement(const Mac48Address &recipient, uint8_t tid)
OriginatorAgreementOptConstRef GetAgreementAsOriginator(const Mac48Address &recipient, uint8_t tid) const
CtrlBAckRequestHeader GetBlockAckReqHeader(const Mac48Address &recipient, uint8_t tid) const
const std::list< AgreementKey > & GetSendBarIfDataQueuedList() const
void NotifyGotBlockAckRequest(const Mac48Address &originator, uint8_t tid, uint16_t startingSeq)
void NotifyMissedAck(uint8_t linkId, Ptr< WifiMpdu > mpdu)
Invoked upon missed reception of an Ack frame on the given link after the transmission of a QoS data ...
Callback template class.
Definition callback.h:422
bool IsNull() const
Check for null implementation.
Definition callback.h:555
Headers for BlockAckRequest.
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.
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 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...
an EUI-48 address
Implement the header for management frames of type Add Block Ack request.
std::optional< Mac48Address > GetGcrGroupAddress() const
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.
uint16_t GetBufferSize() const
Return the buffer size.
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
std::optional< Mac48Address > GetGcrGroupAddress() const
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:78
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.
void InitTxWindow()
Initialize the originator's transmit window by setting its size and starting sequence number equal to...
Smart pointer class similar to boost::intrusive_ptr.
Maintains the scoreboard and the receive reordering buffer used by a recipient of a Block Ack agreeme...
void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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.
virtual 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 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:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1368
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:156
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:188
std:: tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:192
@ WIFI_MAC_CTL_BACKREQ
ns3::Time timeout