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
67 uint8_t tid,
68 std::optional<Mac48Address> gcrGroupAddr)
69{
70 auto [first, last] = m_originatorAgreements.equal_range({recipient, tid});
71 for (auto it = first; it != last; ++it)
72 {
73 [[maybe_unused]] const auto& [baAgreement, packetQueue] = it->second;
74 if (baAgreement.GetGcrGroupAddress() == gcrGroupAddr)
75 {
76 return it;
77 }
78 }
79 return m_originatorAgreements.end();
80}
81
84 uint8_t tid,
85 std::optional<Mac48Address> gcrGroupAddr) const
86{
87 const auto [first, last] = m_originatorAgreements.equal_range({recipient, tid});
88 for (auto it = first; it != last; ++it)
89 {
90 [[maybe_unused]] const auto& [baAgreement, packetQueue] = it->second;
91 if (baAgreement.GetGcrGroupAddress() == gcrGroupAddr)
92 {
93 return it;
94 }
95 }
96 return m_originatorAgreements.cend();
97}
98
101 uint8_t tid,
102 std::optional<Mac48Address> gcrGroupAddr)
103{
104 auto [first, last] = m_recipientAgreements.equal_range({originator, tid});
105 for (auto it = first; it != last; ++it)
106 {
107 if (it->second.GetGcrGroupAddress() == gcrGroupAddr)
108 {
109 return it;
110 }
111 }
112 return m_recipientAgreements.end();
113}
114
117 uint8_t tid,
118 std::optional<Mac48Address> gcrGroupAddr) const
119{
120 const auto [first, last] = m_recipientAgreements.equal_range({originator, tid});
121 for (auto it = first; it != last; ++it)
122 {
123 if (it->second.GetGcrGroupAddress() == gcrGroupAddr)
124 {
125 return it;
126 }
127 }
128 return m_recipientAgreements.cend();
129}
130
133 uint8_t tid,
134 std::optional<Mac48Address> gcrGroupAddr) const
135{
136 if (const auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
137 it != m_originatorAgreements.cend())
138 {
139 return std::cref(it->second.first);
140 }
141 return std::nullopt;
142}
143
146 uint8_t tid,
147 std::optional<Mac48Address> gcrGroupAddr) const
148{
149 if (const auto it = GetRecipientBaAgreement(originator, tid, gcrGroupAddr);
150 it != m_recipientAgreements.end())
151 {
152 return std::cref(it->second);
153 }
154 return std::nullopt;
155}
156
157void
159 const Mac48Address& recipient)
160{
161 NS_LOG_FUNCTION(this << reqHdr << recipient);
162 const auto tid = reqHdr.GetTid();
163
164 OriginatorBlockAckAgreement agreement(recipient, tid);
165 agreement.SetStartingSequence(reqHdr.GetStartingSequence());
166 /* For now we assume that originator doesn't use this field. Use of this field
167 is mandatory only for recipient */
168 agreement.SetBufferSize(reqHdr.GetBufferSize());
169 agreement.SetTimeout(reqHdr.GetTimeout());
170 agreement.SetAmsduSupport(reqHdr.IsAmsduSupported());
171 agreement.SetHtSupported(true);
172 if (reqHdr.IsImmediateBlockAck())
173 {
174 agreement.SetImmediateBlockAck();
175 }
176 else
177 {
178 agreement.SetDelayedBlockAck();
179 }
180 if (const auto gcrGroupAddr = reqHdr.GetGcrGroupAddress())
181 {
182 agreement.SetGcrGroupAddress(*gcrGroupAddr);
183 }
185
187 recipient,
188 tid,
190
191 if (auto it = GetOriginatorBaAgreement(recipient, tid, reqHdr.GetGcrGroupAddress());
192 it != m_originatorAgreements.end())
193 {
194 NS_ASSERT_MSG(it->second.first.IsReset(), "Existing agreement must be in RESET state");
195 it->second = std::make_pair(std::move(agreement), PacketQueue{});
196 }
197 else
198 {
199 m_originatorAgreements.emplace(std::make_pair(recipient, tid),
200 std::make_pair(std::move(agreement), PacketQueue{}));
201 }
202
203 const auto [first, last] = m_originatorAgreements.equal_range({recipient, tid});
204 NS_ASSERT_MSG(std::count_if(first,
205 last,
206 [&reqHdr](const auto& elem) {
207 return elem.second.first.GetGcrGroupAddress() ==
208 reqHdr.GetGcrGroupAddress();
209 }) == 1,
210 "There exists more than one "
211 << (reqHdr.GetGcrGroupAddress().has_value() ? "GCR " : " ")
212 << "Block Ack agreement for recipient " << recipient << " and tid " << +tid);
213
214 m_blockPackets(reqHdr.GetGcrGroupAddress().value_or(recipient), tid);
215}
216
217void
219 uint8_t tid,
220 std::optional<Mac48Address> gcrGroupAddr)
221{
222 NS_LOG_FUNCTION(this << recipient << tid << gcrGroupAddr.has_value());
223 if (auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
224 it != m_originatorAgreements.end())
225 {
226 m_originatorAgreements.erase(it);
227 }
228}
229
230void
232 const Mac48Address& recipient,
233 uint16_t startingSeq)
234{
235 NS_LOG_FUNCTION(this << respHdr << recipient << startingSeq);
236 const auto tid = respHdr.GetTid();
237 if (auto it = GetOriginatorBaAgreement(recipient, tid, respHdr.GetGcrGroupAddress());
238 it != m_originatorAgreements.end())
239 {
240 OriginatorBlockAckAgreement& agreement = it->second.first;
241 agreement.SetBufferSize(respHdr.GetBufferSize());
242 agreement.SetTimeout(respHdr.GetTimeout());
243 agreement.SetAmsduSupport(respHdr.IsAmsduSupported());
244 agreement.SetStartingSequence(startingSeq);
245 agreement.InitTxWindow();
246 if (respHdr.IsImmediateBlockAck())
247 {
248 agreement.SetImmediateBlockAck();
249 }
250 else
251 {
252 agreement.SetDelayedBlockAck();
253 }
254 if (const auto gcrGroupAddr = respHdr.GetGcrGroupAddress())
255 {
256 agreement.SetGcrGroupAddress(*gcrGroupAddr);
257 m_gcrBlockAcks.emplace(*gcrGroupAddr, GcrBlockAcks{});
258 }
259 if (!it->second.first.IsEstablished())
260 {
262 recipient,
263 tid,
265 }
267 if (agreement.GetTimeout() != 0)
268 {
269 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
272 this,
273 recipient,
274 tid,
275 respHdr.GetGcrGroupAddress());
276 }
277 }
278 if (!respHdr.GetGcrGroupAddress().has_value())
279 {
280 m_unblockPackets(recipient, tid);
281 }
282 else
283 {
284 for (const auto& agreement : m_originatorAgreements)
285 {
286 if (agreement.second.first.GetGcrGroupAddress() != respHdr.GetGcrGroupAddress())
287 {
288 continue;
289 }
290 if (!agreement.second.first.IsEstablished())
291 {
292 return;
293 }
294 }
295 // established with all members so we can unblock
296 m_unblockPackets(respHdr.GetGcrGroupAddress().value(), tid);
297 }
298}
299
300void
302 const Mac48Address& originator,
303 uint16_t startingSeq,
304 Ptr<MacRxMiddle> rxMiddle)
305{
306 NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << rxMiddle);
307 const auto tid = respHdr.GetTid();
308
309 RecipientBlockAckAgreement agreement(originator,
310 respHdr.IsAmsduSupported(),
311 tid,
312 respHdr.GetBufferSize(),
313 respHdr.GetTimeout(),
314 startingSeq,
315 true);
316
317 agreement.SetMacRxMiddle(rxMiddle);
318 if (respHdr.IsImmediateBlockAck())
319 {
320 agreement.SetImmediateBlockAck();
321 }
322 else
323 {
324 agreement.SetDelayedBlockAck();
325 }
326 if (const auto gcrGroupAddr = respHdr.GetGcrGroupAddress())
327 {
328 agreement.SetGcrGroupAddress(*gcrGroupAddr);
329 }
330
331 if (auto it = GetRecipientBaAgreement(originator, tid, respHdr.GetGcrGroupAddress());
332 it != m_recipientAgreements.end())
333 {
334 it->second = std::move(agreement);
335 }
336 else
337 {
338 m_recipientAgreements.emplace(std::make_pair(originator, tid), std::move(agreement));
339 }
340
341 const auto [first, last] = m_recipientAgreements.equal_range({originator, tid});
343 std::count_if(first,
344 last,
345 [&respHdr](const auto& elem) {
346 return elem.second.GetGcrGroupAddress() == respHdr.GetGcrGroupAddress();
347 }) == 1,
348 "There exists more than one " << (respHdr.GetGcrGroupAddress().has_value() ? "GCR " : " ")
349 << "Block Ack agreement for originator " << originator
350 << " and tid " << +tid);
351}
352
353void
355 uint8_t tid,
356 std::optional<Mac48Address> gcrGroupAddr)
357{
358 NS_LOG_FUNCTION(this << originator << tid << gcrGroupAddr.has_value());
359 if (auto it = GetRecipientBaAgreement(originator, tid, gcrGroupAddr);
360 it != m_recipientAgreements.end())
361 {
362 // forward up the buffered MPDUs before destroying the agreement
363 it->second.Flush();
364 m_recipientAgreements.erase(it);
365 }
366}
367
368void
370{
371 NS_LOG_FUNCTION(this << *mpdu);
372 DoStorePacket(mpdu, mpdu->GetHeader().GetAddr1());
373}
374
375void
377{
378 NS_LOG_FUNCTION(this << *mpdu << members.size());
379 for (const auto& member : members)
380 {
381 DoStorePacket(mpdu, member, mpdu->begin()->second.GetDestinationAddr());
382 }
383}
384
385void
387 const Mac48Address& recipient,
388 std::optional<Mac48Address> gcrGroupAddr)
389{
390 NS_LOG_FUNCTION(this << *mpdu << recipient << gcrGroupAddr.has_value());
391 NS_ASSERT(mpdu->GetHeader().IsQosData());
392
393 const auto tid = mpdu->GetHeader().GetQosTid();
394 auto agreementIt = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
395 NS_ASSERT(agreementIt != m_originatorAgreements.end());
396
397 const auto mpduDist =
398 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
399
400 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
401 {
402 NS_LOG_DEBUG("Got an old packet. Do nothing");
403 return;
404 }
405
406 // store the packet and keep the list sorted in increasing order of sequence number
407 // with respect to the starting sequence number
408 auto it = agreementIt->second.second.rbegin();
409 while (it != agreementIt->second.second.rend())
410 {
411 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
412 {
413 NS_LOG_DEBUG("Packet already in the queue of the BA agreement");
414 return;
415 }
416
417 const auto dist =
418 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
419
420 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
421 (*it)->GetHeader().GetFragmentNumber()))
422 {
423 break;
424 }
425
426 it++;
427 }
428 agreementIt->second.second.insert(it.base(), mpdu);
429 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
430}
431
433BlockAckManager::GetNBufferedPackets(const Mac48Address& recipient, uint8_t tid) const
434{
435 const auto it = GetOriginatorBaAgreement(recipient, tid);
436 return (it != m_originatorAgreements.cend()) ? it->second.second.size() : 0;
437}
438
439void
441{
442 NS_LOG_FUNCTION(this << nPackets);
443 m_blockAckThreshold = nPackets;
444}
445
448 PacketQueueI mpduIt,
449 MpduStatus status,
450 const OriginatorAgreementsI& it,
451 const Time& now)
452{
453 NS_LOG_FUNCTION(this << linkId << **mpduIt << static_cast<uint8_t>(status));
454
455 if (!(*mpduIt)->IsQueued())
456 {
457 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
458 // removed by another method), remove from the queue of in flight MPDUs
459 NS_LOG_DEBUG("MPDU is not stored in the EDCA queue, drop MPDU");
460 return it->second.second.erase(mpduIt);
461 }
462
463 if (status == ACKNOWLEDGED)
464 {
465 // the MPDU has to be dequeued from the EDCA queue
466 return it->second.second.erase(mpduIt);
467 }
468
469 const WifiMacHeader& hdr = (*mpduIt)->GetHeader();
470
471 NS_ASSERT((hdr.GetAddr1() == it->first.first) || hdr.GetAddr1().IsGroup());
472 NS_ASSERT(hdr.IsQosData() && hdr.GetQosTid() == it->first.second);
473
474 if (it->second.first.GetDistance(hdr.GetSequenceNumber()) >= SEQNO_SPACE_HALF_SIZE)
475 {
476 NS_LOG_DEBUG("Old packet. Remove from the EDCA queue, too");
479 m_queue->Remove(*mpduIt);
480 return it->second.second.erase(mpduIt);
481 }
482
483 std::optional<PacketQueueI> prevIt;
484 if (mpduIt != it->second.second.begin())
485 {
486 prevIt = std::prev(mpduIt);
487 }
488
489 if (m_queue->TtlExceeded(*mpduIt, now))
490 {
491 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
492 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
493 // which removed this MPDU (and possibly others) from the in flight queue as well
494 NS_LOG_DEBUG("MSDU lifetime expired, drop MPDU");
495 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
496 }
497
498 if (status == STAY_INFLIGHT)
499 {
500 // the MPDU has to stay in flight, do nothing
501 return ++mpduIt;
502 }
503
504 NS_ASSERT(status == TO_RETRANSMIT);
505 (*mpduIt)->GetHeader().SetRetry();
506 (*mpduIt)->ResetInFlight(linkId); // no longer in flight; will be if retransmitted
507
508 return it->second.second.erase(mpduIt);
509}
510
511void
513{
514 NS_LOG_FUNCTION(this << linkId << *mpdu);
515 NS_ASSERT(mpdu->GetHeader().IsQosData());
516
517 const auto recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
518 const auto tid = mpdu->GetHeader().GetQosTid();
519
520 auto it = GetOriginatorBaAgreement(recipient, tid);
522 NS_ASSERT(it->second.first.IsEstablished());
523
524 it->second.first.NotifyAckedMpdu(mpdu);
525 if (!m_txOkCallback.IsNull())
526 {
527 m_txOkCallback(mpdu);
528 }
529
530 // remove the acknowledged frame from the queue of outstanding packets
531 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
532 {
533 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
534 {
535 m_queue->DequeueIfQueued({*queueIt});
536 HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, Simulator::Now());
537 break;
538 }
539 }
540}
541
542void
544 const GcrManager::GcrMembers& recipients)
545{
546 NS_LOG_FUNCTION(this << *mpdu << recipients.size());
547 NS_ASSERT(mpdu->GetHeader().IsQosData());
548 const auto tid = mpdu->GetHeader().GetQosTid();
549 const auto gcrGroupAddr = mpdu->GetHeader().GetAddr1();
550 for (const auto& recipient : recipients)
551 {
552 auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
554 NS_ASSERT(it->second.first.IsEstablished());
555 it->second.first.NotifyAckedMpdu(mpdu);
556 }
557}
558
559void
561{
562 NS_LOG_FUNCTION(this << linkId << *mpdu);
563 NS_ASSERT(mpdu->GetHeader().IsQosData());
564
565 const auto recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
566 const auto tid = mpdu->GetHeader().GetQosTid();
567
568 auto it = GetOriginatorBaAgreement(recipient, tid);
570 NS_ASSERT(it->second.first.IsEstablished());
571
572 // remove the frame from the queue of outstanding packets (it will be re-inserted
573 // if retransmitted)
574 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
575 {
576 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
577 {
578 HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, Simulator::Now());
579 break;
580 }
581 }
582}
583
584std::pair<uint16_t, uint16_t>
586 const CtrlBAckResponseHeader& blockAck,
587 const Mac48Address& recipient,
588 const std::set<uint8_t>& tids,
589 size_t index)
590{
591 NS_LOG_FUNCTION(this << linkId << blockAck << recipient << index);
592
593 NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
594 NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
595
596 uint8_t tid = blockAck.GetTidInfo(index);
597 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
598 // use the TID passed by the caller.
599 if (tid == 14)
600 {
601 NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
602 tid = *tids.begin();
603 }
604
605 auto it = GetOriginatorBaAgreement(recipient, tid);
606 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
607 {
608 return {0, 0};
609 }
610
611 uint16_t nSuccessfulMpdus = 0;
612 uint16_t nFailedMpdus = 0;
613
614 if (it->second.first.m_inactivityEvent.IsPending())
615 {
616 /* Upon reception of a BlockAck frame, the inactivity timer at the
617 originator must be reset.
618 For more details see section 11.5.3 in IEEE802.11e standard */
619 it->second.first.m_inactivityEvent.Cancel();
620 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
621 it->second.first.m_inactivityEvent =
624 this,
625 recipient,
626 tid,
627 std::nullopt);
628 }
629
630 NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() || blockAck.IsMultiSta());
631 Time now = Simulator::Now();
632 std::list<Ptr<const WifiMpdu>> acked;
633
634 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
635 {
636 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
637 NS_LOG_DEBUG("Current seq=" << currentSeq);
638 if (blockAck.IsPacketReceived(currentSeq, index))
639 {
640 it->second.first.NotifyAckedMpdu(*queueIt);
641 nSuccessfulMpdus++;
642 if (!m_txOkCallback.IsNull())
643 {
644 m_txOkCallback(*queueIt);
645 }
646 acked.emplace_back(*queueIt);
647 queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
648 }
649 else
650 {
651 ++queueIt;
652 }
653 }
654
655 // Dequeue all acknowledged MPDUs at once
656 m_queue->DequeueIfQueued(acked);
657
658 // Remaining outstanding MPDUs have not been acknowledged
659 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
660 {
661 // transmission actually failed if the MPDU is inflight only on the same link on
662 // which we received the BlockAck frame
663 auto linkIds = (*queueIt)->GetInFlightLinkIds();
664
665 if (linkIds.size() == 1 && *linkIds.begin() == linkId)
666 {
667 nFailedMpdus++;
669 {
670 m_txFailedCallback(*queueIt);
671 }
672 queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
673 continue;
674 }
675
676 queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now);
677 }
678
679 return {nSuccessfulMpdus, nFailedMpdus};
680}
681
682std::optional<std::pair<uint16_t, uint16_t>>
684 const CtrlBAckResponseHeader& blockAck,
685 const Mac48Address& recipient,
686 const GcrManager::GcrMembers& members)
687{
688 NS_LOG_FUNCTION(this << linkId << blockAck << recipient);
689 NS_ABORT_MSG_IF(!blockAck.IsGcr(), "GCR Block Ack is expected");
690 NS_ABORT_MSG_IF(members.count(recipient) == 0,
691 "Received GCR Block Ack response from unexpected recipient");
692
693 const auto tid = blockAck.GetTidInfo();
694 auto it = GetOriginatorBaAgreement(recipient, tid, blockAck.GetGcrGroupAddress());
695 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
696 {
697 return {};
698 }
699
700 NS_ASSERT_MSG(it->second.first.GetGcrGroupAddress().has_value() &&
701 it->second.first.GetGcrGroupAddress().value() ==
702 blockAck.GetGcrGroupAddress(),
703 "No GCR agreement for group address " << blockAck.GetGcrGroupAddress());
704 if (it->second.first.m_inactivityEvent.IsPending())
705 {
706 /* Upon reception of a BlockAck frame, the inactivity timer at the
707 originator must be reset.
708 For more details see section 11.5.3 in IEEE802.11e standard */
709 it->second.first.m_inactivityEvent.Cancel();
710 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
711 it->second.first.m_inactivityEvent =
714 this,
715 recipient,
716 tid,
717 blockAck.GetGcrGroupAddress());
718 }
719
720 auto itGcrBlockAcks = m_gcrBlockAcks.find(blockAck.GetGcrGroupAddress());
721 NS_ASSERT(itGcrBlockAcks != m_gcrBlockAcks.end());
722 NS_ASSERT(itGcrBlockAcks->second.count(recipient) == 0);
723 itGcrBlockAcks->second[recipient] = blockAck;
724
725 if (itGcrBlockAcks->second.size() < members.size())
726 {
727 // we need to collect feedback from all members
728 NS_LOG_DEBUG("Expecting more GCR Block ACK(s)");
729 return {};
730 }
731
732 std::vector<bool> acked;
733 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
734 {
735 auto currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
736 NS_LOG_DEBUG("Current seq=" << currentSeq);
737 auto received = true;
738 for ([[maybe_unused]] const auto& [recipient, gcrBlockAcks] : itGcrBlockAcks->second)
739 {
740 received &= gcrBlockAcks.IsPacketReceived(currentSeq, 0);
741 }
742 acked.emplace_back(received);
743 }
744
745 uint16_t nSuccessfulMpdus = 0;
746 uint16_t nFailedMpdus = 0;
747 const auto now = Simulator::Now();
748 std::list<Ptr<const WifiMpdu>> ackedMpdus;
749 auto countAndNotify = true;
750 for (const auto& member : members)
751 {
752 std::size_t index = 0;
753 it = GetOriginatorBaAgreement(member, tid, blockAck.GetGcrGroupAddress());
754 NS_ASSERT(acked.size() == it->second.second.size());
755 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
756 {
757 if (acked.at(index++))
758 {
759 it->second.first.NotifyAckedMpdu(*queueIt);
760 if (countAndNotify)
761 {
762 nSuccessfulMpdus++;
763 if (!m_txOkCallback.IsNull())
764 {
765 m_txOkCallback(*queueIt);
766 }
767 ackedMpdus.emplace_back(*queueIt);
768 }
769 queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
770 }
771 else
772 {
773 ++queueIt;
774 }
775 }
776 countAndNotify = false;
777 }
778
779 // Dequeue all acknowledged MPDUs at once
780 m_queue->DequeueIfQueued(ackedMpdus);
781
782 // Remaining outstanding MPDUs have not been acknowledged
783 countAndNotify = true;
784 for (const auto& member : members)
785 {
786 it = GetOriginatorBaAgreement(member, tid, blockAck.GetGcrGroupAddress());
787 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
788 {
789 // transmission actually failed if the MPDU is inflight only on the same link on
790 // which we received the BlockAck frame
791 auto linkIds = (*queueIt)->GetInFlightLinkIds();
792
793 if (linkIds.size() == 1 && *linkIds.begin() == linkId)
794 {
795 if (countAndNotify)
796 {
797 nFailedMpdus++;
799 {
800 m_txFailedCallback(*queueIt);
801 }
802 }
803 queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
804 continue;
805 }
806
807 queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now);
808 }
809 countAndNotify = false;
810 }
811
812 itGcrBlockAcks->second.clear();
813 return std::make_pair(nSuccessfulMpdus, nFailedMpdus);
814}
815
816void
817BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, const Mac48Address& recipient, uint8_t tid)
818{
819 NS_LOG_FUNCTION(this << linkId << recipient << tid);
820
821 auto it = GetOriginatorBaAgreement(recipient, tid);
822 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
823 {
824 return;
825 }
826
827 const auto now = Simulator::Now();
828
829 // remove all packets from the queue of outstanding packets (they will be
830 // re-inserted if retransmitted)
831 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
832 {
833 // MPDUs that were transmitted on another link shall stay inflight
834 auto linkIds = (*mpduIt)->GetInFlightLinkIds();
835 if (!linkIds.contains(linkId))
836 {
837 mpduIt = HandleInFlightMpdu(linkId, mpduIt, STAY_INFLIGHT, it, now);
838 continue;
839 }
840 mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
841 }
842}
843
844void
846{
847 NS_LOG_FUNCTION(this << *mpdu);
848 if (!mpdu->GetHeader().IsQosData())
849 {
850 NS_LOG_DEBUG("Not a QoS Data frame");
851 return;
852 }
853
854 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
855 {
856 NS_LOG_DEBUG("This frame has never been transmitted");
857 return;
858 }
859
860 const auto recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
861 const auto tid = mpdu->GetHeader().GetQosTid();
862 if (!recipient.IsGroup())
863 {
864 auto it = GetOriginatorBaAgreement(recipient, tid);
865 HandleDiscardedMpdu(mpdu, it);
866 }
867 else
868 {
869 const auto groupAddress = mpdu->GetOriginal()->GetHeader().GetAddr1();
870 for (auto it = m_originatorAgreements.begin(); it != m_originatorAgreements.end(); ++it)
871 {
872 if (it->first.second != tid || !it->second.first.GetGcrGroupAddress().has_value() ||
873 it->second.first.GetGcrGroupAddress().value() != groupAddress)
874 {
875 continue;
876 }
877 HandleDiscardedMpdu(mpdu, it);
878 }
879 }
880}
881
882void
884{
885 if (iter == m_originatorAgreements.end() || !iter->second.first.IsEstablished())
886 {
887 NS_LOG_DEBUG("No established Block Ack agreement");
888 return;
889 }
890
891 auto& [baAgreement, packetQueue] = iter->second;
892 if (const auto currStartingSeq = baAgreement.GetStartingSequence();
893 QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
894 {
895 NS_LOG_DEBUG("Discarded an old frame");
896 return;
897 }
898
899 // actually advance the transmit window
900 baAgreement.NotifyDiscardedMpdu(mpdu);
901
902 // remove old MPDUs from the EDCA queue and from the in flight queue
903 // (including the given MPDU which became old after advancing the transmit window)
904 for (auto mpduIt = iter->second.second.begin(); mpduIt != iter->second.second.end();)
905 {
906 if (baAgreement.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
908 {
909 NS_LOG_DEBUG("Dropping old MPDU: " << **mpduIt);
910 m_queue->DequeueIfQueued({*mpduIt});
912 {
914 }
915 mpduIt = packetQueue.erase(mpduIt);
916 }
917 else
918 {
919 break; // MPDUs are in increasing order of sequence number in the in flight queue
920 }
921 }
922
923 // schedule a BlockAckRequest
924 const auto [recipient, tid] = iter->first;
925 NS_LOG_DEBUG("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid
926 << ")");
927
928 WifiMacHeader hdr;
930 hdr.SetAddr1(recipient);
931 hdr.SetAddr2(mpdu->GetOriginal()->GetHeader().GetAddr2());
932 hdr.SetDsNotTo();
933 hdr.SetDsNotFrom();
934 hdr.SetNoRetry();
935 hdr.SetNoMoreFragments();
936
937 ScheduleBar(GetBlockAckReqHeader(recipient, tid, baAgreement.GetGcrGroupAddress()), hdr);
938}
939
940void
942 uint8_t tid,
943 uint16_t startingSeq,
944 std::optional<Mac48Address> gcrGroupAddr)
945{
946 NS_LOG_FUNCTION(this << originator << tid << startingSeq << gcrGroupAddr.has_value());
947 if (auto it = GetRecipientBaAgreement(originator, tid, gcrGroupAddr);
948 it != m_recipientAgreements.end())
949 {
950 it->second.NotifyReceivedBar(startingSeq);
951 }
952}
953
954void
956{
957 NS_LOG_FUNCTION(this << *mpdu);
958 NS_ASSERT(mpdu->GetHeader().IsQosData());
959 const auto originator = mpdu->GetOriginal()->GetHeader().GetAddr2();
960 const auto tid = mpdu->GetHeader().GetQosTid();
961 std::optional<Mac48Address> groupAddress;
962 if (const auto addr1 = mpdu->GetOriginal()->GetHeader().GetAddr1(); addr1.IsGroup())
963 {
964 groupAddress =
965 mpdu->GetHeader().IsQosAmsdu() ? mpdu->begin()->second.GetDestinationAddr() : addr1;
966 }
967 if (auto it = GetRecipientBaAgreement(originator, tid, groupAddress);
968 it != m_recipientAgreements.end())
969 {
970 it->second.NotifyReceivedMpdu(mpdu);
971 }
972}
973
976 uint8_t tid,
977 std::optional<Mac48Address> gcrGroupAddr) const
978{
979 auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
982 if (gcrGroupAddr.has_value())
983 {
985 reqHdr.SetGcrGroupAddress(gcrGroupAddr.value());
986 }
987 else
988 {
989 reqHdr.SetType((*it).second.first.GetBlockAckReqType());
990 }
991 reqHdr.SetTidInfo(tid);
992 reqHdr.SetStartingSequence((*it).second.first.GetStartingSequence());
993 return reqHdr;
994}
995
996void
998{
999 NS_LOG_FUNCTION(this << reqHdr << hdr);
1000
1001 uint8_t tid = reqHdr.GetTidInfo();
1002
1003 WifiContainerQueueId queueId(WIFI_CTL_QUEUE, WIFI_UNICAST, hdr.GetAddr1(), std::nullopt);
1004 auto pkt = Create<Packet>();
1005 pkt->AddHeader(reqHdr);
1006 Ptr<WifiMpdu> item = nullptr;
1007
1008 // if a BAR for the given agreement is present, replace it with the new one
1009 while ((item = m_queue->PeekByQueueId(queueId, item)))
1010 {
1011 if (item->GetHeader().IsBlockAckReq() && item->GetHeader().GetAddr1() == hdr.GetAddr1())
1012 {
1013 CtrlBAckRequestHeader otherHdr;
1014 item->GetPacket()->PeekHeader(otherHdr);
1015 if (otherHdr.GetTidInfo() == tid)
1016 {
1017 auto bar = Create<WifiMpdu>(pkt, hdr, item->GetTimestamp());
1018 // replace item with bar
1019 m_queue->Replace(item, bar);
1020 return;
1021 }
1022 }
1023 }
1024
1025 m_queue->Enqueue(Create<WifiMpdu>(pkt, hdr));
1026}
1027
1028const std::list<BlockAckManager::AgreementKey>&
1033
1034void
1036{
1037 NS_LOG_FUNCTION(this << recipient << tid);
1038 // do nothing if the given pair is already in the list
1039 if (std::find(m_sendBarIfDataQueued.begin(),
1041 BlockAckManager::AgreementKey{recipient, tid}) == m_sendBarIfDataQueued.end())
1042 {
1043 m_sendBarIfDataQueued.emplace_back(recipient, tid);
1044 }
1045}
1046
1047void
1049{
1050 NS_LOG_FUNCTION(this << recipient << tid);
1051 m_sendBarIfDataQueued.remove({recipient, tid});
1052}
1053
1054void
1056 uint8_t tid,
1057 std::optional<Mac48Address> gcrGroupAddr)
1058{
1059 NS_LOG_FUNCTION(this << recipient << tid << gcrGroupAddr.has_value());
1060 m_blockAckInactivityTimeout(recipient, tid, true, gcrGroupAddr);
1061}
1062
1063void
1065 uint8_t tid,
1066 std::optional<Mac48Address> gcrGroupAddr)
1067{
1068 NS_LOG_FUNCTION(this << recipient << tid << gcrGroupAddr.has_value());
1069 auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
1070 NS_ASSERT(it != m_originatorAgreements.end());
1071 if (!it->second.first.IsRejected())
1072 {
1074 recipient,
1075 tid,
1077 }
1078 it->second.first.SetState(OriginatorBlockAckAgreement::REJECTED);
1079 if (!gcrGroupAddr.has_value())
1080 {
1081 m_unblockPackets(recipient, tid);
1082 }
1083}
1084
1085void
1087 uint8_t tid,
1088 std::optional<Mac48Address> gcrGroupAddr)
1089{
1090 NS_LOG_FUNCTION(this << recipient << tid << gcrGroupAddr.has_value());
1091 auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
1092 NS_ASSERT(it != m_originatorAgreements.end());
1093 if (!it->second.first.IsNoReply())
1094 {
1096 recipient,
1097 tid,
1099 }
1100 it->second.first.SetState(OriginatorBlockAckAgreement::NO_REPLY);
1101 if (!gcrGroupAddr.has_value())
1102 {
1103 m_unblockPackets(recipient, tid);
1104 }
1105}
1106
1107void
1109 uint8_t tid,
1110 std::optional<Mac48Address> gcrGroupAddr)
1111{
1112 NS_LOG_FUNCTION(this << recipient << tid << gcrGroupAddr.has_value());
1113 auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddr);
1114 NS_ASSERT(it != m_originatorAgreements.end());
1115 if (!it->second.first.IsReset())
1116 {
1118 recipient,
1119 tid,
1121 }
1122 it->second.first.SetState(OriginatorBlockAckAgreement::RESET);
1123 if (gcrGroupAddr.has_value())
1124 {
1125 m_unblockPackets(gcrGroupAddr.value(), tid);
1126 }
1127}
1128
1129void
1131{
1132 NS_LOG_FUNCTION(this << queue);
1133 m_queue = queue;
1134}
1135
1136bool
1138{
1139 auto it = GetOriginatorBaAgreement(recipient, tid);
1140 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
1141 {
1142 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
1143 // has destroyed the agreement, hence we get here and correctly return false
1144 return false;
1145 }
1146
1147 const auto now = Simulator::Now();
1148
1149 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
1150 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
1151 {
1152 // remove MPDU if old or with expired lifetime
1153 mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
1154
1155 if (mpduIt != it->second.second.begin())
1156 {
1157 // the MPDU has not been removed
1158 return true;
1159 }
1160 }
1161
1162 return false;
1163}
1164
1165bool
1167 const Mac48Address& recipient,
1168 uint8_t tid) const
1169{
1170 const auto it = GetOriginatorBaAgreement(recipient, tid, gcrGroupAddress);
1171 return (it != m_originatorAgreements.cend() && it->second.first.IsEstablished());
1172}
1173
1174void
1176 Callback<void, Mac48Address, uint8_t, bool, std::optional<Mac48Address>> callback)
1177{
1178 NS_LOG_FUNCTION(this << &callback);
1179 m_blockAckInactivityTimeout = callback;
1180}
1181
1182void
1188
1189void
1195
1196void
1198{
1199 m_txOkCallback = callback;
1200}
1201
1202void
1207
1208void
1213
1214uint16_t
1215BlockAckManager::GetRecipientBufferSize(const Mac48Address& recipient, uint8_t tid) const
1216{
1217 const auto it = GetOriginatorBaAgreement(recipient, tid);
1218 return (it != m_originatorAgreements.cend()) ? it->second.first.GetBufferSize() : 0;
1219}
1220
1221uint16_t
1223{
1224 const auto it = GetOriginatorBaAgreement(recipient, tid);
1225 return (it != m_originatorAgreements.cend()) ? it->second.first.GetStartingSequence() : 0;
1226}
1227
1228uint16_t
1229BlockAckManager::GetGcrStartingSequence(const Mac48Address& groupAddress, uint8_t tid) const
1230{
1231 uint16_t seqNum = 0;
1232 for (const auto& [key, pair] : m_originatorAgreements)
1233 {
1234 if (key.second != tid)
1235 {
1236 continue;
1237 }
1238 if (pair.first.GetGcrGroupAddress() == groupAddress)
1239 {
1240 seqNum = pair.first.GetStartingSequence();
1241 break;
1242 }
1243 }
1244 return seqNum;
1245}
1246
1247uint16_t
1248BlockAckManager::GetGcrBufferSize(const Mac48Address& groupAddress, uint8_t tid) const
1249{
1250 /* The AP shall maintain a set of the most recently received values of the
1251 Buffer Size subfield from the Block Ack Parameter Set field in the ADDBA
1252 Response frame received from each member of a specific group address.
1253 The minimum of that set of values is defined to be the GCR buffer size
1254 for that group address. */
1255 uint16_t gcrBufferSize = std::numeric_limits<uint16_t>::max();
1256 for (const auto& [key, pair] : m_originatorAgreements)
1257 {
1258 if ((key.second == tid) && (pair.first.GetGcrGroupAddress() == groupAddress))
1259 {
1260 gcrBufferSize = std::min(pair.first.GetBufferSize(), gcrBufferSize);
1261 }
1262 }
1263 return gcrBufferSize;
1264}
1265
1266bool
1268 uint8_t tid,
1269 const GcrManager::GcrMembers& members) const
1270{
1271 NS_ASSERT(!members.empty());
1272 for (const auto& member : members)
1273 {
1274 if (const auto agreement = GetAgreementAsOriginator(member, tid, gcrGroupAddress);
1275 !agreement || !agreement->get().IsEstablished())
1276 {
1277 return false;
1278 }
1279 }
1280 return true;
1281}
1282
1283} // 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.
std::optional< std::pair< uint16_t, uint16_t > > NotifyGotGcrBlockAck(uint8_t linkId, const CtrlBAckResponseHeader &blockAck, const Mac48Address &recipient, const GcrManager::GcrMembers &members)
void SetTxFailedCallback(TxFailed callback)
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
An iterator for originator block ack agreements.
void SetQueue(const Ptr< WifiMacQueue > queue)
void SetTxOkCallback(TxOk callback)
std::map< Mac48Address, CtrlBAckResponseHeader > GcrBlockAcks
List of received GCR BlockAck frames indexed by originator.
OriginatorAgreementsI GetOriginatorBaAgreement(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
CtrlBAckRequestHeader GetBlockAckReqHeader(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt) const
void NotifyOriginatorAgreementNoReply(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
uint8_t m_blockAckThreshold
block ack threshold
void NotifyLastGcrUrTx(Ptr< const WifiMpdu > mpdu, const GcrManager::GcrMembers &recipients)
Notify the block ack manager about the last groupcast MPDU transmitted with the GCR-UR service.
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
std::list< Ptr< WifiMpdu > > PacketQueue
typedef for a list of WifiMpdu.
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
Ptr< WifiMacQueue > m_queue
queue
RecipientAgreements::iterator RecipientAgreementsI
An iterator for recipient block ack agreements.
uint16_t GetRecipientBufferSize(const Mac48Address &recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void NotifyOriginatorAgreementRejected(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
void CreateOriginatorAgreement(const MgtAddBaRequestHeader &reqHdr, const Mac48Address &recipient)
void CreateRecipientAgreement(const MgtAddBaResponseHeader &respHdr, const Mac48Address &originator, uint16_t startingSeq, Ptr< MacRxMiddle > rxMiddle)
Callback< void, Mac48Address, uint8_t, bool, std::optional< Mac48Address > > m_blockAckInactivityTimeout
BlockAck inactivity timeout callback.
OriginatorAgreements::const_iterator OriginatorAgreementsCI
A const iterator for originator block ack agreements.
void DestroyOriginatorAgreement(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
bool NeedGcrBarRetransmission(const Mac48Address &gcrGroupAddress, const Mac48Address &recipient, uint8_t tid) const
This function returns true if a GCR block ack agreement is established with the given recipient,...
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 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)
bool IsGcrAgreementEstablished(const Mac48Address &gcrGroupAddress, uint8_t tid, const GcrManager::GcrMembers &members) const
Check if a GCR Block Ack agreement has been successfully established with all members of the group.
void NotifyGotMpdu(Ptr< const WifiMpdu > mpdu)
void HandleDiscardedMpdu(Ptr< const WifiMpdu > mpdu, OriginatorAgreementsI iter)
Handle discarded MPDU by making the transmit window advance beyond the discarded frame.
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.
void NotifyOriginatorAgreementReset(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
std::list< AgreementKey > m_sendBarIfDataQueued
list of BA agreements for which a BAR shall only be sent if data is queued
void DestroyRecipientAgreement(const Mac48Address &originator, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Destroy a recipient Block Ack agreement.
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.
std::list< Ptr< WifiMpdu > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool, std::optional< Mac48Address > > callback)
Set block ack inactivity callback.
OriginatorAgreementOptConstRef GetAgreementAsOriginator(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt) const
RecipientAgreements::const_iterator RecipientAgreementsCI
A const iterator for recipient block ack agreements.
uint16_t GetOriginatorStartingSequence(const Mac48Address &recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
void NotifyGotBlockAckRequest(const Mac48Address &originator, uint8_t tid, uint16_t startingSeq, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
uint16_t GetGcrStartingSequence(const Mac48Address &groupAddress, uint8_t tid) const
This function returns the starting sequence number of the transmit window for a given GCR Block Ack a...
uint16_t GetGcrBufferSize(const Mac48Address &groupAddress, uint8_t tid) const
This function returns the minimum buffer size from ADDBA Response frames sent by all members of a gro...
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)
void InactivityTimeout(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Inactivity timeout function for a Block Ack agreement.
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
void DoStorePacket(Ptr< WifiMpdu > mpdu, const Mac48Address &recipient, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
void StoreGcrPacket(Ptr< WifiMpdu > mpdu, const GcrManager::GcrMembers &members)
RecipientAgreementsI GetRecipientBaAgreement(const Mac48Address &originator, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
RecipientAgreementOptConstRef GetAgreementAsRecipient(const Mac48Address &originator, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt) const
const std::list< AgreementKey > & GetSendBarIfDataQueuedList() const
std::map< Mac48Address, GcrBlockAcks > m_gcrBlockAcks
received GCR Block ACKs
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).
void SetGcrGroupAddress(const Mac48Address &address)
Set the GCR Group address (GCR variant only).
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...
Mac48Address GetGcrGroupAddress() const
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...
std::unordered_set< Mac48Address, WifiAddressHash > GcrMembers
MAC addresses of member STAs of a GCR group.
an EUI-48 address
bool IsGroup() const
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:561
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:49
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:1369
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
Definition first.py:1
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:268
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:272
@ WIFI_MAC_CTL_BACKREQ
ns3::Time timeout