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-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 <optional>
34
35namespace ns3
36{
37
38NS_LOG_COMPONENT_DEFINE("BlockAckManager");
39
40NS_OBJECT_ENSURE_REGISTERED(BlockAckManager);
41
42TypeId
44{
45 static TypeId tid =
46 TypeId("ns3::BlockAckManager")
48 .SetGroupName("Wifi")
49 .AddConstructor<BlockAckManager>()
50 .AddTraceSource("AgreementState",
51 "The state of the ADDBA handshake",
53 "ns3::BlockAckManager::AgreementStateTracedCallback");
54 return tid;
55}
56
58{
59 NS_LOG_FUNCTION(this);
60}
61
63{
64 NS_LOG_FUNCTION(this);
65}
66
67void
69{
70 NS_LOG_FUNCTION(this);
72 m_queue = nullptr;
73}
74
76BlockAckManager::GetAgreementAsOriginator(const Mac48Address& recipient, uint8_t tid) const
77{
78 NS_LOG_FUNCTION(this << recipient << +tid);
79 if (auto it = m_originatorAgreements.find({recipient, tid}); it != m_originatorAgreements.end())
80 {
81 return std::cref(it->second.first);
82 }
83
84 return std::nullopt;
85}
86
88BlockAckManager::GetAgreementAsRecipient(const Mac48Address& originator, uint8_t tid) const
89{
90 NS_LOG_FUNCTION(this << originator << +tid);
91 if (auto it = m_recipientAgreements.find({originator, tid}); it != m_recipientAgreements.end())
92 {
93 return std::cref(it->second);
94 }
95
96 return std::nullopt;
97}
98
99void
101 const Mac48Address& recipient,
102 bool htSupported)
103{
104 NS_LOG_FUNCTION(this << reqHdr << recipient << htSupported);
105 const uint8_t tid = reqHdr.GetTid();
106 OriginatorBlockAckAgreement agreement(recipient, tid);
107 agreement.SetStartingSequence(reqHdr.GetStartingSequence());
108 /* For now we assume that originator doesn't use this field. Use of this field
109 is mandatory only for recipient */
110 agreement.SetBufferSize(reqHdr.GetBufferSize());
111 agreement.SetTimeout(reqHdr.GetTimeout());
112 agreement.SetAmsduSupport(reqHdr.IsAmsduSupported());
113 agreement.SetHtSupported(htSupported);
114 if (reqHdr.IsImmediateBlockAck())
115 {
116 agreement.SetImmediateBlockAck();
117 }
118 else
119 {
120 agreement.SetDelayedBlockAck();
121 }
124 recipient,
125 tid,
127 if (auto existingAgreement = GetAgreementAsOriginator(recipient, tid))
128 {
129 NS_ASSERT_MSG(existingAgreement->get().IsReset(),
130 "Existing agreement must be in RESET state");
131 }
132 m_originatorAgreements.insert_or_assign({recipient, tid},
133 std::make_pair(std::move(agreement), PacketQueue{}));
134 m_blockPackets(recipient, tid);
135}
136
137void
139{
140 NS_LOG_FUNCTION(this << recipient << +tid);
141 auto it = m_originatorAgreements.find({recipient, tid});
142 if (it != m_originatorAgreements.end())
143 {
144 m_originatorAgreements.erase(it);
145 }
146}
147
148void
150 const Mac48Address& recipient,
151 uint16_t startingSeq)
152{
153 NS_LOG_FUNCTION(this << respHdr << recipient << startingSeq);
154 uint8_t tid = respHdr.GetTid();
155 auto it = m_originatorAgreements.find({recipient, tid});
156 if (it != m_originatorAgreements.end())
157 {
158 OriginatorBlockAckAgreement& agreement = it->second.first;
159 agreement.SetBufferSize(respHdr.GetBufferSize());
160 agreement.SetTimeout(respHdr.GetTimeout());
161 agreement.SetAmsduSupport(respHdr.IsAmsduSupported());
162 agreement.SetStartingSequence(startingSeq);
163 agreement.InitTxWindow();
164 if (respHdr.IsImmediateBlockAck())
165 {
166 agreement.SetImmediateBlockAck();
167 }
168 else
169 {
170 agreement.SetDelayedBlockAck();
171 }
172 if (!it->second.first.IsEstablished())
173 {
175 recipient,
176 tid,
178 }
180 if (agreement.GetTimeout() != 0)
181 {
182 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
185 this,
186 recipient,
187 tid);
188 }
189 }
190 m_unblockPackets(recipient, tid);
191}
192
193void
195 const Mac48Address& originator,
196 uint16_t startingSeq,
197 bool htSupported,
198 Ptr<MacRxMiddle> rxMiddle)
199{
200 NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << htSupported << rxMiddle);
201 uint8_t tid = respHdr.GetTid();
202
203 RecipientBlockAckAgreement agreement(originator,
204 respHdr.IsAmsduSupported(),
205 tid,
206 respHdr.GetBufferSize(),
207 respHdr.GetTimeout(),
208 startingSeq,
209 htSupported);
210 agreement.SetMacRxMiddle(rxMiddle);
211 if (respHdr.IsImmediateBlockAck())
212 {
213 agreement.SetImmediateBlockAck();
214 }
215 else
216 {
217 agreement.SetDelayedBlockAck();
218 }
219
220 m_recipientAgreements.insert_or_assign({originator, tid}, agreement);
221}
222
223void
225{
226 NS_LOG_FUNCTION(this << originator << tid);
227
228 if (auto agreementIt = m_recipientAgreements.find({originator, tid});
229 agreementIt != m_recipientAgreements.end())
230 {
231 // forward up the buffered MPDUs before destroying the agreement
232 agreementIt->second.Flush();
233 m_recipientAgreements.erase(agreementIt);
234 }
235}
236
237void
239{
240 NS_LOG_FUNCTION(this << *mpdu);
241 NS_ASSERT(mpdu->GetHeader().IsQosData());
242
243 uint8_t tid = mpdu->GetHeader().GetQosTid();
244 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
245
246 auto agreementIt = m_originatorAgreements.find({recipient, tid});
247 NS_ASSERT(agreementIt != m_originatorAgreements.end());
248
249 uint16_t mpduDist =
250 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
251
252 if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
253 {
254 NS_LOG_DEBUG("Got an old packet. Do nothing");
255 return;
256 }
257
258 // store the packet and keep the list sorted in increasing order of sequence number
259 // with respect to the starting sequence number
260 auto it = agreementIt->second.second.rbegin();
261 while (it != agreementIt->second.second.rend())
262 {
263 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
264 {
265 NS_LOG_DEBUG("Packet already in the queue of the BA agreement");
266 return;
267 }
268
269 uint16_t dist =
270 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
271
272 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
273 (*it)->GetHeader().GetFragmentNumber()))
274 {
275 break;
276 }
277
278 it++;
279 }
280 agreementIt->second.second.insert(it.base(), mpdu);
281 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
282}
283
285BlockAckManager::GetNBufferedPackets(const Mac48Address& recipient, uint8_t tid) const
286{
287 NS_LOG_FUNCTION(this << recipient << +tid);
288 auto it = m_originatorAgreements.find({recipient, tid});
289 if (it == m_originatorAgreements.end())
290 {
291 return 0;
292 }
293 return it->second.second.size();
294}
295
296void
298{
299 NS_LOG_FUNCTION(this << +nPackets);
300 m_blockAckThreshold = nPackets;
301}
302
305 PacketQueueI mpduIt,
306 MpduStatus status,
307 const OriginatorAgreementsI& it,
308 const Time& now)
309{
310 NS_LOG_FUNCTION(this << linkId << **mpduIt << +static_cast<uint8_t>(status));
311
312 if (!(*mpduIt)->IsQueued())
313 {
314 // MPDU is not in the EDCA queue (e.g., its lifetime expired and it was
315 // removed by another method), remove from the queue of in flight MPDUs
316 NS_LOG_DEBUG("MPDU is not stored in the EDCA queue, drop MPDU");
317 return it->second.second.erase(mpduIt);
318 }
319
320 if (status == ACKNOWLEDGED)
321 {
322 // the MPDU has to be dequeued from the EDCA queue
323 return it->second.second.erase(mpduIt);
324 }
325
326 const WifiMacHeader& hdr = (*mpduIt)->GetHeader();
327
328 NS_ASSERT(hdr.GetAddr1() == it->first.first);
329 NS_ASSERT(hdr.IsQosData() && hdr.GetQosTid() == it->first.second);
330
331 if (it->second.first.GetDistance(hdr.GetSequenceNumber()) >= SEQNO_SPACE_HALF_SIZE)
332 {
333 NS_LOG_DEBUG("Old packet. Remove from the EDCA queue, too");
335 {
337 }
338 m_queue->Remove(*mpduIt);
339 return it->second.second.erase(mpduIt);
340 }
341
342 std::optional<PacketQueueI> prevIt;
343 if (mpduIt != it->second.second.begin())
344 {
345 prevIt = std::prev(mpduIt);
346 }
347
348 if (m_queue->TtlExceeded(*mpduIt, now))
349 {
350 // WifiMacQueue::TtlExceeded() has removed the MPDU from the EDCA queue
351 // and fired the Expired trace source, which called NotifyDiscardedMpdu,
352 // which removed this MPDU (and possibly others) from the in flight queue as well
353 NS_LOG_DEBUG("MSDU lifetime expired, drop MPDU");
354 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
355 }
356
357 if (status == STAY_INFLIGHT)
358 {
359 // the MPDU has to stay in flight, do nothing
360 return ++mpduIt;
361 }
362
363 NS_ASSERT(status == TO_RETRANSMIT);
364 (*mpduIt)->GetHeader().SetRetry();
365 (*mpduIt)->ResetInFlight(linkId); // no longer in flight; will be if retransmitted
366
367 return it->second.second.erase(mpduIt);
368}
369
370void
372{
373 NS_LOG_FUNCTION(this << linkId << *mpdu);
374 NS_ASSERT(mpdu->GetHeader().IsQosData());
375
376 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
377 uint8_t tid = mpdu->GetHeader().GetQosTid();
378
379 auto it = m_originatorAgreements.find({recipient, tid});
381 NS_ASSERT(it->second.first.IsEstablished());
382
383 it->second.first.NotifyAckedMpdu(mpdu);
384
385 // remove the acknowledged frame from the queue of outstanding packets
386 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
387 {
388 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
389 {
390 m_queue->DequeueIfQueued({*queueIt});
391 HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, Simulator::Now());
392 break;
393 }
394 }
395}
396
397void
399{
400 NS_LOG_FUNCTION(this << linkId << *mpdu);
401 NS_ASSERT(mpdu->GetHeader().IsQosData());
402
403 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
404 uint8_t tid = mpdu->GetHeader().GetQosTid();
405
406 auto it = m_originatorAgreements.find({recipient, tid});
408 NS_ASSERT(it->second.first.IsEstablished());
409
410 // remove the frame from the queue of outstanding packets (it will be re-inserted
411 // if retransmitted)
412 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
413 {
414 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
415 {
416 HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, Simulator::Now());
417 break;
418 }
419 }
420}
421
422std::pair<uint16_t, uint16_t>
424 const CtrlBAckResponseHeader& blockAck,
425 const Mac48Address& recipient,
426 const std::set<uint8_t>& tids,
427 size_t index)
428{
429 NS_LOG_FUNCTION(this << linkId << blockAck << recipient << index);
430
431 NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
432 NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
433
434 uint8_t tid = blockAck.GetTidInfo(index);
435 // If this is a Multi-STA Block Ack with All-ack context (TID equal to 14),
436 // use the TID passed by the caller.
437 if (tid == 14)
438 {
439 NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
440 tid = *tids.begin();
441 }
442
443 auto it = m_originatorAgreements.find({recipient, tid});
444 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
445 {
446 return {0, 0};
447 }
448
449 uint16_t nSuccessfulMpdus = 0;
450 uint16_t nFailedMpdus = 0;
451
452 if (it->second.first.m_inactivityEvent.IsRunning())
453 {
454 /* Upon reception of a BlockAck frame, the inactivity timer at the
455 originator must be reset.
456 For more details see section 11.5.3 in IEEE802.11e standard */
457 it->second.first.m_inactivityEvent.Cancel();
458 Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
459 it->second.first.m_inactivityEvent =
461 }
462
463 NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() || blockAck.IsMultiSta());
464 Time now = Simulator::Now();
465 std::list<Ptr<const WifiMpdu>> acked;
466
467 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
468 {
469 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
470 NS_LOG_DEBUG("Current seq=" << currentSeq);
471 if (blockAck.IsPacketReceived(currentSeq, index))
472 {
473 it->second.first.NotifyAckedMpdu(*queueIt);
474 nSuccessfulMpdus++;
475 if (!m_txOkCallback.IsNull())
476 {
477 m_txOkCallback(*queueIt);
478 }
479 acked.emplace_back(*queueIt);
480 queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
481 }
482 else
483 {
484 ++queueIt;
485 }
486 }
487
488 // Dequeue all acknowledged MPDUs at once
489 m_queue->DequeueIfQueued(acked);
490
491 // Remaining outstanding MPDUs have not been acknowledged
492 for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
493 {
494 // transmission actually failed if the MPDU is inflight only on the same link on
495 // which we received the BlockAck frame
496 auto linkIds = (*queueIt)->GetInFlightLinkIds();
497
498 if (linkIds.size() == 1 && *linkIds.begin() == linkId)
499 {
500 nFailedMpdus++;
502 {
503 m_txFailedCallback(*queueIt);
504 }
505 queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
506 continue;
507 }
508
509 queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now);
510 }
511
512 return {nSuccessfulMpdus, nFailedMpdus};
513}
514
515void
516BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, const Mac48Address& recipient, uint8_t tid)
517{
518 NS_LOG_FUNCTION(this << linkId << recipient << +tid);
519
520 auto it = m_originatorAgreements.find({recipient, tid});
521 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
522 {
523 return;
524 }
525
526 Time now = Simulator::Now();
527
528 // remove all packets from the queue of outstanding packets (they will be
529 // re-inserted if retransmitted)
530 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
531 {
532 // MPDUs that were transmitted on another link shall stay inflight
533 auto linkIds = (*mpduIt)->GetInFlightLinkIds();
534 if (linkIds.count(linkId) == 0)
535 {
536 mpduIt = HandleInFlightMpdu(linkId, mpduIt, STAY_INFLIGHT, it, now);
537 continue;
538 }
539 mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
540 }
541}
542
543void
545{
546 NS_LOG_FUNCTION(this << *mpdu);
547
548 if (!mpdu->GetHeader().IsQosData())
549 {
550 NS_LOG_DEBUG("Not a QoS Data frame");
551 return;
552 }
553
554 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
555 {
556 NS_LOG_DEBUG("This frame has never been transmitted");
557 return;
558 }
559
560 Mac48Address recipient = mpdu->GetOriginal()->GetHeader().GetAddr1();
561 uint8_t tid = mpdu->GetHeader().GetQosTid();
562 auto it = m_originatorAgreements.find({recipient, tid});
563 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
564 {
565 NS_LOG_DEBUG("No established Block Ack agreement");
566 return;
567 }
568
569 uint16_t currStartingSeq = it->second.first.GetStartingSequence();
570 if (QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
571 {
572 NS_LOG_DEBUG("Discarded an old frame");
573 return;
574 }
575
576 // actually advance the transmit window
577 it->second.first.NotifyDiscardedMpdu(mpdu);
578
579 // remove old MPDUs from the EDCA queue and from the in flight queue
580 // (including the given MPDU which became old after advancing the transmit window)
581 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
582 {
583 if (it->second.first.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
585 {
586 NS_LOG_DEBUG("Dropping old MPDU: " << **mpduIt);
587 m_queue->DequeueIfQueued({*mpduIt});
589 {
591 }
592 mpduIt = it->second.second.erase(mpduIt);
593 }
594 else
595 {
596 break; // MPDUs are in increasing order of sequence number in the in flight queue
597 }
598 }
599
600 // schedule a BlockAckRequest
601 NS_LOG_DEBUG("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid
602 << ")");
603
604 WifiMacHeader hdr;
606 hdr.SetAddr1(recipient);
607 hdr.SetAddr2(mpdu->GetOriginal()->GetHeader().GetAddr2());
608 hdr.SetDsNotTo();
609 hdr.SetDsNotFrom();
610 hdr.SetNoRetry();
611 hdr.SetNoMoreFragments();
612
613 ScheduleBar(GetBlockAckReqHeader(recipient, tid), hdr);
614}
615
616void
618 uint8_t tid,
619 uint16_t startingSeq)
620{
621 NS_LOG_FUNCTION(this << originator << tid << startingSeq);
622 auto it = m_recipientAgreements.find({originator, tid});
623 if (it == m_recipientAgreements.end())
624 {
625 return;
626 }
627 it->second.NotifyReceivedBar(startingSeq);
628}
629
630void
632{
633 NS_LOG_FUNCTION(this << *mpdu);
634 auto originator = mpdu->GetOriginal()->GetHeader().GetAddr2();
635 NS_ASSERT(mpdu->GetHeader().IsQosData());
636 auto tid = mpdu->GetHeader().GetQosTid();
637
638 auto it = m_recipientAgreements.find({originator, tid});
639 if (it == m_recipientAgreements.end())
640 {
641 return;
642 }
643 it->second.NotifyReceivedMpdu(mpdu);
644}
645
647BlockAckManager::GetBlockAckReqHeader(const Mac48Address& recipient, uint8_t tid) const
648{
649 NS_LOG_FUNCTION(this << recipient << +tid);
650 auto it = m_originatorAgreements.find({recipient, tid});
652
654 reqHdr.SetType((*it).second.first.GetBlockAckReqType());
655 reqHdr.SetTidInfo(tid);
656 reqHdr.SetStartingSequence((*it).second.first.GetStartingSequence());
657 return reqHdr;
658}
659
660void
662{
663 NS_LOG_FUNCTION(this << reqHdr << hdr);
664
665 uint8_t tid = reqHdr.GetTidInfo();
666
667 WifiContainerQueueId queueId(WIFI_CTL_QUEUE, WIFI_UNICAST, hdr.GetAddr1(), std::nullopt);
668 auto pkt = Create<Packet>();
669 pkt->AddHeader(reqHdr);
670 Ptr<WifiMpdu> item = nullptr;
671
672 // if a BAR for the given agreement is present, replace it with the new one
673 while ((item = m_queue->PeekByQueueId(queueId, item)))
674 {
675 if (item->GetHeader().IsBlockAckReq() && item->GetHeader().GetAddr1() == hdr.GetAddr1())
676 {
677 CtrlBAckRequestHeader otherHdr;
678 item->GetPacket()->PeekHeader(otherHdr);
679 if (otherHdr.GetTidInfo() == tid)
680 {
681 auto bar = Create<WifiMpdu>(pkt, hdr, item->GetTimestamp());
682 // replace item with bar
683 m_queue->Replace(item, bar);
684 return;
685 }
686 }
687 }
688
689 m_queue->Enqueue(Create<WifiMpdu>(pkt, hdr));
690}
691
692void
694{
695 NS_LOG_FUNCTION(this << *muBar);
696 NS_ASSERT(muBar->GetHeader().IsTrigger());
697
698#ifdef NS3_BUILD_PROFILE_DEBUG
699 CtrlTriggerHeader triggerHdr;
700 muBar->GetPacket()->PeekHeader(triggerHdr);
701 NS_ASSERT(triggerHdr.IsMuBar());
702#endif
703
704 m_queue->Enqueue(muBar);
705}
706
707const std::list<BlockAckManager::AgreementKey>&
709{
711}
712
713void
715{
716 NS_LOG_FUNCTION(this << recipient << tid);
717 // do nothing if the given pair is already in the list
718 if (std::find(m_sendBarIfDataQueued.begin(),
721 {
722 m_sendBarIfDataQueued.emplace_back(recipient, tid);
723 }
724}
725
726void
728{
729 NS_LOG_FUNCTION(this << recipient << tid);
730 m_sendBarIfDataQueued.remove({recipient, tid});
731}
732
733void
735{
736 NS_LOG_FUNCTION(this << recipient << +tid);
737 m_blockAckInactivityTimeout(recipient, tid, true);
738}
739
740void
742 uint8_t tid,
743 uint16_t startingSeq)
744{
745 NS_LOG_FUNCTION(this << recipient << +tid << startingSeq);
746 auto it = m_originatorAgreements.find({recipient, tid});
748 if (!it->second.first.IsEstablished())
749 {
751 recipient,
752 tid,
754 }
755 it->second.first.SetState(OriginatorBlockAckAgreement::ESTABLISHED);
756 it->second.first.SetStartingSequence(startingSeq);
757}
758
759void
761{
762 NS_LOG_FUNCTION(this << recipient << +tid);
763 auto it = m_originatorAgreements.find({recipient, tid});
765 if (!it->second.first.IsRejected())
766 {
768 recipient,
769 tid,
771 }
772 it->second.first.SetState(OriginatorBlockAckAgreement::REJECTED);
773}
774
775void
777{
778 NS_LOG_FUNCTION(this << recipient << +tid);
779 auto it = m_originatorAgreements.find({recipient, tid});
781 if (!it->second.first.IsNoReply())
782 {
784 recipient,
785 tid,
787 }
788 it->second.first.SetState(OriginatorBlockAckAgreement::NO_REPLY);
789 m_unblockPackets(recipient, tid);
790}
791
792void
794{
795 NS_LOG_FUNCTION(this << recipient << +tid);
796 auto it = m_originatorAgreements.find({recipient, tid});
798 if (!it->second.first.IsReset())
799 {
801 recipient,
802 tid,
804 }
805 it->second.first.SetState(OriginatorBlockAckAgreement::RESET);
806}
807
808void
810{
811 NS_LOG_FUNCTION(this << queue);
812 m_queue = queue;
813}
814
815bool
817{
818 auto it = m_originatorAgreements.find({recipient, tid});
819 if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished())
820 {
821 // If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
822 // has destroyed the agreement, hence we get here and correctly return false
823 return false;
824 }
825
826 Time now = Simulator::Now();
827
828 // A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
829 for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
830 {
831 // remove MPDU if old or with expired lifetime
832 mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
833
834 if (mpduIt != it->second.second.begin())
835 {
836 // the MPDU has not been removed
837 return true;
838 }
839 }
840
841 return false;
842}
843
844void
846{
847 NS_LOG_FUNCTION(this << &callback);
849}
850
851void
853{
854 NS_LOG_FUNCTION(this << &callback);
855 m_blockPackets = callback;
856}
857
858void
860{
861 NS_LOG_FUNCTION(this << &callback);
862 m_unblockPackets = callback;
863}
864
865void
867{
868 m_txOkCallback = callback;
869}
870
871void
873{
874 m_txFailedCallback = callback;
875}
876
877void
879{
880 m_droppedOldMpduCallback = callback;
881}
882
883uint16_t
884BlockAckManager::GetRecipientBufferSize(const Mac48Address& recipient, uint8_t tid) const
885{
886 uint16_t size = 0;
887 auto it = m_originatorAgreements.find({recipient, tid});
888 if (it != m_originatorAgreements.end())
889 {
890 size = it->second.first.GetBufferSize();
891 }
892 return size;
893}
894
895uint16_t
897{
898 uint16_t seqNum = 0;
899 auto it = m_originatorAgreements.find({recipient, tid});
900 if (it != m_originatorAgreements.end())
901 {
902 seqNum = it->second.first.GetStartingSequence();
903 }
904 return seqNum;
905}
906
907} // 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 ScheduleMuBar(Ptr< WifiMpdu > muBar)
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:567
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.
Headers for Trigger frames.
Definition: ctrl-headers.h:942
bool IsMuBar() const
Check if this is a MU-BAR Trigger frame.
an EUI-48 address
Definition: mac48-address.h:46
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:795
uint16_t GetBufferSize() const
Return the buffer size.
uint16_t GetTimeout() const
Return the timeout.
uint8_t GetTid() const
Return the Traffic ID (TID).
uint16_t GetStartingSequence() const
Return the starting sequence number.
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
bool IsImmediateBlockAck() const
Return whether the Block Ack policy is immediate Block Ack.
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:926
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:78
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:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
uint16_t GetSequenceNumber() const
Return the sequence number of the header.
void SetNoMoreFragments()
Un-set the More Fragment bit in the Frame Control Field.
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void 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:1360
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:136
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:140
@ WIFI_MAC_CTL_BACKREQ
ns3::Time timeout