A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
qos-txop.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006, 2009 INRIA
3 * Copyright (c) 2009 MIRKO BANCHI
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
8 * Mirko Banchi <mk.banchi@gmail.com>
9 * Stefano Avallone <stavalli@unina.it>
10 */
11
12#include "qos-txop.h"
13
14#include "ap-wifi-mac.h"
16#include "ctrl-headers.h"
17#include "gcr-manager.h"
18#include "mac-tx-middle.h"
19#include "mgt-action-headers.h"
20#include "mpdu-aggregator.h"
21#include "msdu-aggregator.h"
23#include "wifi-mac-queue.h"
24#include "wifi-mac-trailer.h"
25#include "wifi-phy.h"
26#include "wifi-psdu.h"
27#include "wifi-tx-parameters.h"
28
29#include "ns3/ht-configuration.h"
30#include "ns3/ht-frame-exchange-manager.h"
31#include "ns3/log.h"
32#include "ns3/pointer.h"
33#include "ns3/random-variable-stream.h"
34#include "ns3/simulator.h"
35
36#undef NS_LOG_APPEND_CONTEXT
37#define NS_LOG_APPEND_CONTEXT WIFI_TXOP_NS_LOG_APPEND_CONTEXT
38
39namespace ns3
40{
41
43
45
46TypeId
48{
49 static TypeId tid =
50 TypeId("ns3::QosTxop")
52 .SetGroupName("Wifi")
53 .AddConstructor<QosTxop>()
54 .AddAttribute("UseExplicitBarAfterMissedBlockAck",
55 "Specify whether explicit BlockAckRequest should be sent upon missed "
56 "BlockAck Response.",
57 BooleanValue(true),
60 .AddAttribute("AddBaResponseTimeout",
61 "The timeout to wait for ADDBA response after the Ack to "
62 "ADDBA request is received.",
67 .AddAttribute(
68 "FailedAddBaTimeout",
69 "The timeout after a failed BA agreement. During this "
70 "timeout, the originator resumes sending packets using normal "
71 "MPDU. After that, BA agreement is reset and the originator "
72 "will retry BA negotiation.",
76 .AddAttribute("BlockAckManager",
77 "The BlockAckManager object.",
81 .AddAttribute("NMaxInflights",
82 "The maximum number of links (in the range 1-15) on which an MPDU can be "
83 "simultaneously in-flight.",
87 .AddTraceSource("TxopTrace",
88 "Trace source for TXOP start and duration times",
90 "ns3::QosTxop::TxopTracedCallback")
91 .AddTraceSource("BaEstablished",
92 "A block ack agreement is established with the given recipient for "
93 "the given TID (and the given GCR group address, if any).",
95 "ns3::QosTxop::BaEstablishedCallback");
96 return tid;
97}
98
104
105void
107{
108 NS_LOG_FUNCTION(this << aci);
110 m_ac = aci;
111 m_baManager->SetQueue(m_queue);
112 m_baManager->SetBlockDestinationCallback(
113 Callback<void, Mac48Address, uint8_t>([this](Mac48Address recipient, uint8_t tid) {
114 m_mac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::WAITING_ADDBA_RESP,
115 m_ac,
117 recipient,
118 m_mac->GetLocalAddress(recipient),
119 {tid});
120 }));
121 m_baManager->SetUnblockDestinationCallback(
122 Callback<void, Mac48Address, uint8_t>([this](Mac48Address recipient, uint8_t tid) {
123 // save the status of AC queues before unblocking the transmissions to the recipient
124 std::map<uint8_t, bool> hasFramesToTransmit;
125 for (const auto& [id, link] : GetLinks())
126 {
127 hasFramesToTransmit[id] = HasFramesToTransmit(id);
128 }
129
130 m_mac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::WAITING_ADDBA_RESP,
131 m_ac,
133 recipient,
134 m_mac->GetLocalAddress(recipient),
135 {tid});
136
137 // start access (if needed) on all the links
138 for (const auto& [id, link] : GetLinks())
139 {
140 StartAccessAfterEvent(id, hasFramesToTransmit.at(id), CHECK_MEDIUM_BUSY);
141 }
142 }));
143 m_queue->TraceConnectWithoutContext(
144 "Expired",
146}
147
149{
150 NS_LOG_FUNCTION(this);
151}
152
153void
155{
156 NS_LOG_FUNCTION(this);
157 if (m_baManager)
158 {
159 m_baManager->Dispose();
160 }
161 m_baManager = nullptr;
163}
164
165std::unique_ptr<Txop::LinkEntity>
167{
168 return std::make_unique<QosLinkEntity>();
169}
170
172QosTxop::GetLink(uint8_t linkId) const
173{
174 return static_cast<QosLinkEntity&>(Txop::GetLink(linkId));
175}
176
177uint8_t
178QosTxop::GetQosQueueSize(uint8_t tid, Mac48Address receiver) const
179{
180 const auto queueId = MakeWifiUnicastQueueId(WIFI_QOSDATA_QUEUE, receiver, tid);
181 uint32_t bufferSize = m_queue->GetNBytes(queueId);
182 // A queue size value of 254 is used for all sizes greater than 64 768 octets.
183 uint8_t queueSize = static_cast<uint8_t>(std::ceil(std::min(bufferSize, 64769U) / 256.0));
184 NS_LOG_DEBUG("Buffer size=" << bufferSize << " Queue Size=" << +queueSize);
185 return queueSize;
186}
187
188void
190{
191 NS_LOG_FUNCTION(this << &callback);
193 m_baManager->SetDroppedOldMpduCallback(callback.Bind(WIFI_MAC_DROP_QOS_OLD_PACKET));
194}
195
196void
197QosTxop::SetMuCwMin(uint16_t cwMin, uint8_t linkId)
198{
199 NS_LOG_FUNCTION(this << cwMin << +linkId);
200 GetLink(linkId).muCwMin = cwMin;
201}
202
203void
204QosTxop::SetMuCwMax(uint16_t cwMax, uint8_t linkId)
205{
206 NS_LOG_FUNCTION(this << cwMax << +linkId);
207 GetLink(linkId).muCwMax = cwMax;
208}
209
210void
211QosTxop::SetMuAifsn(uint8_t aifsn, uint8_t linkId)
212{
213 NS_LOG_FUNCTION(this << +aifsn << +linkId);
214 GetLink(linkId).muAifsn = aifsn;
215}
216
217void
218QosTxop::SetMuEdcaTimer(Time timer, uint8_t linkId)
219{
220 NS_LOG_FUNCTION(this << timer << +linkId);
221 GetLink(linkId).muEdcaTimer = timer;
222}
223
224void
226{
227 NS_LOG_FUNCTION(this << +linkId);
228 auto& link = GetLink(linkId);
229 link.muEdcaTimerStartTime = Simulator::Now();
230 if (EdcaDisabled(linkId))
231 {
232 NS_LOG_DEBUG("Disable EDCA for " << link.muEdcaTimer.As(Time::MS));
233 m_mac->GetChannelAccessManager(linkId)->DisableEdcaFor(this, link.muEdcaTimer);
234 }
235}
236
237bool
238QosTxop::MuEdcaTimerRunning(uint8_t linkId) const
239{
240 auto& link = GetLink(linkId);
241 return (link.muEdcaTimerStartTime.IsStrictlyPositive() &&
242 link.muEdcaTimer.IsStrictlyPositive() &&
243 link.muEdcaTimerStartTime + link.muEdcaTimer > Simulator::Now());
244}
245
246bool
247QosTxop::EdcaDisabled(uint8_t linkId) const
248{
249 return (MuEdcaTimerRunning(linkId) && GetLink(linkId).muAifsn == 0);
250}
251
253QosTxop::GetMinCw(uint8_t linkId) const
254{
255 if (!MuEdcaTimerRunning(linkId))
256 {
257 return GetLink(linkId).cwMin;
258 }
259 NS_ASSERT(!EdcaDisabled(linkId));
260 return GetLink(linkId).muCwMin;
261}
262
264QosTxop::GetMaxCw(uint8_t linkId) const
265{
266 if (!MuEdcaTimerRunning(linkId))
267 {
268 return GetLink(linkId).cwMax;
269 }
270 NS_ASSERT(!EdcaDisabled(linkId));
271 return GetLink(linkId).muCwMax;
272}
273
274uint8_t
275QosTxop::GetAifsn(uint8_t linkId) const
276{
277 if (!MuEdcaTimerRunning(linkId))
278 {
279 return GetLink(linkId).aifsn;
280 }
281 return GetLink(linkId).muAifsn;
282}
283
286{
287 return m_baManager;
288}
289
290uint16_t
291QosTxop::GetBaBufferSize(Mac48Address address, uint8_t tid, bool isGcr) const
292{
293 return isGcr ? m_baManager->GetGcrBufferSize(address, tid)
294 : m_baManager->GetRecipientBufferSize(address, tid);
295}
296
297uint16_t
298QosTxop::GetBaStartingSequence(Mac48Address address, uint8_t tid, bool isGcr) const
299{
300 return isGcr ? m_baManager->GetGcrStartingSequence(address, tid)
301 : m_baManager->GetOriginatorStartingSequence(address, tid);
302}
303
304std::pair<CtrlBAckRequestHeader, WifiMacHeader>
306 uint8_t tid,
307 std::optional<Mac48Address> gcrGroupAddr) const
308{
309 NS_LOG_FUNCTION(this << recipient << +tid << gcrGroupAddr.has_value());
311
312 auto recipientMld = m_mac->GetMldAddress(recipient);
313
314 auto reqHdr =
315 m_baManager->GetBlockAckReqHeader(recipientMld.value_or(recipient), tid, gcrGroupAddr);
316
317 WifiMacHeader hdr;
319 hdr.SetAddr1(recipient);
320 hdr.SetAddr2(m_mac->GetLocalAddress(recipient));
321 hdr.SetDsNotTo();
322 hdr.SetDsNotFrom();
323 hdr.SetNoRetry();
324 hdr.SetNoMoreFragments();
325
326 return {reqHdr, hdr};
327}
328
329bool
334
335bool
337{
338 // remove MSDUs with expired lifetime starting from the head of the queue
339 m_queue->WipeAllExpiredMpdus();
340 auto hasFramesToTransmit = static_cast<bool>(m_queue->PeekFirstAvailable(linkId));
341
342 // Print the number of packets that are actually in the queue (which might not be
343 // eligible for transmission for some reason, e.g., TID not mapped to the link, etc.)
344 NS_LOG_DEBUG(m_ac << " on link " << +linkId << (hasFramesToTransmit ? " has" : " has not")
345 << " frames to transmit with " << m_queue->GetNPackets()
346 << " packets in the queue");
347 return hasFramesToTransmit;
348}
349
350uint16_t
352{
353 return m_txMiddle->GetNextSequenceNumberFor(hdr);
354}
355
356uint16_t
358{
359 return m_txMiddle->PeekNextSequenceNumberFor(hdr);
360}
361
362bool
364{
365 NS_LOG_FUNCTION(this << *mpdu);
366
367 if (!mpdu->GetHeader().IsQosData())
368 {
369 return false;
370 }
371
372 Mac48Address recipient = mpdu->GetHeader().GetAddr1();
373 uint8_t tid = mpdu->GetHeader().GetQosTid();
374
375 if (!m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid))
376 {
377 return false;
378 }
379
380 return QosUtilsIsOldPacket(GetBaStartingSequence(recipient, tid),
381 mpdu->GetHeader().GetSequenceNumber());
382}
383
385QosTxop::PeekNextMpdu(uint8_t linkId, uint8_t tid, Mac48Address recipient, Ptr<const WifiMpdu> mpdu)
386{
387 NS_LOG_FUNCTION(this << +linkId << +tid << recipient << mpdu);
388
389 // lambda to peek the next frame
390 auto peek = [this, &linkId, &tid, &recipient, &mpdu]() -> Ptr<WifiMpdu> {
391 if (tid == 8 && recipient.IsBroadcast()) // undefined TID and recipient
392 {
393 return m_queue->PeekFirstAvailable(linkId, mpdu);
394 }
395 const auto queueId =
396 recipient.IsGroup()
398 recipient,
399 m_mac->GetFrameExchangeManager(linkId)->GetAddress(),
400 tid)
402 if (auto mask = m_mac->GetMacQueueScheduler()->GetQueueLinkMask(m_ac, queueId, linkId);
403 mask && mask->none())
404 {
405 return m_queue->PeekByQueueId(queueId, mpdu);
406 }
407 return nullptr;
408 };
409
410 auto item = peek();
411 // remove old packets (must be retransmissions or in flight, otherwise they did
412 // not get a sequence number assigned)
413 while (item && !item->IsFragment())
414 {
415 if (item->GetHeader().IsCtl() && !item->GetHeader().IsPsPoll())
416 {
417 NS_LOG_DEBUG("Skipping control frame: " << *item);
418 mpdu = item;
419 item = peek();
420 continue;
421 }
422
423 if (item->HasSeqNoAssigned() && IsQosOldPacket(item))
424 {
425 NS_LOG_DEBUG("Removing an old packet from EDCA queue: " << *item);
426 if (!m_droppedMpduCallback.IsNull())
427 {
429 }
430 mpdu = item;
431 item = peek();
432 m_queue->Remove(mpdu);
433 continue;
434 }
435
436 if (auto linkIds = item->GetInFlightLinkIds(); !linkIds.empty()) // MPDU is in-flight
437 {
438 // if the MPDU is not already in-flight on the link for which we are requesting an
439 // MPDU and the number of links on which the MPDU is in-flight is less than the
440 // maximum number, then we can transmit this MPDU
441 if (!linkIds.contains(linkId) && (linkIds.size() < m_nMaxInflights))
442 {
443 break;
444 }
445
446 if (item->GetHeader().IsQosData())
447 {
448 auto apMac = DynamicCast<ApWifiMac>(m_mac);
449 const auto isGcr = IsGcr(m_mac, item->GetHeader());
450 const auto agreementEstablished =
451 isGcr
452 ? apMac->IsGcrBaAgreementEstablishedWithAllMembers(
453 item->GetHeader().GetAddr1(),
454 item->GetHeader().GetQosTid())
455 : m_mac
456 ->GetBaAgreementEstablishedAsOriginator(item->GetHeader().GetAddr1(),
457 item->GetHeader().GetQosTid())
458 .has_value();
459 // if no BA agreement, we cannot have multiple MPDUs in-flight
460 if (!agreementEstablished)
461 {
462 NS_LOG_DEBUG("No BA agreement and an MPDU is already in-flight");
463 return nullptr;
464 }
465 }
466
467 NS_LOG_DEBUG("Skipping in flight MPDU: " << *item);
468 mpdu = item;
469 item = peek();
470 continue;
471 }
472
473 if (item->GetHeader().HasData() &&
474 !m_mac->CanForwardPacketsTo(item->GetHeader().GetAddr1()))
475 {
476 NS_LOG_DEBUG("Skipping frame that cannot be forwarded: " << *item);
477 mpdu = item;
478 item = peek();
479 continue;
480 }
481 break;
482 }
483
484 if (!item)
485 {
486 return nullptr;
487 }
488
489 auto& hdr = item->GetHeader();
490
491 // peek the next sequence number and check if it is within the transmit window
492 // in case of QoS data frame
493 const auto sequence = item->HasSeqNoAssigned() ? hdr.GetSequenceNumber()
494 : m_txMiddle->PeekNextSequenceNumberFor(&hdr);
495 if (hdr.IsQosData())
496 {
497 const auto recipient = hdr.GetAddr1();
498 const auto tid = hdr.GetQosTid();
499 const auto isGcr = IsGcr(m_mac, hdr);
500 const auto bufferSize = GetBaBufferSize(recipient, tid, isGcr);
501 const auto startSeq = GetBaStartingSequence(recipient, tid, isGcr);
502 auto apMac = DynamicCast<ApWifiMac>(m_mac);
503 const auto agreementEstablished =
504 isGcr ? apMac->IsGcrBaAgreementEstablishedWithAllMembers(recipient, tid)
505 : m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid).has_value();
506 if (agreementEstablished && !IsInWindow(sequence, startSeq, bufferSize))
507 {
508 NS_LOG_DEBUG("Packet beyond the end of the current transmit window");
509 return nullptr;
510 }
511 }
512
513 // Assign a sequence number if this is not a fragment nor it already has one assigned
514 if (!item->IsFragment() && !item->HasSeqNoAssigned())
515 {
516 hdr.SetSequenceNumber(sequence);
517 }
518 NS_LOG_DEBUG("Packet peeked from EDCA queue: " << *item);
519 return item;
520}
521
523QosTxop::GetNextMpdu(uint8_t linkId,
524 Ptr<WifiMpdu> peekedItem,
525 WifiTxParameters& txParams,
526 Time availableTime,
527 bool initialFrame)
528{
529 NS_ASSERT(peekedItem);
530 NS_LOG_FUNCTION(this << +linkId << *peekedItem << &txParams << availableTime << initialFrame);
531
532 Mac48Address recipient = peekedItem->GetHeader().GetAddr1();
533
534 // The TXOP limit can be exceeded by the TXOP holder if it does not transmit more
535 // than one Data or Management frame in the TXOP and the frame is not in an A-MPDU
536 // consisting of more than one MPDU (Sec. 10.22.2.8 of 802.11-2016)
537 Time actualAvailableTime =
538 (initialFrame && txParams.GetSize(recipient) == 0 ? Time::Min() : availableTime);
539
540 auto qosFem = StaticCast<QosFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
541 if (!qosFem->TryAddMpdu(peekedItem, txParams, actualAvailableTime))
542 {
543 return nullptr;
544 }
545
546 NS_ASSERT(peekedItem->IsQueued());
547 Ptr<WifiMpdu> mpdu;
548
549 // If it is a non-broadcast QoS Data frame and it is not a retransmission nor a fragment,
550 // attempt A-MSDU aggregation
551 if (peekedItem->GetHeader().IsQosData())
552 {
553 uint8_t tid = peekedItem->GetHeader().GetQosTid();
554
555 // we should not be asked to dequeue an MPDU that is beyond the transmit window.
556 // Note that PeekNextMpdu() temporarily assigns the next available sequence number
557 // to the peeked frame
558 NS_ASSERT(!m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid) ||
560 peekedItem->GetHeader().GetSequenceNumber(),
561 GetBaStartingSequence(peekedItem->GetOriginal()->GetHeader().GetAddr1(), tid),
562 GetBaBufferSize(peekedItem->GetOriginal()->GetHeader().GetAddr1(), tid)));
563
564 // try A-MSDU aggregation if the MPDU does not contain an A-MSDU and does not already
565 // have a sequence number assigned (may be a retransmission) unless it is a concealed GCR
566 // MPDU:
567 if (auto apMac = DynamicCast<ApWifiMac>(m_mac);
568 m_mac->GetHtConfiguration() && !recipient.IsBroadcast() &&
569 !peekedItem->GetHeader().IsQosAmsdu() && !peekedItem->IsFragment() &&
570 (!peekedItem->HasSeqNoAssigned() ||
571 (IsGcr(m_mac, peekedItem->GetHeader()) &&
572 (apMac->GetGcrManager()->UseConcealment(peekedItem->GetHeader())))))
573 {
574 auto htFem = StaticCast<HtFrameExchangeManager>(qosFem);
575 mpdu = htFem->GetMsduAggregator()->GetNextAmsdu(peekedItem, txParams, availableTime);
576 }
577
578 if (mpdu)
579 {
580 NS_LOG_DEBUG("Prepared an MPDU containing an A-MSDU");
581 }
582 // else aggregation was not attempted or failed
583 }
584
585 if (!mpdu)
586 {
587 mpdu = peekedItem;
588 }
589
590 // Assign a sequence number if this is not a fragment nor a retransmission
592 NS_LOG_DEBUG("Got MPDU from EDCA queue: " << *mpdu);
593
594 return mpdu;
595}
596
597void
599{
600 NS_LOG_FUNCTION(this << *mpdu);
601
602 if (!mpdu->IsFragment() && !mpdu->HasSeqNoAssigned())
603 {
604 // in case of 11be MLDs, sequence numbers refer to the MLD address
605 auto origMpdu = m_queue->GetOriginal(mpdu);
606 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&origMpdu->GetHeader());
607 mpdu->AssignSeqNo(sequence);
608 }
609}
610
611void
612QosTxop::NotifyChannelAccessed(uint8_t linkId, Time txopDuration)
613{
614 NS_LOG_FUNCTION(this << +linkId << txopDuration);
615
616 NS_ASSERT(txopDuration != Time::Min());
617 GetLink(linkId).startTxop = Simulator::Now();
618 GetLink(linkId).txopDuration = txopDuration;
620}
621
622std::optional<Time>
623QosTxop::GetTxopStartTime(uint8_t linkId) const
624{
625 auto& link = GetLink(linkId);
626 NS_LOG_FUNCTION(this << link.startTxop.has_value());
627 return link.startTxop;
628}
629
630void
632{
633 NS_LOG_FUNCTION(this << +linkId);
634 auto& link = GetLink(linkId);
635
636 if (link.startTxop)
637 {
638 NS_LOG_DEBUG("Terminating TXOP. Duration = " << Simulator::Now() - *link.startTxop);
639 m_txopTrace(*link.startTxop, Simulator::Now() - *link.startTxop, linkId);
640 }
641
642 // generate a new backoff value if either the TXOP duration is not null (i.e., some frames
643 // were transmitted) or no frame was transmitted but the queue actually contains frame to
644 // transmit and the user indicated that a backoff value should be generated in this situation.
645 // This behavior reflects the following specs text (Sec. 35.3.16.4 of 802.11be D4.0):
646 // An AP or non-AP STA affiliated with an MLD that has gained the right to initiate the
647 // transmission of a frame as described in 10.23.2.4 (Obtaining an EDCA TXOP) for an AC but
648 // does not transmit any frame corresponding to that AC for the reasons stated above may:
649 // - invoke a backoff for the EDCAF associated with that AC as allowed per h) of 10.23.2.2
650 // (EDCA backoff procedure).
651 auto hasTransmitted = link.startTxop.has_value() && Simulator::Now() > *link.startTxop;
652
653 m_queue->WipeAllExpiredMpdus();
654 if ((hasTransmitted) ||
655 (!m_queue->IsEmpty() && m_mac->GetChannelAccessManager(linkId)->GetGenerateBackoffOnNoTx()))
656 {
657 GenerateBackoff(linkId);
658 if (!m_queue->IsEmpty())
659 {
660 // if the channel released notification (below) leads the power save manager to put the
661 // PHY in sleep state, do not request channel access (which would wake up the PHY)
662 Simulator::ScheduleNow([=, this]() {
663 if (auto phy = m_mac->GetWifiPhy(linkId); phy && !phy->IsStateSleep())
664 {
665 NS_LOG_DEBUG("Request channel access again after releasing the channel");
666 RequestAccess(linkId);
667 }
668 });
669 }
670 }
671 link.startTxop.reset();
672 GetLink(linkId).access = NOT_REQUESTED;
673 m_mac->NotifyChannelReleased(this, linkId);
674}
675
676Time
677QosTxop::GetRemainingTxop(uint8_t linkId) const
678{
679 auto& link = GetLink(linkId);
680 NS_ASSERT(link.startTxop.has_value());
681
682 Time remainingTxop = link.txopDuration;
683 remainingTxop -= (Simulator::Now() - *link.startTxop);
684 if (remainingTxop.IsStrictlyNegative())
685 {
686 remainingTxop = Seconds(0);
687 }
688 NS_LOG_FUNCTION(this << remainingTxop);
689 return remainingTxop;
690}
691
692void
694{
695 NS_LOG_FUNCTION(this << respHdr << recipient);
696 uint8_t tid = respHdr.GetTid();
697
698 if (respHdr.GetStatusCode().IsSuccess())
699 {
700 const auto gcrGroup = respHdr.GetGcrGroupAddress();
701 NS_LOG_DEBUG("block ack agreement established with "
702 << recipient << " tid " << +tid << (gcrGroup ? " group " : "")
703 << (gcrGroup ? gcrGroup->ConvertTo() : Address()));
704 m_baEstablishedCallback(recipient, tid, gcrGroup);
705 // A (destination, TID) pair is "blocked" (i.e., no more packets are sent) when an
706 // Add BA Request is sent to the destination. However, when the Add BA Request timer
707 // expires, the (destination, TID) pair is "unblocked" and packets to the destination are
708 // sent again (under normal ack policy). Thus, there may be a packet with a sequence number
709 // already assigned waiting to be retransmitted (or being transmitted on another link)
710 // when the Add BA Response is received. In this case, the starting sequence number shall
711 // be set equal to the sequence number of such packet.
712 const auto queueRecipient = respHdr.GetGcrGroupAddress().value_or(recipient);
713 auto startingSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress(tid, queueRecipient);
714 for (const auto linkId : m_mac->GetLinkIds())
715 {
716 const auto src = m_mac->GetFrameExchangeManager(linkId)->GetAddress();
717 auto peekedItem = m_queue->PeekByTidAndAddress(tid, queueRecipient, src);
718 if (peekedItem && peekedItem->HasSeqNoAssigned())
719 {
720 startingSeq = peekedItem->GetHeader().GetSequenceNumber();
721 break;
722 }
723 }
724 m_baManager->UpdateOriginatorAgreement(respHdr, recipient, startingSeq);
725 }
726 else
727 {
728 NS_LOG_DEBUG("discard ADDBA response" << recipient);
729 m_baManager->NotifyOriginatorAgreementRejected(recipient,
730 tid,
731 respHdr.GetGcrGroupAddress());
732 }
733}
734
735void
737{
738 NS_LOG_FUNCTION(this << delBaHdr << recipient);
739 NS_LOG_DEBUG("received DELBA frame from=" << recipient);
740 m_baManager->DestroyOriginatorAgreement(recipient,
741 delBaHdr->GetTid(),
742 delBaHdr->GetGcrGroupAddress());
743}
744
745void
747 uint8_t tid,
748 std::optional<Mac48Address> gcrGroupAddr)
749{
750 NS_LOG_FUNCTION(this << recipient << tid << gcrGroupAddr.has_value());
751 m_baManager->NotifyOriginatorAgreementNoReply(recipient, tid, gcrGroupAddr);
752}
753
754void
756{
757 NS_LOG_FUNCTION(this << *mpdu);
758 NS_ASSERT(mpdu->GetHeader().IsQosData());
759 // If there is an established BA agreement, store the packet in the queue of outstanding packets
760
761 if (auto apMac = DynamicCast<ApWifiMac>(m_mac);
762 IsGcr(m_mac, mpdu->GetHeader()) &&
763 (apMac->GetGcrManager()->GetRetransmissionPolicyFor(mpdu->GetHeader()) ==
765 {
766 NS_ASSERT(mpdu->IsQueued());
767 NS_ASSERT(m_queue->GetAc() == mpdu->GetQueueAc());
768 const auto recipient = mpdu->begin()->second.GetDestinationAddr();
769 m_baManager->StoreGcrPacket(
770 m_queue->GetOriginal(mpdu),
771 apMac->GetGcrManager()->GetMemberStasForGroupAddress(recipient));
772 return;
773 }
774
775 if (const auto recipient = mpdu->GetHeader().GetAddr1();
776 m_mac->GetBaAgreementEstablishedAsOriginator(recipient, mpdu->GetHeader().GetQosTid()))
777 {
778 NS_ASSERT(mpdu->IsQueued());
779 NS_ASSERT(m_queue->GetAc() == mpdu->GetQueueAc());
780 m_baManager->StorePacket(m_queue->GetOriginal(mpdu));
781 }
782}
783
784void
786{
787 NS_LOG_FUNCTION(this << +threshold);
788 m_blockAckThreshold = threshold;
789 m_baManager->SetBlockAckThreshold(threshold);
790}
791
792void
798
799uint8_t
805
806uint16_t
811
812void
814 uint8_t tid,
815 std::optional<Mac48Address> gcrGroupAddr)
816{
817 NS_LOG_FUNCTION(this << recipient << +tid << gcrGroupAddr.has_value());
818 // If agreement is still pending, ADDBA response is not received
819 auto agreement = m_baManager->GetAgreementAsOriginator(recipient, tid, gcrGroupAddr);
820 if (agreement && agreement->get().IsPending())
821 {
822 NotifyOriginatorAgreementNoReply(recipient, tid, gcrGroupAddr);
825 this,
826 recipient,
827 tid,
828 gcrGroupAddr);
829 }
830}
831
832void
833QosTxop::ResetBa(Mac48Address recipient, uint8_t tid, std::optional<Mac48Address> gcrGroupAddr)
834{
835 NS_LOG_FUNCTION(this << recipient << +tid << gcrGroupAddr.has_value());
836 // This function is scheduled when waiting for an ADDBA response. However,
837 // before this function is called, a DELBA request may arrive, which causes
838 // the agreement to be deleted. Hence, check if an agreement exists before
839 // notifying that the agreement has to be reset.
840 auto agreement = m_baManager->GetAgreementAsOriginator(recipient, tid, gcrGroupAddr);
841 if (agreement && !agreement->get().IsEstablished())
842 {
843 m_baManager->NotifyOriginatorAgreementReset(recipient, tid, gcrGroupAddr);
844 }
845}
846
847void
849{
850 NS_LOG_FUNCTION(this << addBaResponseTimeout);
851 m_addBaResponseTimeout = addBaResponseTimeout;
852}
853
854Time
859
860void
862{
863 NS_LOG_FUNCTION(this << failedAddBaTimeout);
864 m_failedAddBaTimeout = failedAddBaTimeout;
865}
866
867Time
872
873bool
875{
876 return true;
877}
878
881{
882 return m_ac;
883}
884
885} // namespace ns3
a polymophic address class
Definition address.h:114
void NotifyDiscardedMpdu(Ptr< const WifiMpdu > mpdu)
Callback template class.
Definition callback.h:428
auto Bind(BoundArgs &&... bargs)
Bind a variable number of arguments.
Definition callback.h:549
an EUI-48 address
bool IsGroup() const
bool IsBroadcast() const
Implement the header for management frames of type Add Block Ack response.
StatusCode GetStatusCode() const
Return the status code.
std::optional< Mac48Address > GetGcrGroupAddress() const
uint8_t GetTid() const
Return the Traffic ID (TID).
Implement the header for management frames of type Delete Block Ack.
std::optional< Mac48Address > GetGcrGroupAddress() const
uint8_t GetTid() const
Return the Traffic ID (TID).
AttributeValue implementation for Pointer.
Definition pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
std::unique_ptr< LinkEntity > CreateLinkEntity() const override
Create a LinkEntity object.
Definition qos-txop.cc:166
~QosTxop() override
Definition qos-txop.cc:148
uint8_t m_blockAckThreshold
the block ack threshold (use BA mechanism if number of packets in queue reaches this value.
Definition qos-txop.h:455
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition qos-txop.cc:285
Time m_failedAddBaTimeout
timeout after failed BA agreement
Definition qos-txop.h:462
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition qos-txop.cc:385
uint16_t PeekNextSequenceNumberFor(const WifiMacHeader *hdr)
Return the next sequence number for the Traffic ID and destination, but do not pick it (i....
Definition qos-txop.cc:357
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid, bool isGcr=false) const
Definition qos-txop.cc:291
void SetMuCwMin(uint16_t cwMin, uint8_t linkId)
Set the minimum contention window size to use while the MU EDCA Timer is running for the given link.
Definition qos-txop.cc:197
bool UseExplicitBarAfterMissedBlockAck() const
Return true if an explicit BlockAckRequest is sent after a missed BlockAck.
Definition qos-txop.cc:330
bool EdcaDisabled(uint8_t linkId) const
Return true if the EDCA is disabled (the MU EDCA Timer is running and the MU AIFSN is zero) for the g...
Definition qos-txop.cc:247
Time GetAddBaResponseTimeout() const
Get the timeout for ADDBA response.
Definition qos-txop.cc:855
AcIndex GetAccessCategory() const
Get the access category of this object.
Definition qos-txop.cc:880
void AddBaResponseTimeout(Mac48Address recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Callback when ADDBA response is not received after timeout.
Definition qos-txop.cc:813
BaEstablishedTracedCallback m_baEstablishedCallback
traced callback for block ack agreement established events
Definition qos-txop.h:491
void DoDispose() override
Destructor implementation.
Definition qos-txop.cc:154
void SetMuCwMax(uint16_t cwMax, uint8_t linkId)
Set the maximum contention window size to use while the MU EDCA Timer is running for the given link.
Definition qos-txop.cc:204
bool MuEdcaTimerRunning(uint8_t linkId) const
Return true if the MU EDCA Timer is running for the given link, false otherwise.
Definition qos-txop.cc:238
void StartMuEdcaTimerNow(uint8_t linkId)
Start the MU EDCA Timer for the given link.
Definition qos-txop.cc:225
uint8_t GetBlockAckThreshold() const
Return the current threshold for block ack mechanism.
Definition qos-txop.cc:800
void NotifyChannelReleased(uint8_t linkId) override
Called by the FrameExchangeManager to notify the completion of the transmissions.
Definition qos-txop.cc:631
std::pair< CtrlBAckRequestHeader, WifiMacHeader > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt) const
Definition qos-txop.cc:305
uint16_t GetNextSequenceNumberFor(const WifiMacHeader *hdr)
Return the next sequence number for the given header.
Definition qos-txop.cc:351
uint16_t GetBlockAckInactivityTimeout() const
Get the BlockAck inactivity timeout.
Definition qos-txop.cc:807
TxopTracedCallback m_txopTrace
TXOP trace callback.
Definition qos-txop.h:473
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition qos-txop.cc:677
AcIndex m_ac
the access category
Definition qos-txop.h:453
void SetDroppedMpduCallback(DroppedMpdu callback) override
Definition qos-txop.cc:189
bool m_useExplicitBarAfterMissedBlockAck
flag whether explicit BlockAckRequest should be sent upon missed BlockAck Response
Definition qos-txop.h:463
void SetMuAifsn(uint8_t aifsn, uint8_t linkId)
Set the number of slots that make up an AIFS while the MU EDCA Timer is running for the given link.
Definition qos-txop.cc:211
virtual std::optional< Time > GetTxopStartTime(uint8_t linkId) const
Definition qos-txop.cc:623
uint8_t GetQosQueueSize(uint8_t tid, Mac48Address receiver) const
Get the value for the Queue Size subfield of the QoS Control field of a QoS data frame of the given T...
Definition qos-txop.cc:178
void NotifyOriginatorAgreementNoReply(const Mac48Address &recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Take action upon notification of ADDBA_REQUEST frame being discarded (likely due to exceeded max retr...
Definition qos-txop.cc:746
Time GetFailedAddBaTimeout() const
Get the timeout for failed BA agreement.
Definition qos-txop.cc:868
void ResetBa(Mac48Address recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Reset BA agreement after BA negotiation failed.
Definition qos-txop.cc:833
void GotAddBaResponse(const MgtAddBaResponseHeader &respHdr, Mac48Address recipient)
Event handler when an ADDBA response is received.
Definition qos-txop.cc:693
static TypeId GetTypeId()
Get the type ID.
Definition qos-txop.cc:47
void AssignSequenceNumber(Ptr< WifiMpdu > mpdu) const
Assign a sequence number to the given MPDU, if it is not a fragment and it is not a retransmitted fra...
Definition qos-txop.cc:598
void SetFailedAddBaTimeout(Time failedAddBaTimeout)
Set the timeout for failed BA agreement.
Definition qos-txop.cc:861
uint16_t m_blockAckInactivityTimeout
the BlockAck inactivity timeout value (in TUs, i.e.
Definition qos-txop.h:459
QosLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition qos-txop.cc:172
void CreateQueue(AcIndex aci) override
Create a wifi MAC queue containing packets of the given AC.
Definition qos-txop.cc:106
Ptr< WifiMpdu > GetNextMpdu(uint8_t linkId, Ptr< WifiMpdu > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame)
Prepare the frame to transmit on the given link starting from the MPDU that has been previously peeke...
Definition qos-txop.cc:523
void SetBlockAckThreshold(uint8_t threshold)
Set threshold for block ack mechanism.
Definition qos-txop.cc:785
bool IsQosOldPacket(Ptr< const WifiMpdu > mpdu)
Check if the given MPDU is to be considered old according to the current starting sequence number of ...
Definition qos-txop.cc:363
void GotDelBaFrame(const MgtDelBaHeader *delBaHdr, Mac48Address recipient)
Event handler when a DELBA frame is received.
Definition qos-txop.cc:736
void SetBlockAckInactivityTimeout(uint16_t timeout)
Set the BlockAck inactivity timeout.
Definition qos-txop.cc:793
uint8_t m_nMaxInflights
the maximum number of links on which an MPDU can be in-flight at the same time
Definition qos-txop.h:465
void CompleteMpduTx(Ptr< WifiMpdu > mpdu)
Stores an MPDU (part of an A-MPDU) in block ack agreement (i.e.
Definition qos-txop.cc:755
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid, bool isGcr=false) const
Definition qos-txop.cc:298
void SetAddBaResponseTimeout(Time addBaResponseTimeout)
Set the timeout to wait for ADDBA response.
Definition qos-txop.cc:848
bool HasFramesToTransmit(uint8_t linkId) override
Check if the Txop has frames to transmit over the given link.
Definition qos-txop.cc:336
bool IsQosTxop() const override
Check for QoS TXOP.
Definition qos-txop.cc:874
Time m_addBaResponseTimeout
timeout for ADDBA response
Definition qos-txop.h:461
void NotifyChannelAccessed(uint8_t linkId, Time txopDuration) override
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
Definition qos-txop.cc:612
void SetMuEdcaTimer(Time timer, uint8_t linkId)
Set the MU EDCA Timer for the given link.
Definition qos-txop.cc:218
Ptr< BlockAckManager > m_baManager
the block ack manager
Definition qos-txop.h:454
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
bool IsSuccess() const
Return whether the status code is success.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:277
@ MS
millisecond
Definition nstime.h:107
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
Definition nstime.h:332
Handles the packet queue and stores DCF/EDCA access parameters (one Txop per AC).
Definition txop.h:56
Ptr< WifiMac > m_mac
the wifi MAC
Definition txop.h:571
Ptr< WifiMacQueue > m_queue
the wifi MAC queue
Definition txop.h:569
void StartAccessAfterEvent(uint8_t linkId, bool hadFramesToTransmit, bool checkMediumBusy)
Request channel access on the given link after the occurrence of an event that possibly requires to g...
Definition txop.cc:664
void DoDispose() override
Destructor implementation.
Definition txop.cc:137
uint32_t GetMinCw() const
Return the minimum contention window size.
Definition txop.cc:489
@ NOT_REQUESTED
Definition txop.h:77
virtual void CreateQueue(AcIndex aci)
Create a wifi MAC queue containing packets of the given AC.
Definition txop.cc:148
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition txop.cc:162
DroppedMpdu m_droppedMpduCallback
the dropped MPDU callback
Definition txop.h:568
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
Definition txop.cc:171
virtual void SetDroppedMpduCallback(DroppedMpdu callback)
Definition txop.cc:212
virtual void GenerateBackoff(uint8_t linkId)
Generate a new backoff for the given link now.
Definition txop.cc:767
Ptr< MacTxMiddle > m_txMiddle
the MacTxMiddle
Definition txop.h:570
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
Definition txop.h:413
virtual void NotifyChannelAccessed(uint8_t linkId, Time txopDuration=Seconds(0))
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
Definition txop.cc:721
void RequestAccess(uint8_t linkId)
Request access to the ChannelAccessManager associated with the given link.
Definition txop.cc:749
uint8_t GetAifsn() const
Return the number of slots that make up an AIFS.
Definition txop.cc:537
uint32_t GetMaxCw() const
Return the maximum contention window size.
Definition txop.cc:513
Callback< void, WifiMacDropReason, Ptr< const WifiMpdu > > DroppedMpdu
typedef for a callback to invoke when an MPDU is dropped.
Definition txop.h:70
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
Implements the IEEE 802.11 MAC 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.
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.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
#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
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:250
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:273
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:690
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiContainerQueueId MakeWifiUnicastQueueId(WifiContainerQueueType type, Mac48Address addr1, std::optional< tid_t > tid=std::nullopt)
Helper function to create WifiContainerQueueId for unicast queues.
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition qos-utils.cc:123
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
WifiContainerQueueId MakeWifiGroupcastQueueId(WifiContainerQueueType type, Mac48Address addr1, Mac48Address addr2, std::optional< tid_t > tid=std::nullopt)
Helper function to create WifiContainerQueueId for groupcast queues.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:64
@ WIFI_MAC_DROP_QOS_OLD_PACKET
Definition wifi-mac.h:75
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1376
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:643
@ WIFI_MAC_CTL_BACKREQ
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:650
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
bool IsGcr(Ptr< WifiMac > mac, const WifiMacHeader &hdr)
Return whether a given packet is transmitted using the GCR service.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1396
bool IsInWindow(uint16_t seq, uint16_t winstart, uint16_t winsize)
ns3::Time timeout
std::ofstream queueSize