30#include "ns3/simulator.h"
47 skipIfNoDataQueued(skipIfNoDataQueued)
58 TypeId(
"ns3::BlockAckManager")
62 .AddTraceSource(
"AgreementState",
63 "The state of the ADDBA handshake",
65 "ns3::BlockAckManager::AgreementStateTracedCallback");
114 return it->second.first.IsEstablished();
116 return it->second.first.IsPending();
118 return it->second.first.IsRejected();
120 return it->second.first.IsNoReply();
122 return it->second.first.IsReset();
136 std::pair<Mac48Address, uint8_t> key(recipient, reqHdr->
GetTid());
153 uint8_t tid = reqHdr->
GetTid();
157 std::pair<OriginatorBlockAckAgreement, PacketQueue>
value(agreement, queue);
177 for (std::list<Bar>::const_iterator i =
m_bars.begin(); i !=
m_bars.end();)
179 if (i->bar->GetHeader().GetAddr1() == recipient && i->tid == tid)
194 uint16_t startingSeq)
197 uint8_t tid = respHdr->
GetTid();
215 if (!it->second.first.IsEstablished())
240 NS_ASSERT(mpdu->GetHeader().IsQosData());
242 uint8_t tid = mpdu->GetHeader().GetQosTid();
249 agreementIt->second.first.GetDistance(mpdu->GetHeader().GetSequenceNumber());
259 auto it = agreementIt->second.second.rbegin();
260 while (it != agreementIt->second.second.rend())
262 if (mpdu->GetHeader().GetSequenceControl() == (*it)->GetHeader().GetSequenceControl())
264 NS_LOG_DEBUG(
"Packet already in the queue of the BA agreement");
269 agreementIt->second.first.GetDistance((*it)->GetHeader().GetSequenceNumber());
271 if (mpduDist > dist || (mpduDist == dist && mpdu->GetHeader().GetFragmentNumber() >
272 (*it)->GetHeader().GetFragmentNumber()))
279 agreementIt->second.second.insert(it.base(), mpdu);
280 agreementIt->second.first.NotifyTransmittedMpdu(mpdu);
291 m_queue->WipeAllExpiredMpdus();
293 auto nextBar =
m_bars.begin();
295 while (nextBar !=
m_bars.end())
297 Mac48Address recipient = nextBar->bar->GetHeader().GetAddr1();
300 (!nextBar->bar->GetHeader().IsBlockAckReq() ||
address != recipient ||
301 tid != nextBar->tid))
307 if (nextBar->bar->GetHeader().IsBlockAckReq())
310 AgreementsI it = bam->m_agreements.find(std::make_pair(recipient, nextBar->tid));
314 nextBar =
m_bars.erase(nextBar);
317 if (nextBar->skipIfNoDataQueued &&
318 !
m_queue->PeekByTidAndAddress(nextBar->tid, recipient))
326 nextBar->bar->GetPacket()->PeekHeader(reqHdr);
332 nextBar->bar = Create<const WifiMpdu>(packet, nextBar->bar->GetHeader());
355 return it->second.second.size();
373 if (!(*mpduIt)->IsQueued())
377 NS_LOG_DEBUG(
"MPDU is not stored in the EDCA queue, drop MPDU");
378 return it->second.second.erase(mpduIt);
384 return it->second.second.erase(mpduIt);
394 NS_LOG_DEBUG(
"Old packet. Remove from the EDCA queue, too");
400 return it->second.second.erase(mpduIt);
403 std::optional<PacketQueueI> prevIt;
404 if (mpduIt != it->second.second.begin())
409 if (
m_queue->TtlExceeded(*mpduIt, now))
415 return (prevIt.has_value() ? std::next(prevIt.value()) : it->second.second.begin());
425 (*mpduIt)->GetHeader().SetRetry();
426 (*mpduIt)->ResetInFlight();
428 return it->second.second.erase(mpduIt);
435 NS_ASSERT(mpdu->GetHeader().IsQosData());
438 uint8_t tid = mpdu->GetHeader().GetQosTid();
444 it->second.first.NotifyAckedMpdu(mpdu);
447 for (
auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
449 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
451 m_queue->DequeueIfQueued({*queueIt});
462 NS_ASSERT(mpdu->GetHeader().IsQosData());
465 uint8_t tid = mpdu->GetHeader().GetQosTid();
473 for (
auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt)
475 if ((*queueIt)->GetHeader().GetSequenceNumber() == mpdu->GetHeader().GetSequenceNumber())
483std::pair<uint16_t, uint16_t>
486 const std::set<uint8_t>& tids,
490 uint16_t nSuccessfulMpdus = 0;
491 uint16_t nFailedMpdus = 0;
508 if (it->second.first.m_inactivityEvent.IsRunning())
513 it->second.first.m_inactivityEvent.Cancel();
515 it->second.first.m_inactivityEvent =
526 std::list<Ptr<const WifiMpdu>> acked;
528 for (
auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
530 uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
534 it->second.first.NotifyAckedMpdu(*queueIt);
540 acked.emplace_back(*queueIt);
550 m_queue->DequeueIfQueued(acked);
553 for (
auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
563 return {nSuccessfulMpdus, nFailedMpdus};
577 for (
auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
589 if (!mpdu->GetHeader().IsQosData())
595 if (!mpdu->GetHeader().IsRetry() && !mpdu->IsInFlight())
602 uint8_t tid = mpdu->GetHeader().GetQosTid();
610 uint16_t currStartingSeq = it->second.first.GetStartingSequence();
618 it->second.first.NotifyDiscardedMpdu(mpdu);
622 for (
auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
624 if (it->second.first.GetDistance((*mpduIt)->GetHeader().GetSequenceNumber()) >=
628 m_queue->DequeueIfQueued({*mpduIt});
633 mpduIt = it->second.second.erase(mpduIt);
642 NS_LOG_DEBUG(
"Schedule a Block Ack Request for agreement (" << recipient <<
", " << +tid
650 hdr.
SetAddr2(mpdu->GetHeader().GetAddr2());
651 hdr.
SetAddr3(mpdu->GetHeader().GetAddr3());
668 reqHdr.
SetType((*it).second.first.GetBlockAckReqType());
678 NS_ASSERT(bar->GetHeader().IsBlockAckReq() || bar->GetHeader().IsTrigger());
681 if (bar->GetHeader().IsBlockAckReq())
684 bar->GetPacket()->PeekHeader(reqHdr);
687#ifdef NS3_BUILD_PROFILE_DEBUG
691 bar->GetPacket()->PeekHeader(triggerHdr);
695 Bar request(bar, tid, skipIfNoDataQueued);
698 std::list<Bar>::const_iterator i =
m_bars.end();
700 if (bar->GetHeader().IsBlockAckReq())
704 if (i->bar->GetHeader().IsBlockAckReq() &&
705 i->bar->GetHeader().GetAddr1() == bar->GetHeader().GetAddr1() && i->tid == tid)
713 if (bar->GetHeader().IsRetry())
715 m_bars.push_front(request);
719 m_bars.insert(i, request);
733 uint16_t startingSeq)
738 if (!it->second.first.IsEstablished())
746 it->second.first.SetStartingSequence(startingSeq);
755 if (!it->second.first.IsRejected())
768 if (!it->second.first.IsNoReply())
782 if (!it->second.first.IsReset())
826 for (
auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
831 if (mpduIt != it->second.second.begin())
890 size = it->second.first.GetBufferSize();
900 return it->second.first.GetBlockAckReqType();
908 return it->second.first.GetBlockAckType();
918 seqNum = it->second.first.GetStartingSequence();
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)
void NotifyAgreementRejected(Mac48Address recipient, uint8_t tid)
std::map< AcIndex, Ptr< BlockAckManager > > m_bamMap
AC-indexed map of all Block Ack Managers.
CtrlBAckRequestHeader GetBlockAckReqHeader(Mac48Address recipient, uint8_t tid) const
Callback< void, Mac48Address, uint8_t > m_unblockPackets
unblock packets callback
void SetQueue(const Ptr< WifiMacQueue > queue)
void SetTxOkCallback(TxOk callback)
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
uint8_t m_blockAckThreshold
block ack threshold
std::list< Ptr< WifiMpdu > > PacketQueue
typedef for a list of WifiMpdu.
~BlockAckManager() override
static TypeId GetTypeId()
Get the type ID.
void SetBlockAckThreshold(uint8_t nPackets)
DroppedOldMpdu m_droppedOldMpduCallback
the dropped MPDU callback
void NotifyAgreementEstablished(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
void SetDroppedOldMpduCallback(DroppedOldMpdu callback)
void DestroyAgreement(Mac48Address recipient, uint8_t tid)
void NotifyGotAck(Ptr< const WifiMpdu > mpdu)
Invoked upon receipt of an Ack frame after the transmission of a QoS data frame sent under an establi...
TxFailed m_txFailedCallback
transmit failed callback
void SetUnblockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set unblock destination callback.
Ptr< WifiMacQueue > m_queue
queue
std::pair< uint16_t, uint16_t > NotifyGotBlockAck(const CtrlBAckResponseHeader &blockAck, Mac48Address recipient, const std::set< uint8_t > &tids, size_t index=0)
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent to the recipient.
void NotifyAgreementReset(Mac48Address recipient, uint8_t tid)
TracedCallback< Time, Mac48Address, uint8_t, OriginatorBlockAckAgreement::State > m_agreementState
The trace source fired when a state transition occurred.
void UpdateAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address recipient, uint16_t startingSeq)
uint16_t GetRecipientBufferSize(Mac48Address recipient, uint8_t tid) const
This function returns the buffer size negotiated with the recipient.
void InactivityTimeout(Mac48Address recipient, uint8_t tid)
Inactivity timeout function.
void SetBlockAckManagerMap(const std::map< AcIndex, Ptr< BlockAckManager > > &bamMap)
Provide information about all the Block Ack Managers installed on this device.
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const
void NotifyAgreementNoReply(Mac48Address recipient, uint8_t tid)
bool NeedBarRetransmission(uint8_t tid, Mac48Address recipient)
This function returns true if a block ack agreement is established with the given recipient for the g...
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
This function returns the type of Block Acks sent by the recipient.
void StorePacket(Ptr< WifiMpdu > mpdu)
void NotifyDiscardedMpdu(Ptr< const WifiMpdu > mpdu)
Agreements m_agreements
This data structure contains, for each block ack agreement (recipient, TID), a set of packets for whi...
void ScheduleBar(Ptr< const WifiMpdu > bar, bool skipIfNoDataQueued=false)
void CreateAgreement(const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient, bool htSupported=true)
void SetBlockDestinationCallback(Callback< void, Mac48Address, uint8_t > callback)
Set block destination callback.
std::list< Ptr< WifiMpdu > >::iterator PacketQueueI
typedef for an iterator for PacketQueue.
void SetBlockAckInactivityCallback(Callback< void, Mac48Address, uint8_t, bool > callback)
Set block ack inactivity callback.
bool ExistsAgreementInState(Mac48Address recipient, uint8_t tid, OriginatorBlockAckAgreement::State state) const
Callback< void, Mac48Address, uint8_t, bool > m_blockAckInactivityTimeout
BlockAck inactivity timeout callback.
Ptr< const WifiMpdu > GetBar(bool remove=true, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast())
Returns the next BlockAckRequest or MU-BAR Trigger Frame to send, if any.
TxOk m_txOkCallback
transmit OK callback
MpduStatus
Enumeration for the statuses of a buffered MPDU.
void NotifyMissedBlockAck(Mac48Address recipient, uint8_t tid)
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::const_iterator AgreementsCI
typedef for a const iterator for Agreements.
std::map< std::pair< Mac48Address, uint8_t >, std::pair< OriginatorBlockAckAgreement, PacketQueue > >::iterator AgreementsI
typedef for an iterator for Agreements.
void DoDispose() override
Destructor implementation.
uint32_t GetNBufferedPackets(Mac48Address recipient, uint8_t tid) const
void NotifyMissedAck(Ptr< WifiMpdu > mpdu)
Invoked upon missed reception of an Ack frame after the transmission of a QoS data frame sent under a...
Callback< void, Mac48Address, uint8_t > m_blockPackets
block packets callback
uint16_t GetOriginatorStartingSequence(Mac48Address recipient, uint8_t tid) const
This function returns the starting sequence number of the transmit window.
std::list< Bar > m_bars
list of BARs
PacketQueueI HandleInFlightMpdu(PacketQueueI mpduIt, MpduStatus status, const AgreementsI &it, const Time &now)
Handle the given in flight MPDU based on its given status.
bool IsNull() const
Check for null implementation.
static Mac48Address GetBroadcast()
A base class which provides memory management and object aggregation.
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.
State
Represents the state for this agreement.
void InitTxWindow()
Initialize the originator's transmit window by setting its size and starting sequence number equal to...
void AddHeader(const Header &header)
Add header to this packet.
Smart pointer class similar to boost::intrusive_ptr.
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.
Simulation virtual time values and global simulation resolution.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#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 ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time MicroSeconds(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 ...
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)
std::tuple< WifiContainerQueueType, Mac48Address, uint8_t > WifiContainerQueueId
Tuple (queue type, Address, TID) identifying a container queue.
@ WIFI_QOSDATA_UNICAST_QUEUE
BlockAckRequest frame information.
Ptr< const WifiMpdu > bar
BlockAckRequest or MU-BAR Trigger Frame.
uint8_t tid
TID (unused if MU-BAR)
bool skipIfNoDataQueued
do not send if there is no data queued (unused if MU-BAR)
The different BlockAckRequest variants.
The different BlockAck variants.