29#include "ns3/ht-configuration.h"
30#include "ns3/ht-frame-exchange-manager.h"
32#include "ns3/pointer.h"
33#include "ns3/random-variable-stream.h"
34#include "ns3/simulator.h"
36#undef NS_LOG_APPEND_CONTEXT
37#define NS_LOG_APPEND_CONTEXT WIFI_TXOP_NS_LOG_APPEND_CONTEXT
54 .AddAttribute(
"UseExplicitBarAfterMissedBlockAck",
55 "Specify whether explicit BlockAckRequest should be sent upon missed "
60 .AddAttribute(
"AddBaResponseTimeout",
61 "The timeout to wait for ADDBA response after the Ack to "
62 "ADDBA request is received.",
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");
118 m_mac->GetLocalAddress(recipient),
124 std::map<uint8_t, bool> hasFramesToTransmit;
125 for (
const auto& [
id, link] :
GetLinks())
134 m_mac->GetLocalAddress(recipient),
138 for (
const auto& [
id, link] :
GetLinks())
143 m_queue->TraceConnectWithoutContext(
165std::unique_ptr<Txop::LinkEntity>
168 return std::make_unique<QosLinkEntity>();
183 uint8_t
queueSize =
static_cast<uint8_t
>(std::ceil(std::min(bufferSize, 64769U) / 256.0));
233 m_mac->GetChannelAccessManager(linkId)->DisableEdcaFor(
this, link.muEdcaTimer);
241 return (link.muEdcaTimerStartTime.IsStrictlyPositive() &&
242 link.muEdcaTimer.IsStrictlyPositive() &&
293 return isGcr ?
m_baManager->GetGcrBufferSize(address, tid)
294 :
m_baManager->GetRecipientBufferSize(address, tid);
300 return isGcr ?
m_baManager->GetGcrStartingSequence(address, tid)
301 :
m_baManager->GetOriginatorStartingSequence(address, tid);
304std::pair<CtrlBAckRequestHeader, WifiMacHeader>
307 std::optional<Mac48Address> gcrGroupAddr)
const
309 NS_LOG_FUNCTION(
this << recipient << +tid << gcrGroupAddr.has_value());
312 auto recipientMld =
m_mac->GetMldAddress(recipient);
315 m_baManager->GetBlockAckReqHeader(recipientMld.value_or(recipient), tid, gcrGroupAddr);
326 return {reqHdr, hdr};
339 m_queue->WipeAllExpiredMpdus();
340 auto hasFramesToTransmit =
static_cast<bool>(
m_queue->PeekFirstAvailable(linkId));
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;
353 return m_txMiddle->GetNextSequenceNumberFor(hdr);
359 return m_txMiddle->PeekNextSequenceNumberFor(hdr);
367 if (!mpdu->GetHeader().IsQosData())
373 uint8_t tid = mpdu->GetHeader().GetQosTid();
375 if (!
m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid))
381 mpdu->GetHeader().GetSequenceNumber());
390 auto peek = [
this, &linkId, &tid, &recipient, &mpdu]() ->
Ptr<WifiMpdu> {
393 return m_queue->PeekFirstAvailable(linkId, mpdu);
399 if (
auto mask =
m_mac->GetMacQueueScheduler()->GetQueueLinkMask(
m_ac, queueId, linkId);
400 mask && mask->none())
402 return m_queue->PeekByQueueId(queueId, mpdu);
410 while (item && !item->IsFragment())
412 if (item->GetHeader().IsCtl())
422 NS_LOG_DEBUG(
"Removing an old packet from EDCA queue: " << *item);
433 if (
auto linkIds = item->GetInFlightLinkIds(); !linkIds.empty())
443 if (item->GetHeader().IsQosData())
446 const auto isGcr =
IsGcr(
m_mac, item->GetHeader());
447 const auto agreementEstablished =
449 ? apMac->IsGcrBaAgreementEstablishedWithAllMembers(
450 item->GetHeader().GetAddr1(),
451 item->GetHeader().GetQosTid())
453 ->GetBaAgreementEstablishedAsOriginator(item->GetHeader().GetAddr1(),
454 item->GetHeader().GetQosTid())
457 if (!agreementEstablished)
459 NS_LOG_DEBUG(
"No BA agreement and an MPDU is already in-flight");
470 if (item->GetHeader().HasData() &&
471 !
m_mac->CanForwardPacketsTo(item->GetHeader().GetAddr1()))
473 NS_LOG_DEBUG(
"Skipping frame that cannot be forwarded: " << *item);
486 auto& hdr = item->GetHeader();
490 const auto sequence = item->HasSeqNoAssigned() ? hdr.GetSequenceNumber()
491 :
m_txMiddle->PeekNextSequenceNumberFor(&hdr);
494 const auto recipient = hdr.GetAddr1();
495 const auto tid = hdr.GetQosTid();
500 const auto agreementEstablished =
501 isGcr ? apMac->IsGcrBaAgreementEstablishedWithAllMembers(recipient, tid)
502 :
m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid).has_value();
503 if (agreementEstablished && !
IsInWindow(sequence, startSeq, bufferSize))
505 NS_LOG_DEBUG(
"Packet beyond the end of the current transmit window");
511 if (!item->IsFragment() && !item->HasSeqNoAssigned())
513 hdr.SetSequenceNumber(sequence);
515 NS_LOG_DEBUG(
"Packet peeked from EDCA queue: " << *item);
527 NS_LOG_FUNCTION(
this << +linkId << *peekedItem << &txParams << availableTime << initialFrame);
529 Mac48Address recipient = peekedItem->GetHeader().GetAddr1();
534 Time actualAvailableTime =
535 (initialFrame && txParams.
GetSize(recipient) == 0 ?
Time::Min() : availableTime);
538 if (!qosFem->TryAddMpdu(peekedItem, txParams, actualAvailableTime))
548 if (peekedItem->GetHeader().IsQosData())
550 uint8_t tid = peekedItem->GetHeader().GetQosTid();
555 NS_ASSERT(!
m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid) ||
557 peekedItem->GetHeader().GetSequenceNumber(),
559 GetBaBufferSize(peekedItem->GetOriginal()->GetHeader().GetAddr1(), tid)));
566 !peekedItem->GetHeader().IsQosAmsdu() && !peekedItem->IsFragment() &&
567 (!peekedItem->HasSeqNoAssigned() ||
569 (apMac->GetGcrManager()->UseConcealment(peekedItem->GetHeader())))))
572 mpdu = htFem->GetMsduAggregator()->GetNextAmsdu(peekedItem, txParams, availableTime);
599 if (!mpdu->IsFragment() && !mpdu->HasSeqNoAssigned())
602 auto origMpdu =
m_queue->GetOriginal(mpdu);
603 uint16_t sequence =
m_txMiddle->GetNextSequenceNumberFor(&origMpdu->GetHeader());
604 mpdu->AssignSeqNo(sequence);
624 return link.startTxop;
648 auto hasTransmitted = link.startTxop.has_value() &&
Simulator::Now() > *link.startTxop;
650 m_queue->WipeAllExpiredMpdus();
651 if ((hasTransmitted) ||
652 (!
m_queue->IsEmpty() &&
m_mac->GetChannelAccessManager(linkId)->GetGenerateBackoffOnNoTx()))
660 link.startTxop.reset();
670 Time remainingTxop = link.txopDuration;
677 return remainingTxop;
684 uint8_t tid = respHdr.
GetTid();
690 << recipient <<
" tid " << +tid << (gcrGroup ?
" group " :
"")
691 << (gcrGroup ? gcrGroup->ConvertTo() :
Address()));
701 auto startingSeq =
m_txMiddle->GetNextSeqNumberByTidAndAddress(tid, queueRecipient);
702 auto peekedItem =
m_queue->PeekByTidAndAddress(tid, queueRecipient);
703 if (peekedItem && peekedItem->HasSeqNoAssigned())
705 startingSeq = peekedItem->GetHeader().GetSequenceNumber();
707 m_baManager->UpdateOriginatorAgreement(respHdr, recipient, startingSeq);
712 m_baManager->NotifyOriginatorAgreementRejected(recipient,
722 NS_LOG_DEBUG(
"received DELBA frame from=" << recipient);
731 std::optional<Mac48Address> gcrGroupAddr)
734 m_baManager->NotifyOriginatorAgreementNoReply(recipient, tid, gcrGroupAddr);
741 NS_ASSERT(mpdu->GetHeader().IsQosData());
746 (apMac->GetGcrManager()->GetRetransmissionPolicyFor(mpdu->GetHeader()) ==
751 const auto recipient = mpdu->begin()->second.GetDestinationAddr();
754 apMac->GetGcrManager()->GetMemberStasForGroupAddress(recipient));
758 if (
const auto recipient = mpdu->GetHeader().GetAddr1();
759 m_mac->GetBaAgreementEstablishedAsOriginator(recipient, mpdu->GetHeader().GetQosTid()))
798 std::optional<Mac48Address> gcrGroupAddr)
800 NS_LOG_FUNCTION(
this << recipient << +tid << gcrGroupAddr.has_value());
802 auto agreement =
m_baManager->GetAgreementAsOriginator(recipient, tid, gcrGroupAddr);
803 if (agreement && agreement->get().IsPending())
818 NS_LOG_FUNCTION(
this << recipient << +tid << gcrGroupAddr.has_value());
823 auto agreement =
m_baManager->GetAgreementAsOriginator(recipient, tid, gcrGroupAddr);
824 if (agreement && !agreement->get().IsEstablished())
826 m_baManager->NotifyOriginatorAgreementReset(recipient, tid, gcrGroupAddr);
a polymophic address class
void NotifyDiscardedMpdu(Ptr< const WifiMpdu > mpdu)
AttributeValue implementation for Boolean.
bool IsNull() const
Check for null implementation.
auto Bind(BoundArgs &&... bargs)
Bind a variable number of arguments.
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
Handles the packet queue and stores DCF/EDCA access parameters (one Txop per AC).
std::unique_ptr< LinkEntity > CreateLinkEntity() const override
Create a LinkEntity object.
uint8_t m_blockAckThreshold
the block ack threshold (use BA mechanism if number of packets in queue reaches this value.
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Time m_failedAddBaTimeout
timeout after failed BA agreement
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...
uint16_t PeekNextSequenceNumberFor(const WifiMacHeader *hdr)
Return the next sequence number for the Traffic ID and destination, but do not pick it (i....
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid, bool isGcr=false) const
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.
bool UseExplicitBarAfterMissedBlockAck() const
Return true if an explicit BlockAckRequest is sent after a missed BlockAck.
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...
Time GetAddBaResponseTimeout() const
Get the timeout for ADDBA response.
AcIndex GetAccessCategory() const
Get the access category of this object.
void AddBaResponseTimeout(Mac48Address recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Callback when ADDBA response is not received after timeout.
BaEstablishedTracedCallback m_baEstablishedCallback
traced callback for block ack agreement established events
void DoDispose() override
Destructor implementation.
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.
bool MuEdcaTimerRunning(uint8_t linkId) const
Return true if the MU EDCA Timer is running for the given link, false otherwise.
void StartMuEdcaTimerNow(uint8_t linkId)
Start the MU EDCA Timer for the given link.
uint8_t GetBlockAckThreshold() const
Return the current threshold for block ack mechanism.
void NotifyChannelReleased(uint8_t linkId) override
Called by the FrameExchangeManager to notify the completion of the transmissions.
std::pair< CtrlBAckRequestHeader, WifiMacHeader > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr=std::nullopt) const
uint16_t GetNextSequenceNumberFor(const WifiMacHeader *hdr)
Return the next sequence number for the given header.
uint16_t GetBlockAckInactivityTimeout() const
Get the BlockAck inactivity timeout.
TxopTracedCallback m_txopTrace
TXOP trace callback.
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
AcIndex m_ac
the access category
void SetDroppedMpduCallback(DroppedMpdu callback) override
bool m_useExplicitBarAfterMissedBlockAck
flag whether explicit BlockAckRequest should be sent upon missed BlockAck Response
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.
virtual std::optional< Time > GetTxopStartTime(uint8_t linkId) const
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...
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...
Time GetFailedAddBaTimeout() const
Get the timeout for failed BA agreement.
void ResetBa(Mac48Address recipient, uint8_t tid, std::optional< Mac48Address > gcrGroupAddr)
Reset BA agreement after BA negotiation failed.
void GotAddBaResponse(const MgtAddBaResponseHeader &respHdr, Mac48Address recipient)
Event handler when an ADDBA response is received.
static TypeId GetTypeId()
Get the type ID.
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...
void SetFailedAddBaTimeout(Time failedAddBaTimeout)
Set the timeout for failed BA agreement.
uint16_t m_blockAckInactivityTimeout
the BlockAck inactivity timeout value (in TUs, i.e.
QosLinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
void CreateQueue(AcIndex aci) override
Create a wifi MAC queue containing packets of the given AC.
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...
void SetBlockAckThreshold(uint8_t threshold)
Set threshold for block ack mechanism.
bool IsQosOldPacket(Ptr< const WifiMpdu > mpdu)
Check if the given MPDU is to be considered old according to the current starting sequence number of ...
void GotDelBaFrame(const MgtDelBaHeader *delBaHdr, Mac48Address recipient)
Event handler when a DELBA frame is received.
void SetBlockAckInactivityTimeout(uint16_t timeout)
Set the BlockAck inactivity timeout.
uint8_t m_nMaxInflights
the maximum number of links on which an MPDU can be in-flight at the same time
void CompleteMpduTx(Ptr< WifiMpdu > mpdu)
Stores an MPDU (part of an A-MPDU) in block ack agreement (i.e.
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid, bool isGcr=false) const
void SetAddBaResponseTimeout(Time addBaResponseTimeout)
Set the timeout to wait for ADDBA response.
bool HasFramesToTransmit(uint8_t linkId) override
Check if the Txop has frames to transmit over the given link.
bool IsQosTxop() const override
Check for QoS TXOP.
Time m_addBaResponseTimeout
timeout for ADDBA response
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...
void SetMuEdcaTimer(Time timer, uint8_t linkId)
Set the MU EDCA Timer for the given link.
Ptr< BlockAckManager > m_baManager
the block ack manager
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static Time Now()
Return the current simulation virtual time.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
bool IsSuccess() const
Return whether the status code is success.
Simulation virtual time values and global simulation resolution.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
AttributeValue implementation for Time.
Handles the packet queue and stores DCF/EDCA access parameters (one Txop per AC).
Ptr< WifiMac > m_mac
the wifi MAC
Ptr< WifiMacQueue > m_queue
the wifi MAC queue
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...
void DoDispose() override
Destructor implementation.
uint32_t GetMinCw() const
Return the minimum contention window size.
virtual void CreateQueue(AcIndex aci)
Create a wifi MAC queue containing packets of the given AC.
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
DroppedMpdu m_droppedMpduCallback
the dropped MPDU callback
const std::map< uint8_t, std::unique_ptr< LinkEntity > > & GetLinks() const
virtual void SetDroppedMpduCallback(DroppedMpdu callback)
virtual void GenerateBackoff(uint8_t linkId)
Generate a new backoff for the given link now.
Ptr< MacTxMiddle > m_txMiddle
the MacTxMiddle
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
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...
void RequestAccess(uint8_t linkId)
Request access to the ChannelAccessManager associated with the given link.
uint8_t GetAifsn() const
Return the number of slots that make up an AIFS.
uint32_t GetMaxCw() const
Return the maximum contention window size.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
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,...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeChecker > MakeUintegerChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#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.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Seconds(double value)
Construct a Time in the indicated unit.
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
bool QosUtilsIsOldPacket(uint16_t startingSeq, uint16_t seqNumber)
This function checks if packet with sequence number seqNumber is an "old" packet.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_MAC_DROP_QOS_OLD_PACKET
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std:: tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
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...
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
bool IsGcr(Ptr< WifiMac > mac, const WifiMacHeader &hdr)
Return whether a given packet is transmitted using the GCR service.
bool IsInWindow(uint16_t seq, uint16_t winstart, uint16_t winsize)
Structure holding information specific to a single link.
uint8_t muAifsn
the MU AIFSN
uint32_t muCwMax
the MU CW maximum
std::optional< Time > startTxop
the start TXOP time
uint32_t muCwMin
the MU CW minimum
Time txopDuration
the duration of a TXOP
Time muEdcaTimer
the MU EDCA Timer
ChannelAccessStatus access
channel access status
uint32_t cwMax
the maximum contention window
uint32_t cwMin
the minimum contention window