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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Mirko Banchi <mk.banchi@gmail.com>
18 */
19
20#include "block-ack-manager.h"
21
22#include "ctrl-headers.h"
23#include "mac-rx-middle.h"
24#include "mgt-action-headers.h"
25#include "qos-utils.h"
26#include "wifi-mac-queue.h"
27#include "wifi-tx-vector.h"
28#include "wifi-utils.h"
29
30#include "ns3/log.h"
31#include "ns3/simulator.h"
32
33#include <algorithm>
34#include <optional>
35
36namespace ns3
37{
38
39NS_LOG_COMPONENT_DEFINE("BlockAckManager");
40
41NS_OBJECT_ENSURE_REGISTERED(BlockAckManager);
42
43TypeId
45{
46 static TypeId tid =
47 TypeId("ns3::BlockAckManager")
49 .SetGroupName("Wifi")
50 .AddConstructor<BlockAckManager>()
51 .AddTraceSource("AgreementState",
52 "The state of the ADDBA handshake",
54 "ns3::BlockAckManager::AgreementStateTracedCallback");
55 return tid;
56}
57
59{
60 NS_LOG_FUNCTION(this);
61}
62
64{
65 NS_LOG_FUNCTION(this);
66}
67
68void
70{
71 NS_LOG_FUNCTION(this);
73 m_queue = nullptr;
74}
75
77BlockAckManager::GetAgreementAsOriginator(const Mac48Address& recipient, uint8_t tid) const
78{
79 NS_LOG_FUNCTION(this << recipient << +tid);
80 if (auto it = m_originatorAgreements.find({recipient, tid}); it != m_originatorAgreements.end())
81 {
82 return std::cref(it->second.first);
83 }
84
85 return std::nullopt;
86}
87
89BlockAckManager::GetAgreementAsRecipient(const Mac48Address& originator, uint8_t tid) const
90{
91 NS_LOG_FUNCTION(this << originator << +tid);
92 if (auto it = m_recipientAgreements.find({originator, tid}); it != m_recipientAgreements.end())
93 {
94 return std::cref(it->second);
95 }
96
97 return std::nullopt;
98}
99
100void
102 const Mac48Address& recipient,
103 bool htSupported)
104{
105 NS_LOG_FUNCTION(this << reqHdr << recipient << htSupported);
106 const uint8_t tid = reqHdr.GetTid();
107 OriginatorBlockAckAgreement agreement(recipient, tid);
108 agreement.SetStartingSequence(reqHdr.GetStartingSequence());
109 /* For now we assume that originator doesn't use this field. Use of this field
110 is mandatory only for recipient */
111 agreement.SetBufferSize(reqHdr.GetBufferSize());
112 agreement.SetTimeout(reqHdr.GetTimeout());
113 agreement.SetAmsduSupport(reqHdr.IsAmsduSupported());
114 agreement.SetHtSupported(htSupported);
115 if (reqHdr.IsImmediateBlockAck())
116 {
117 agreement.SetImmediateBlockAck();
118 }
119 else
120 {
121 agreement.SetDelayedBlockAck();
122 }
125 recipient,
126 tid,
128 if (auto existingAgreement = GetAgreementAsOriginator(recipient, tid))
129 {
130 NS_ASSERT_MSG(existingAgreement->get().IsReset(),
131 "Existing agreement must be in RESET state");
132 }
133 m_originatorAgreements.insert_or_assign({recipient, tid},
134 std::make_pair(std::move(agreement), PacketQueue{}));
135 m_blockPackets(recipient, tid);
136}
137
138void
140{
141 NS_LOG_FUNCTION(this << recipient << +tid);
142 auto it = m_originatorAgreements.find({recipient, tid});
143 if (it != m_originatorAgreements.end())
144 {
145 m_originatorAgreements.erase(it);
146 }
147}
148
149void
151 const Mac48Address& recipient,
152 uint16_t startingSeq)
153{
154 NS_LOG_FUNCTION(this << respHdr << recipient << startingSeq);
155 uint8_t tid = respHdr.GetTid();
156 auto it = m_originatorAgreements.find({recipient, tid});
157 if (it != m_originatorAgreements.end())
158 {
159 OriginatorBlockAckAgreement& agreement = it->second.first;
160 agreement.SetBufferSize(respHdr.GetBufferSize());
161 agreement.SetTimeout(respHdr.GetTimeout());
162 agreement.SetAmsduSupport(respHdr.IsAmsduSupported());
163 agreement.SetStartingSequence(startingSeq);
164 agreement.InitTxWindow();
165 if (respHdr.IsImmediateBlockAck())
166 {
167 agreement.SetImmediateBlockAck();
168 }
169 else
170 {
171 agreement.SetDelayedBlockAck();
172 }
173 if (!it->second.first.IsEstablished())
174 {
176 recipient,
177 tid,
179 }
181 if (agreement.GetTimeout() != 0)
182 {
183 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
186 this,
187 recipient,
188 tid);
189 }
190 }
191 m_unblockPackets(recipient, tid);
192}
193
194void
196 const Mac48Address& originator,
197 uint16_t startingSeq,
198 bool htSupported,
199 Ptr<MacRxMiddle> rxMiddle)
200{
201 NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << htSupported << rxMiddle);
202 uint8_t tid = respHdr.GetTid();
203
204 RecipientBlockAckAgreement agreement(originator,
205 respHdr.IsAmsduSupported(),
206 tid,
207 respHdr.GetBufferSize(),
208 respHdr.GetTimeout(),
209 startingSeq,
210 htSupported);
211 agreement.SetMacRxMiddle(rxMiddle);
212 if (respHdr.IsImmediateBlockAck())
213 {
214 agreement.SetImmediateBlockAck();
215 }
216 else
217 {
218 agreement.SetDelayedBlockAck();
219 }
220
221 m_recipientAgreements.insert_or_assign({originator, tid}, agreement);
222}
223
224void
226{
227 NS_LOG_FUNCTION(this << originator << tid);
228
229 if (auto agreementIt = m_recipientAgreements.find({originator, tid});
230 agreementIt != m_recipientAgreements.end())
231 {
232 // forward up the buffered MPDUs before destroying the agreement
233 agreementIt->second.Flush();
234 m_recipientAgreements.erase(agreementIt);
235 }
236}
237
238void
240{
241 NS_LOG_FUNCTION(this << *mpdu);
242 NS_ASSERT(mpdu->GetHeader().IsQosData());
243
244 uint8_t tid = mpdu->GetHeader().GetQosTid();
245 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
246
247 auto agreementIt = m_originatorAgreements.find({recipient, tid});
248 NS_ASSERT(agreementIt != m_originatorAgreements.end());
249
250 uint16_t mpduDist =
251 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
252
253 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
254 {
255 NS_LOG_DEBUG("Got an old packet. Do nothing");
256 return;
257 }
258
259 // store the packet and keep the list sorted in increasing order of sequence number
260 // with respect to the starting sequence number
261 auto it = agreementIt->second.second.rbegin();
262 while (it != agreementIt->second.second.rend())
263 {
264 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
265 {
266 NS_LOG_DEBUG("Packet already in the queue of the BA agreement");
267 return;
268 }
269
270 uint16_t dist =
271 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
272
273 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
274 (*it)->GetHeader().GetFragmentNumber()))
275 {
276 break;
277 }
278
279 it++;
280 }
281 agreementIt->second.second.insert(it.base(), mpdu);
282 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
283}
284
286BlockAckManager::GetNBufferedPackets(const Mac48Address& recipient, uint8_t tid) const
287{
288 NS_LOG_FUNCTION(this << recipient << +tid);
289 auto it = m_originatorAgreements.find({recipient, tid});
290 if (it == m_originatorAgreements.end())
291 {
292 return 0;
293 }
294 return it->second.second.size();
295}
296
297void
299{
300 NS_LOG_FUNCTION(this << +nPackets);
301 m_blockAckThreshold = nPackets;
302}
303
306 PacketQueueI mpduIt,
307 MpduStatus status,
308 const OriginatorAgreementsI& it,
309 const Time& now)
310{
311 NS_LOG_FUNCTION(this << linkId << **mpduIt << +static_cast<uint8_t>(status));
312
313 if (!(*mpduIt)->IsQueued())
314 {
315 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
316 // removed by another method), remove from the queue of in flight MPDUs
317 NS_LOG_DEBUG("MPDU is not stored in the EDCA queue, drop MPDU");
318 return it->second.second.erase(mpduIt);
319 }
320
321 if (status == ACKNOWLEDGED)
322 {
323 // the MPDU has to be dequeued from the EDCA queue
324 return it->second.second.erase(mpduIt);
325 }
326
327 const WifiMacHeader& hdr = (*mpduIt)->GetHeader();
328
329 NS_ASSERT(hdr.GetAddr1() == it->first.first);
330 NS_ASSERT(hdr.IsQosData() && hdr.GetQosTid() == it->first.second);
331
332 if (it->second.first.GetDistance(hdr.GetSequenceNumber()) >= SEQNO_SPACE_HALF_SIZE)
333 {
334 NS_LOG_DEBUG("Old packet. Remove from the EDCA queue, too");
336 {
338 }
339 m_queue->Remove(*mpduIt);
340 return it->second.second.erase(mpduIt);
341 }
342
343 std::optional<PacketQueueI> prevIt;
344 if (mpduIt != it->second.second.begin())
345 {
346 prevIt = std::prev(mpduIt);
347 }
348
349 if (m_queue->TtlExceeded(*mpduIt, now))
350 {
351 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
352 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
353 // which removed this MPDU (and possibly others) from the in flight queue as well
354 NS_LOG_DEBUG("MSDU lifetime expired, drop MPDU");
355 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
356 }
357
358 if (status == STAY_INFLIGHT)
359 {
360 // the MPDU has to stay in flight, do nothing
361 return ++mpduIt;
362 }
363
364 NS_ASSERT(status == TO_RETRANSMIT);
365 (*mpduIt)->GetHeader().SetRetry();
366 (*mpduIt)->ResetInFlight(linkId); // no longer in flight; will be if retransmitted
367
368 return it->second.second.erase(mpduIt);
369}
370
371void
373{
374 NS_LOG_FUNCTION(this << linkId << *mpdu);
375 NS_ASSERT(mpdu->GetHeader().IsQosData());
376
377 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
378 uint8_t tid = mpdu->GetHeader().GetQosTid();
379
380 auto it = m_originatorAgreements.find({recipient, tid});
382 NS_ASSERT(it->second.first.IsEstablished());
383
384 it->second.first.NotifyAckedMpdu(mpdu);
385
386 // remove the acknowledged frame from the queue of outstanding packets
387 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
388 {
389 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
390 {
391 m_queue->DequeueIfQueued({*queueIt});
392 HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, Simulator::Now());
393 break;
394 }
395 }
396}
397
398void
400{
401 NS_LOG_FUNCTION(this << linkId << *mpdu);
402 NS_ASSERT(mpdu->GetHeader().IsQosData());
403
404 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
405 uint8_t tid = mpdu->GetHeader().GetQosTid();
406
407 auto it = m_originatorAgreements.find({recipient, tid});
409 NS_ASSERT(it->second.first.IsEstablished());
410
411 // remove the frame from the queue of outstanding packets (it will be re-inserted
412 // if retransmitted)
413 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
414 {
415 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
416 {
417 HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, Simulator::Now());
418 break;
419 }
420 }
421}
422
423std::pair<uint16_t, uint16_t>
425 const CtrlBAckResponseHeader& blockAck,
426 const Mac48Address& recipient,
427 const std::set<uint8_t>& tids,
428 size_t index)
429{
430 NS_LOG_FUNCTION(this << linkId << blockAck << recipient << index);
431
432 NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
433 NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
434
435 uint8_t tid = blockAck.GetTidInfo(index);
436 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
437 // use the TID passed by the caller.
438 if (tid == 14)
439 {
440 NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
441 tid = *tids.begin();
442 }
443
444 auto it = m_originatorAgreements.find({recipient, tid});
445 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
446 {
447 return {0, 0};
448 }
449
450 uint16_t nSuccessfulMpdus = 0;
451 uint16_t nFailedMpdus = 0;
452
453 if (it->second.first.m_inactivityEvent.IsRunning())
454 {
455 /* Upon reception of a BlockAck frame, the inactivity timer at the
456 originator must be reset.
457 For more details see section 11.5.3 in IEEE802.11e standard */
458 it->second.first.m_inactivityEvent.Cancel();
459 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
460 it->second.first.m_inactivityEvent =
462 }
463
464 NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() || blockAck.IsMultiSta());
465 Time now = Simulator::Now();
466 std::list<Ptr<const WifiMpdu>> acked;
467
468 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
469 {
470 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
471 NS_LOG_DEBUG("Current seq=" << currentSeq);
472 if (blockAck.IsPacketReceived(currentSeq, index))
473 {
474 it->second.first.NotifyAckedMpdu(*queueIt);
475 nSuccessfulMpdus++;
476 if (!m_txOkCallback.IsNull())
477 {
478 m_txOkCallback(*queueIt);
479 }
480 acked.emplace_back(*queueIt);
481 queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
482 }
483 else
484 {
485 ++queueIt;
486 }
487 }
488
489 // Dequeue all acknowledged MPDUs at once
490 m_queue->DequeueIfQueued(acked);
491
492 // Remaining outstanding MPDUs have not been acknowledged
493 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
494 {
495 // transmission actually failed if the MPDU is inflight only on the same link on
496 // which we received the BlockAck frame
497 auto linkIds = (*queueIt)->GetInFlightLinkIds();
498
499 if (linkIds.size() == 1 && *linkIds.begin() == linkId)
500 {
501 nFailedMpdus++;
503 {
504 m_txFailedCallback(*queueIt);
505 }
506 queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
507 continue;
508 }
509
510 queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now);
511 }
512
513 return {nSuccessfulMpdus, nFailedMpdus};
514}
515
516void
517BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, const Mac48Address& recipient, uint8_t tid)
518{
519 NS_LOG_FUNCTION(this << linkId << recipient << +tid);
520
521 auto it = m_originatorAgreements.find({recipient, tid});
522 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
523 {
524 return;
525 }
526
527 Time now = Simulator::Now();
528
529 // remove all packets from the queue of outstanding packets (they will be
530 // re-inserted if retransmitted)
531 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
532 {
533 // MPDUs that were transmitted on another link shall stay inflight
534 auto linkIds = (*mpduIt)->GetInFlightLinkIds();
535 if (!linkIds.contains(linkId))
536 {
537 mpduIt = HandleInFlightMpdu(linkId, mpduIt, STAY_INFLIGHT, it, now);
538 continue;
539 }
540 mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
541 }
542}
543
544void
546{
547 NS_LOG_FUNCTION(this << *mpdu);
548
549 if (!mpdu->GetHeader().IsQosData())
550 {
551 NS_LOG_DEBUG("Not a QoS Data frame");
552 return;
553 }
554
555 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
556 {
557 NS_LOG_DEBUG("This frame has never been transmitted");
558 return;
559 }
560
561 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
562 uint8_t tid = mpdu->GetHeader().GetQosTid();
563 auto it = m_originatorAgreements.find({recipient, tid});
564 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
565 {
566 NS_LOG_DEBUG("No established Block Ack agreement");
567 return;
568 }
569
570 uint16_t currStartingSeq = it->second.first.GetStartingSequence();
571 if (QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
572 {
573 NS_LOG_DEBUG("Discarded an old frame");
574 return;
575 }
576
577 // actually advance the transmit window
578 it->second.first.NotifyDiscardedMpdu(mpdu);
579
580 // remove old MPDUs from the EDCA queue and from the in flight queue
581 // (including the given MPDU which became old after advancing the transmit window)
582 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
583 {
584 if (it->second.first.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
586 {
587 NS_LOG_DEBUG("Dropping old MPDU: " << **mpduIt);
588 m_queue->DequeueIfQueued({*mpduIt});
590 {
592 }
593 mpduIt = it->second.second.erase(mpduIt);
594 }
595 else
596 {
597 break; // MPDUs are in increasing order of sequence number in the in flight queue
598 }
599 }
600
601 // schedule a BlockAckRequest
602 NS_LOG_DEBUG("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid
603 << ")");
604
605 WifiMacHeader hdr;
607 hdr.SetAddr1(recipient);
608 hdr.SetAddr2(mpdu->GetOriginal()->GetHeader().GetAddr2());
609 hdr.SetDsNotTo();
610 hdr.SetDsNotFrom();
611 hdr.SetNoRetry();
612 hdr.SetNoMoreFragments();
613
614 ScheduleBar(GetBlockAckReqHeader(recipient, tid), hdr);
615}
616
617void
619 uint8_t tid,
620 uint16_t startingSeq)
621{
622 NS_LOG_FUNCTION(this << originator << tid << startingSeq);
623 auto it = m_recipientAgreements.find({originator, tid});
624 if (it == m_recipientAgreements.end())
625 {
626 return;
627 }
628 it->second.NotifyReceivedBar(startingSeq);
629}
630
631void
633{
634 NS_LOG_FUNCTION(this << *mpdu);
635 auto originator = mpdu->GetOriginal()->GetHeader().GetAddr2();
636 NS_ASSERT(mpdu->GetHeader().IsQosData());
637 auto tid = mpdu->GetHeader().GetQosTid();
638
639 auto it = m_recipientAgreements.find({originator, tid});
640 if (it == m_recipientAgreements.end())
641 {
642 return;
643 }
644 it->second.NotifyReceivedMpdu(mpdu);
645}
646
648BlockAckManager::GetBlockAckReqHeader(const Mac48Address& recipient, uint8_t tid) const
649{
650 NS_LOG_FUNCTION(this << recipient << +tid);
651 auto it = m_originatorAgreements.find({recipient, tid});
653
655 reqHdr.SetType((*it).second.first.GetBlockAckReqType());
656 reqHdr.SetTidInfo(tid);
657 reqHdr.SetStartingSequence((*it).second.first.GetStartingSequence());
658 return reqHdr;
659}
660
661void
663{
664 NS_LOG_FUNCTION(this << reqHdr << hdr);
665
666 uint8_t tid = reqHdr.GetTidInfo();
667
668 WifiContainerQueueId queueId(WIFI_CTL_QUEUE, WIFI_UNICAST, hdr.GetAddr1(), std::nullopt);
669 auto pkt = Create<Packet>();
670 pkt->AddHeader(reqHdr);
671 Ptr<WifiMpdu> item = nullptr;
672
673 // if a BAR for the given agreement is present, replace it with the new one
674 while ((item = m_queue->PeekByQueueId(queueId, item)))
675 {
676 if (item->GetHeader().IsBlockAckReq() && item->GetHeader().GetAddr1() == hdr.GetAddr1())
677 {
678 CtrlBAckRequestHeader otherHdr;
679 item->GetPacket()->PeekHeader(otherHdr);
680 if (otherHdr.GetTidInfo() == tid)
681 {
682 auto bar = Create<WifiMpdu>(pkt, hdr, item->GetTimestamp());
683 // replace item with bar
684 m_queue->Replace(item, bar);
685 return;
686 }
687 }
688 }
689
690 m_queue->Enqueue(Create<WifiMpdu>(pkt, hdr));
691}
692
693const std::list<BlockAckManager::AgreementKey>&
695{
697}
698
699void
701{
702 NS_LOG_FUNCTION(this << recipient << tid);
703 // do nothing if the given pair is already in the list
704 if (std::find(m_sendBarIfDataQueued.begin(),
707 {
708 m_sendBarIfDataQueued.emplace_back(recipient, tid);
709 }
710}
711
712void
714{
715 NS_LOG_FUNCTION(this << recipient << tid);
716 m_sendBarIfDataQueued.remove({recipient, tid});
717}
718
719void
721{
722 NS_LOG_FUNCTION(this << recipient << +tid);
723 m_blockAckInactivityTimeout(recipient, tid, true);
724}
725
726void
728 uint8_t tid,
729 uint16_t startingSeq)
730{
731 NS_LOG_FUNCTION(this << recipient << +tid << startingSeq);
732 auto it = m_originatorAgreements.find({recipient, tid});
734 if (!it->second.first.IsEstablished())
735 {
737 recipient,
738 tid,
740 }
741 it->second.first.SetState(OriginatorBlockAckAgreement::ESTABLISHED);
742 it->second.first.SetStartingSequence(startingSeq);
743}
744
745void
747{
748 NS_LOG_FUNCTION(this << recipient << +tid);
749 auto it = m_originatorAgreements.find({recipient, tid});
751 if (!it->second.first.IsRejected())
752 {
754 recipient,
755 tid,
757 }
758 it->second.first.SetState(OriginatorBlockAckAgreement::REJECTED);
759 m_unblockPackets(recipient, tid);
760}
761
762void
764{
765 NS_LOG_FUNCTION(this << recipient << +tid);
766 auto it = m_originatorAgreements.find({recipient, tid});
768 if (!it->second.first.IsNoReply())
769 {
771 recipient,
772 tid,
774 }
775 it->second.first.SetState(OriginatorBlockAckAgreement::NO_REPLY);
776 m_unblockPackets(recipient, tid);
777}
778
779void
781{
782 NS_LOG_FUNCTION(this << recipient << +tid);
783 auto it = m_originatorAgreements.find({recipient, tid});
785 if (!it->second.first.IsReset())
786 {
788 recipient,
789 tid,
791 }
792 it->second.first.SetState(OriginatorBlockAckAgreement::RESET);
793}
794
795void
797{
798 NS_LOG_FUNCTION(this << queue);
799 m_queue = queue;
800}
801
802bool
804{
805 auto it = m_originatorAgreements.find({recipient, tid});
806 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
807 {
808 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
809 // has destroyed the agreement, hence we get here and correctly return false
810 return false;
811 }
812
813 Time now = Simulator::Now();
814
815 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
816 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
817 {
818 // remove MPDU if old or with expired lifetime
819 mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
820
821 if (mpduIt != it->second.second.begin())
822 {
823 // the MPDU has not been removed
824 return true;
825 }
826 }
827
828 return false;
829}
830
831void
833{
834 NS_LOG_FUNCTION(this << &callback);
836}
837
838void
840{
841 NS_LOG_FUNCTION(this << &callback);
842 m_blockPackets = callback;
843}
844
845void
847{
848 NS_LOG_FUNCTION(this << &callback);
849 m_unblockPackets = callback;
850}
851
852void
854{
855 m_txOkCallback = callback;
856}
857
858void
860{
861 m_txFailedCallback = callback;
862}
863
864void
866{
867 m_droppedOldMpduCallback = callback;
868}
869
870uint16_t
871BlockAckManager::GetRecipientBufferSize(const Mac48Address& recipient, uint8_t tid) const
872{
873 uint16_t size = 0;
874 auto it = m_originatorAgreements.find({recipient, tid});
875 if (it != m_originatorAgreements.end())
876 {
877 size = it->second.first.GetBufferSize();
878 }
879 return size;
880}
881
882uint16_t
884{
885 uint16_t seqNum = 0;
886 auto it = m_originatorAgreements.find({recipient, tid});
887 if (it != m_originatorAgreements.end())
888 {
889 seqNum = it->second.first.GetStartingSequence();
890 }
891 return seqNum;
892}
893
894} // 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)
void CreateOriginatorAgreement(const MgtAddBaRequestHeader &reqHdr, const Mac48Address &recipient, bool htSupported=true)
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.
std::optional< std::reference_wrapper< const OriginatorBlockAckAgreement > > OriginatorAgreementOptConstRef
optional const reference to OriginatorBlockAckAgreement
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::optional< std::reference_wrapper< const RecipientBlockAckAgreement > > RecipientAgreementOptConstRef
optional const reference to RecipientBlockAckAgreement
void SetDroppedOldMpduCallback(DroppedOldMpdu callback)
TxFailed m_txFailedCallback
transmit failed callback
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
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 CreateRecipientAgreement(const MgtAddBaResponseHeader &respHdr, const Mac48Address &originator, uint16_t startingSeq, bool htSupported, 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.
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:438
bool IsNull() const
Check for null implementation.
Definition: callback.h:571
Headers for BlockAckRequest.
Definition: ctrl-headers.h:52
uint8_t GetTidInfo() const
Return the Traffic ID (TID).
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
Headers for BlockAck response.
Definition: ctrl-headers.h:203
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
Definition: mac48-address.h:46
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:89
Maintains the state and information about transmitted MPDUs with Ack Policy set to Block Ack for an o...
void SetState(State state)
Set the current state.
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.
Definition: ptr.h:77
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:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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:66
#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:86
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
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:182
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