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 NS_LOG_FUNCTION(this << recipient << +tid);
69 if (auto it = m_originatorAgreements.find({recipient, tid}); it != m_originatorAgreements.end())
70 {
71 return std::cref(it->second.first);
72 }
73
74 return std::nullopt;
75}
76
78BlockAckManager::GetAgreementAsRecipient(const Mac48Address& originator, uint8_t tid) const
79{
80 NS_LOG_FUNCTION(this << originator << +tid);
81 if (auto it = m_recipientAgreements.find({originator, tid}); it != m_recipientAgreements.end())
82 {
83 return std::cref(it->second);
84 }
85
86 return std::nullopt;
87}
88
89void
91 const Mac48Address& recipient)
92{
93 NS_LOG_FUNCTION(this << reqHdr << recipient);
94 const auto tid = reqHdr.GetTid();
95
96 OriginatorBlockAckAgreement agreement(recipient, tid);
97 agreement.SetStartingSequence(reqHdr.GetStartingSequence());
98 /* For now we assume that originator doesn't use this field. Use of this field
99 is mandatory only for recipient */
100 agreement.SetBufferSize(reqHdr.GetBufferSize());
101 agreement.SetTimeout(reqHdr.GetTimeout());
102 agreement.SetAmsduSupport(reqHdr.IsAmsduSupported());
103 agreement.SetHtSupported(true);
104 if (reqHdr.IsImmediateBlockAck())
105 {
106 agreement.SetImmediateBlockAck();
107 }
108 else
109 {
110 agreement.SetDelayedBlockAck();
111 }
114 recipient,
115 tid,
117 if (auto existingAgreement = GetAgreementAsOriginator(recipient, tid))
118 {
119 NS_ASSERT_MSG(existingAgreement->get().IsReset(),
120 "Existing agreement must be in RESET state");
121 }
122 m_originatorAgreements.insert_or_assign({recipient, tid},
123 std::make_pair(std::move(agreement), PacketQueue{}));
124 m_blockPackets(recipient, tid);
125}
126
127void
129{
130 NS_LOG_FUNCTION(this << recipient << +tid);
131 auto it = m_originatorAgreements.find({recipient, tid});
132 if (it != m_originatorAgreements.end())
133 {
134 m_originatorAgreements.erase(it);
135 }
136}
137
138void
140 const Mac48Address& recipient,
141 uint16_t startingSeq)
142{
143 NS_LOG_FUNCTION(this << respHdr << recipient << startingSeq);
144 uint8_t tid = respHdr.GetTid();
145 auto it = m_originatorAgreements.find({recipient, tid});
146 if (it != m_originatorAgreements.end())
147 {
148 OriginatorBlockAckAgreement& agreement = it->second.first;
149 agreement.SetBufferSize(respHdr.GetBufferSize());
150 agreement.SetTimeout(respHdr.GetTimeout());
151 agreement.SetAmsduSupport(respHdr.IsAmsduSupported());
152 agreement.SetStartingSequence(startingSeq);
153 agreement.InitTxWindow();
154 if (respHdr.IsImmediateBlockAck())
155 {
156 agreement.SetImmediateBlockAck();
157 }
158 else
159 {
160 agreement.SetDelayedBlockAck();
161 }
162 if (!it->second.first.IsEstablished())
163 {
165 recipient,
166 tid,
168 }
170 if (agreement.GetTimeout() != 0)
171 {
172 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
175 this,
176 recipient,
177 tid);
178 }
179 }
180 m_unblockPackets(recipient, tid);
181}
182
183void
185 const Mac48Address& originator,
186 uint16_t startingSeq,
187 Ptr<MacRxMiddle> rxMiddle)
188{
189 NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << rxMiddle);
190 const auto tid = respHdr.GetTid();
191
192 RecipientBlockAckAgreement agreement(originator,
193 respHdr.IsAmsduSupported(),
194 tid,
195 respHdr.GetBufferSize(),
196 respHdr.GetTimeout(),
197 startingSeq,
198 true);
199
200 agreement.SetMacRxMiddle(rxMiddle);
201 if (respHdr.IsImmediateBlockAck())
202 {
203 agreement.SetImmediateBlockAck();
204 }
205 else
206 {
207 agreement.SetDelayedBlockAck();
208 }
209
210 m_recipientAgreements.insert_or_assign({originator, tid}, agreement);
211}
212
213void
215{
216 NS_LOG_FUNCTION(this << originator << tid);
217
218 if (auto agreementIt = m_recipientAgreements.find({originator, tid});
219 agreementIt != m_recipientAgreements.end())
220 {
221 // forward up the buffered MPDUs before destroying the agreement
222 agreementIt->second.Flush();
223 m_recipientAgreements.erase(agreementIt);
224 }
225}
226
227void
229{
230 NS_LOG_FUNCTION(this << *mpdu);
231 NS_ASSERT(mpdu->GetHeader().IsQosData());
232
233 uint8_t tid = mpdu->GetHeader().GetQosTid();
234 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
235
236 auto agreementIt = m_originatorAgreements.find({recipient, tid});
237 NS_ASSERT(agreementIt != m_originatorAgreements.end());
238
239 uint16_t mpduDist =
240 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
241
242 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
243 {
244 NS_LOG_DEBUG("Got an old packet. Do nothing");
245 return;
246 }
247
248 // store the packet and keep the list sorted in increasing order of sequence number
249 // with respect to the starting sequence number
250 auto it = agreementIt->second.second.rbegin();
251 while (it != agreementIt->second.second.rend())
252 {
253 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
254 {
255 NS_LOG_DEBUG("Packet already in the queue of the BA agreement");
256 return;
257 }
258
259 uint16_t dist =
260 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
261
262 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
263 (*it)->GetHeader().GetFragmentNumber()))
264 {
265 break;
266 }
267
268 it++;
269 }
270 agreementIt->second.second.insert(it.base(), mpdu);
271 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
272}
273
275BlockAckManager::GetNBufferedPackets(const Mac48Address& recipient, uint8_t tid) const
276{
277 NS_LOG_FUNCTION(this << recipient << +tid);
278 auto it = m_originatorAgreements.find({recipient, tid});
279 if (it == m_originatorAgreements.end())
280 {
281 return 0;
282 }
283 return it->second.second.size();
284}
285
286void
288{
289 NS_LOG_FUNCTION(this << +nPackets);
290 m_blockAckThreshold = nPackets;
291}
292
295 PacketQueueI mpduIt,
296 MpduStatus status,
297 const OriginatorAgreementsI& it,
298 const Time& now)
299{
300 NS_LOG_FUNCTION(this << linkId << **mpduIt << +static_cast<uint8_t>(status));
301
302 if (!(*mpduIt)->IsQueued())
303 {
304 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
305 // removed by another method), remove from the queue of in flight MPDUs
306 NS_LOG_DEBUG("MPDU is not stored in the EDCA queue, drop MPDU");
307 return it->second.second.erase(mpduIt);
308 }
309
310 if (status == ACKNOWLEDGED)
311 {
312 // the MPDU has to be dequeued from the EDCA queue
313 return it->second.second.erase(mpduIt);
314 }
315
316 const WifiMacHeader& hdr = (*mpduIt)->GetHeader();
317
318 NS_ASSERT(hdr.GetAddr1() == it->first.first);
319 NS_ASSERT(hdr.IsQosData() && hdr.GetQosTid() == it->first.second);
320
321 if (it->second.first.GetDistance(hdr.GetSequenceNumber()) >= SEQNO_SPACE_HALF_SIZE)
322 {
323 NS_LOG_DEBUG("Old packet. Remove from the EDCA queue, too");
326 m_queue->Remove(*mpduIt);
327 return it->second.second.erase(mpduIt);
328 }
329
330 std::optional<PacketQueueI> prevIt;
331 if (mpduIt != it->second.second.begin())
332 {
333 prevIt = std::prev(mpduIt);
334 }
335
336 if (m_queue->TtlExceeded(*mpduIt, now))
337 {
338 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
339 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
340 // which removed this MPDU (and possibly others) from the in flight queue as well
341 NS_LOG_DEBUG("MSDU lifetime expired, drop MPDU");
342 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
343 }
344
345 if (status == STAY_INFLIGHT)
346 {
347 // the MPDU has to stay in flight, do nothing
348 return ++mpduIt;
349 }
350
351 NS_ASSERT(status == TO_RETRANSMIT);
352 (*mpduIt)->GetHeader().SetRetry();
353 (*mpduIt)->ResetInFlight(linkId); // no longer in flight; will be if retransmitted
354
355 return it->second.second.erase(mpduIt);
356}
357
358void
360{
361 NS_LOG_FUNCTION(this << linkId << *mpdu);
362 NS_ASSERT(mpdu->GetHeader().IsQosData());
363
364 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
365 uint8_t tid = mpdu->GetHeader().GetQosTid();
366
367 auto it = m_originatorAgreements.find({recipient, tid});
369 NS_ASSERT(it->second.first.IsEstablished());
370
371 it->second.first.NotifyAckedMpdu(mpdu);
372
373 // remove the acknowledged frame from the queue of outstanding packets
374 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
375 {
376 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
377 {
378 m_queue->DequeueIfQueued({*queueIt});
379 HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, Simulator::Now());
380 break;
381 }
382 }
383}
384
385void
387{
388 NS_LOG_FUNCTION(this << linkId << *mpdu);
389 NS_ASSERT(mpdu->GetHeader().IsQosData());
390
391 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
392 uint8_t tid = mpdu->GetHeader().GetQosTid();
393
394 auto it = m_originatorAgreements.find({recipient, tid});
396 NS_ASSERT(it->second.first.IsEstablished());
397
398 // remove the frame from the queue of outstanding packets (it will be re-inserted
399 // if retransmitted)
400 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
401 {
402 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
403 {
404 HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, Simulator::Now());
405 break;
406 }
407 }
408}
409
410std::pair<uint16_t, uint16_t>
412 const CtrlBAckResponseHeader& blockAck,
413 const Mac48Address& recipient,
414 const std::set<uint8_t>& tids,
415 size_t index)
416{
417 NS_LOG_FUNCTION(this << linkId << blockAck << recipient << index);
418
419 NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
420 NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
421
422 uint8_t tid = blockAck.GetTidInfo(index);
423 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
424 // use the TID passed by the caller.
425 if (tid == 14)
426 {
427 NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
428 tid = *tids.begin();
429 }
430
431 auto it = m_originatorAgreements.find({recipient, tid});
432 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
433 {
434 return {0, 0};
435 }
436
437 uint16_t nSuccessfulMpdus = 0;
438 uint16_t nFailedMpdus = 0;
439
440 if (it->second.first.m_inactivityEvent.IsPending())
441 {
442 /* Upon reception of a BlockAck frame, the inactivity timer at the
443 originator must be reset.
444 For more details see section 11.5.3 in IEEE802.11e standard */
445 it->second.first.m_inactivityEvent.Cancel();
446 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
447 it->second.first.m_inactivityEvent =
449 }
450
451 NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() || blockAck.IsMultiSta());
452 Time now = Simulator::Now();
453 std::list<Ptr<const WifiMpdu>> acked;
454
455 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
456 {
457 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
458 NS_LOG_DEBUG("Current seq=" << currentSeq);
459 if (blockAck.IsPacketReceived(currentSeq, index))
460 {
461 it->second.first.NotifyAckedMpdu(*queueIt);
462 nSuccessfulMpdus++;
463 if (!m_txOkCallback.IsNull())
464 {
465 m_txOkCallback(*queueIt);
466 }
467 acked.emplace_back(*queueIt);
468 queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
469 }
470 else
471 {
472 ++queueIt;
473 }
474 }
475
476 // Dequeue all acknowledged MPDUs at once
477 m_queue->DequeueIfQueued(acked);
478
479 // Remaining outstanding MPDUs have not been acknowledged
480 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
481 {
482 // transmission actually failed if the MPDU is inflight only on the same link on
483 // which we received the BlockAck frame
484 auto linkIds = (*queueIt)->GetInFlightLinkIds();
485
486 if (linkIds.size() == 1 && *linkIds.begin() == linkId)
487 {
488 nFailedMpdus++;
490 {
491 m_txFailedCallback(*queueIt);
492 }
493 queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
494 continue;
495 }
496
497 queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now);
498 }
499
500 return {nSuccessfulMpdus, nFailedMpdus};
501}
502
503void
504BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, const Mac48Address& recipient, uint8_t tid)
505{
506 NS_LOG_FUNCTION(this << linkId << recipient << +tid);
507
508 auto it = m_originatorAgreements.find({recipient, tid});
509 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
510 {
511 return;
512 }
513
514 Time now = Simulator::Now();
515
516 // remove all packets from the queue of outstanding packets (they will be
517 // re-inserted if retransmitted)
518 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
519 {
520 // MPDUs that were transmitted on another link shall stay inflight
521 auto linkIds = (*mpduIt)->GetInFlightLinkIds();
522 if (!linkIds.contains(linkId))
523 {
524 mpduIt = HandleInFlightMpdu(linkId, mpduIt, STAY_INFLIGHT, it, now);
525 continue;
526 }
527 mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
528 }
529}
530
531void
533{
534 NS_LOG_FUNCTION(this << *mpdu);
535
536 if (!mpdu->GetHeader().IsQosData())
537 {
538 NS_LOG_DEBUG("Not a QoS Data frame");
539 return;
540 }
541
542 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
543 {
544 NS_LOG_DEBUG("This frame has never been transmitted");
545 return;
546 }
547
548 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
549 uint8_t tid = mpdu->GetHeader().GetQosTid();
550 auto it = m_originatorAgreements.find({recipient, tid});
551 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
552 {
553 NS_LOG_DEBUG("No established Block Ack agreement");
554 return;
555 }
556
557 uint16_t currStartingSeq = it->second.first.GetStartingSequence();
558 if (QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
559 {
560 NS_LOG_DEBUG("Discarded an old frame");
561 return;
562 }
563
564 // actually advance the transmit window
565 it->second.first.NotifyDiscardedMpdu(mpdu);
566
567 // remove old MPDUs from the EDCA queue and from the in flight queue
568 // (including the given MPDU which became old after advancing the transmit window)
569 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
570 {
571 if (it->second.first.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
573 {
574 NS_LOG_DEBUG("Dropping old MPDU: " << **mpduIt);
575 m_queue->DequeueIfQueued({*mpduIt});
577 {
579 }
580 mpduIt = it->second.second.erase(mpduIt);
581 }
582 else
583 {
584 break; // MPDUs are in increasing order of sequence number in the in flight queue
585 }
586 }
587
588 // schedule a BlockAckRequest
589 NS_LOG_DEBUG("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid
590 << ")");
591
592 WifiMacHeader hdr;
594 hdr.SetAddr1(recipient);
595 hdr.SetAddr2(mpdu->GetOriginal()->GetHeader().GetAddr2());
596 hdr.SetDsNotTo();
597 hdr.SetDsNotFrom();
598 hdr.SetNoRetry();
599 hdr.SetNoMoreFragments();
600
601 ScheduleBar(GetBlockAckReqHeader(recipient, tid), hdr);
602}
603
604void
606 uint8_t tid,
607 uint16_t startingSeq)
608{
609 NS_LOG_FUNCTION(this << originator << tid << startingSeq);
610 auto it = m_recipientAgreements.find({originator, tid});
611 if (it == m_recipientAgreements.end())
612 {
613 return;
614 }
615 it->second.NotifyReceivedBar(startingSeq);
616}
617
618void
620{
621 NS_LOG_FUNCTION(this << *mpdu);
622 auto originator = mpdu->GetOriginal()->GetHeader().GetAddr2();
623 NS_ASSERT(mpdu->GetHeader().IsQosData());
624 auto tid = mpdu->GetHeader().GetQosTid();
625
626 auto it = m_recipientAgreements.find({originator, tid});
627 if (it == m_recipientAgreements.end())
628 {
629 return;
630 }
631 it->second.NotifyReceivedMpdu(mpdu);
632}
633
635BlockAckManager::GetBlockAckReqHeader(const Mac48Address& recipient, uint8_t tid) const
636{
637 NS_LOG_FUNCTION(this << recipient << +tid);
638 auto it = m_originatorAgreements.find({recipient, tid});
640
642 reqHdr.SetType((*it).second.first.GetBlockAckReqType());
643 reqHdr.SetTidInfo(tid);
644 reqHdr.SetStartingSequence((*it).second.first.GetStartingSequence());
645 return reqHdr;
646}
647
648void
650{
651 NS_LOG_FUNCTION(this << reqHdr << hdr);
652
653 uint8_t tid = reqHdr.GetTidInfo();
654
655 WifiContainerQueueId queueId(WIFI_CTL_QUEUE, WIFI_UNICAST, hdr.GetAddr1(), std::nullopt);
656 auto pkt = Create<Packet>();
657 pkt->AddHeader(reqHdr);
658 Ptr<WifiMpdu> item = nullptr;
659
660 // if a BAR for the given agreement is present, replace it with the new one
661 while ((item = m_queue->PeekByQueueId(queueId, item)))
662 {
663 if (item->GetHeader().IsBlockAckReq() && item->GetHeader().GetAddr1() == hdr.GetAddr1())
664 {
665 CtrlBAckRequestHeader otherHdr;
666 item->GetPacket()->PeekHeader(otherHdr);
667 if (otherHdr.GetTidInfo() == tid)
668 {
669 auto bar = Create<WifiMpdu>(pkt, hdr, item->GetTimestamp());
670 // replace item with bar
671 m_queue->Replace(item, bar);
672 return;
673 }
674 }
675 }
676
677 m_queue->Enqueue(Create<WifiMpdu>(pkt, hdr));
678}
679
680const std::list<BlockAckManager::AgreementKey>&
685
686void
688{
689 NS_LOG_FUNCTION(this << recipient << tid);
690 // do nothing if the given pair is already in the list
691 if (std::find(m_sendBarIfDataQueued.begin(),
694 {
695 m_sendBarIfDataQueued.emplace_back(recipient, tid);
696 }
697}
698
699void
701{
702 NS_LOG_FUNCTION(this << recipient << tid);
703 m_sendBarIfDataQueued.remove({recipient, tid});
704}
705
706void
708{
709 NS_LOG_FUNCTION(this << recipient << +tid);
710 m_blockAckInactivityTimeout(recipient, tid, true);
711}
712
713void
715 uint8_t tid,
716 uint16_t startingSeq)
717{
718 NS_LOG_FUNCTION(this << recipient << +tid << startingSeq);
719 auto it = m_originatorAgreements.find({recipient, tid});
721 if (!it->second.first.IsEstablished())
722 {
724 recipient,
725 tid,
727 }
728 it->second.first.SetState(OriginatorBlockAckAgreement::ESTABLISHED);
729 it->second.first.SetStartingSequence(startingSeq);
730}
731
732void
734{
735 NS_LOG_FUNCTION(this << recipient << +tid);
736 auto it = m_originatorAgreements.find({recipient, tid});
738 if (!it->second.first.IsRejected())
739 {
741 recipient,
742 tid,
744 }
745 it->second.first.SetState(OriginatorBlockAckAgreement::REJECTED);
746 m_unblockPackets(recipient, tid);
747}
748
749void
751{
752 NS_LOG_FUNCTION(this << recipient << +tid);
753 auto it = m_originatorAgreements.find({recipient, tid});
755 if (!it->second.first.IsNoReply())
756 {
758 recipient,
759 tid,
761 }
762 it->second.first.SetState(OriginatorBlockAckAgreement::NO_REPLY);
763 m_unblockPackets(recipient, tid);
764}
765
766void
768{
769 NS_LOG_FUNCTION(this << recipient << +tid);
770 auto it = m_originatorAgreements.find({recipient, tid});
772 if (!it->second.first.IsReset())
773 {
775 recipient,
776 tid,
778 }
779 it->second.first.SetState(OriginatorBlockAckAgreement::RESET);
780}
781
782void
784{
785 NS_LOG_FUNCTION(this << queue);
786 m_queue = queue;
787}
788
789bool
791{
792 auto it = m_originatorAgreements.find({recipient, tid});
793 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
794 {
795 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
796 // has destroyed the agreement, hence we get here and correctly return false
797 return false;
798 }
799
800 Time now = Simulator::Now();
801
802 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
803 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
804 {
805 // remove MPDU if old or with expired lifetime
806 mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
807
808 if (mpduIt != it->second.second.begin())
809 {
810 // the MPDU has not been removed
811 return true;
812 }
813 }
814
815 return false;
816}
817
818void
824
825void
831
832void
838
839void
841{
842 m_txOkCallback = callback;
843}
844
845void
850
851void
856
857uint16_t
858BlockAckManager::GetRecipientBufferSize(const Mac48Address& recipient, uint8_t tid) const
859{
860 uint16_t size = 0;
861 auto it = m_originatorAgreements.find({recipient, tid});
862 if (it != m_originatorAgreements.end())
863 {
864 size = it->second.first.GetBufferSize();
865 }
866 return size;
867}
868
869uint16_t
871{
872 uint16_t seqNum = 0;
873 auto it = m_originatorAgreements.find({recipient, tid});
874 if (it != m_originatorAgreements.end())
875 {
876 seqNum = it->second.first.GetStartingSequence();
877 }
878 return seqNum;
879}
880
881} // 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)
RecipientAgreementOptConstRef GetAgreementAsRecipient(const Mac48Address &originator, uint8_t tid) const
void NotifyOriginatorAgreementEstablished(const Mac48Address &recipient, uint8_t tid, uint16_t startingSeq)
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 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.
an EUI-48 address
Implement the header for management frames of type Add Block Ack request.
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.
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:1332
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:179
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:183
@ WIFI_MAC_CTL_BACKREQ
ns3::Time timeout