wifi: Add Block Ack support to WifiDefaultAckManager
This commit is contained in:
@@ -106,6 +106,58 @@ WifiNormalAck::Print (std::ostream &os) const
|
||||
os << "NORMAL_ACK";
|
||||
}
|
||||
|
||||
/*
|
||||
* WifiBlockAck
|
||||
*/
|
||||
|
||||
WifiBlockAck::WifiBlockAck ()
|
||||
: WifiAcknowledgment (BLOCK_ACK)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WifiBlockAck::CheckQosAckPolicy (Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy) const
|
||||
{
|
||||
if (ackPolicy == WifiMacHeader::NORMAL_ACK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WifiBlockAck::Print (std::ostream &os) const
|
||||
{
|
||||
os << "BLOCK_ACK";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* WifiBarBlockAck
|
||||
*/
|
||||
|
||||
WifiBarBlockAck::WifiBarBlockAck ()
|
||||
: WifiAcknowledgment (BAR_BLOCK_ACK)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WifiBarBlockAck::CheckQosAckPolicy (Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy) const
|
||||
{
|
||||
if (ackPolicy == WifiMacHeader::BLOCK_ACK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WifiBarBlockAck::Print (std::ostream &os) const
|
||||
{
|
||||
os << "BAR_BLOCK_ACK";
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream &os, const WifiAcknowledgment* acknowledgment)
|
||||
{
|
||||
acknowledgment->Print (os);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "ns3/nstime.h"
|
||||
#include "wifi-tx-vector.h"
|
||||
#include "block-ack-type.h"
|
||||
#include "wifi-mac-header.h"
|
||||
#include "ctrl-headers.h"
|
||||
#include <map>
|
||||
@@ -48,7 +49,9 @@ struct WifiAcknowledgment
|
||||
enum Method
|
||||
{
|
||||
NONE = 0,
|
||||
NORMAL_ACK
|
||||
NORMAL_ACK,
|
||||
BLOCK_ACK,
|
||||
BAR_BLOCK_ACK
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,6 +141,44 @@ struct WifiNormalAck : public WifiAcknowledgment
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup wifi
|
||||
*
|
||||
* WifiBlockAck specifies that acknowledgment via Block Ack is required.
|
||||
*/
|
||||
struct WifiBlockAck : public WifiAcknowledgment
|
||||
{
|
||||
WifiBlockAck ();
|
||||
|
||||
// Overridden from WifiAcknowledgment
|
||||
bool CheckQosAckPolicy (Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy) const;
|
||||
void Print (std::ostream &os) const;
|
||||
|
||||
WifiTxVector blockAckTxVector; //!< BlockAck TXVECTOR
|
||||
BlockAckType baType; //!< BlockAck type
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup wifi
|
||||
*
|
||||
* WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
|
||||
*/
|
||||
struct WifiBarBlockAck : public WifiAcknowledgment
|
||||
{
|
||||
WifiBarBlockAck ();
|
||||
|
||||
// Overridden from WifiAcknowledgment
|
||||
bool CheckQosAckPolicy (Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy) const;
|
||||
void Print (std::ostream &os) const;
|
||||
|
||||
WifiTxVector blockAckReqTxVector; //!< BlockAckReq TXVECTOR
|
||||
WifiTxVector blockAckTxVector; //!< BlockAck TXVECTOR
|
||||
BlockAckReqType barType; //!< BlockAckReq type
|
||||
BlockAckType baType; //!< BlockAck type
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Stream insertion operator.
|
||||
*
|
||||
|
||||
@@ -43,6 +43,21 @@ WifiDefaultAckManager::GetTypeId (void)
|
||||
.SetParent<WifiAckManager> ()
|
||||
.SetGroupName ("Wifi")
|
||||
.AddConstructor<WifiDefaultAckManager> ()
|
||||
.AddAttribute ("UseExplicitBar",
|
||||
"Specify whether to send Block Ack Requests (if true) or use"
|
||||
" Implicit Block Ack Request ack policy (if false).",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&WifiDefaultAckManager::m_useExplicitBar),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("BaThreshold",
|
||||
"Immediate acknowledgment is requested upon transmission of a frame "
|
||||
"whose sequence number is distant at least BaThreshold multiplied "
|
||||
"by the transmit window size from the starting sequence number of "
|
||||
"the transmit window. Set to zero to request a response for every "
|
||||
"transmitted frame.",
|
||||
DoubleValue (0.0),
|
||||
MakeDoubleAccessor (&WifiDefaultAckManager::m_baThreshold),
|
||||
MakeDoubleChecker<double> (0.0, 1.0))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -57,6 +72,82 @@ WifiDefaultAckManager::~WifiDefaultAckManager ()
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
uint16_t
|
||||
WifiDefaultAckManager::GetMaxDistFromStartingSeq (Ptr<const WifiMacQueueItem> mpdu,
|
||||
const WifiTxParameters& txParams) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << *mpdu << &txParams);
|
||||
|
||||
const WifiMacHeader& hdr = mpdu->GetHeader ();
|
||||
Mac48Address receiver = hdr.GetAddr1 ();
|
||||
|
||||
uint8_t tid = hdr.GetQosTid ();
|
||||
Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
|
||||
NS_ABORT_MSG_IF (!edca->GetBaAgreementEstablished (receiver, tid),
|
||||
"An established Block Ack agreement is required");
|
||||
|
||||
uint16_t startingSeq = edca->GetBaStartingSequence (receiver, tid);
|
||||
uint16_t maxDistFromStartingSeq = (mpdu->GetHeader ().GetSequenceNumber () - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
|
||||
NS_ABORT_MSG_IF (maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
|
||||
"The given QoS data frame is too old");
|
||||
|
||||
const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
|
||||
|
||||
if (psduInfo == nullptr || psduInfo->seqNumbers.find (tid) == psduInfo->seqNumbers.end ())
|
||||
{
|
||||
// there are no aggregated MPDUs (so far)
|
||||
return maxDistFromStartingSeq;
|
||||
}
|
||||
|
||||
for (const auto& seqNumber : psduInfo->seqNumbers.at (tid))
|
||||
{
|
||||
if (!QosUtilsIsOldPacket (startingSeq, seqNumber))
|
||||
{
|
||||
uint16_t currDistToStartingSeq = (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
|
||||
|
||||
if (currDistToStartingSeq > maxDistFromStartingSeq)
|
||||
{
|
||||
maxDistFromStartingSeq = currDistToStartingSeq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG ("Returning " << maxDistFromStartingSeq);
|
||||
return maxDistFromStartingSeq;
|
||||
}
|
||||
|
||||
bool
|
||||
WifiDefaultAckManager::IsResponseNeeded (Ptr<const WifiMacQueueItem> mpdu,
|
||||
const WifiTxParameters& txParams) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << *mpdu << &txParams);
|
||||
|
||||
uint8_t tid = mpdu->GetHeader ().GetQosTid ();
|
||||
Mac48Address receiver = mpdu->GetHeader ().GetAddr1 ();
|
||||
Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
|
||||
|
||||
// An immediate response (Ack or Block Ack) is needed if any of the following holds:
|
||||
// * the maximum distance between the sequence number of an MPDU to transmit
|
||||
// and the starting sequence number of the transmit window is greater than
|
||||
// or equal to the window size multiplied by the BaThreshold
|
||||
// * no other frame belonging to this BA agreement is queued (because, in such
|
||||
// a case, a Block Ack is not going to be requested anytime soon)
|
||||
// * this is the initial frame of a transmission opportunity and it is not
|
||||
// protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
|
||||
if (m_baThreshold > 0
|
||||
&& GetMaxDistFromStartingSeq (mpdu, txParams) < m_baThreshold * edca->GetBaBufferSize (receiver, tid)
|
||||
&& (edca->GetWifiMacQueue ()->GetNPackets (tid, receiver)
|
||||
+ edca->GetBaManager ()->GetRetransmitQueue ()->GetNPackets (tid, receiver) > 1)
|
||||
&& !(edca->GetTxopLimit ().IsStrictlyPositive ()
|
||||
&& edca->GetRemainingTxop () == edca->GetTxopLimit ()
|
||||
&& !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiAcknowledgment>
|
||||
WifiDefaultAckManager::TryAddMpdu (Ptr<const WifiMacQueueItem> mpdu,
|
||||
const WifiTxParameters& txParams)
|
||||
@@ -66,6 +157,15 @@ WifiDefaultAckManager::TryAddMpdu (Ptr<const WifiMacQueueItem> mpdu,
|
||||
const WifiMacHeader& hdr = mpdu->GetHeader ();
|
||||
Mac48Address receiver = hdr.GetAddr1 ();
|
||||
|
||||
// if the current protection method (if any) is already BLOCK_ACK or BAR_BLOCK_ACK,
|
||||
// it will not change by adding an MPDU
|
||||
if (txParams.m_acknowledgment
|
||||
&& (txParams.m_acknowledgment->method == WifiAcknowledgment::BLOCK_ACK
|
||||
|| txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (receiver.IsGroup ())
|
||||
{
|
||||
NS_ABORT_MSG_IF (txParams.GetSize (receiver) > 0,
|
||||
@@ -79,13 +179,82 @@ WifiDefaultAckManager::TryAddMpdu (Ptr<const WifiMacQueueItem> mpdu,
|
||||
return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
|
||||
}
|
||||
|
||||
WifiNormalAck* acknowledgment = new WifiNormalAck;
|
||||
WifiMode mode = txParams.m_txVector.GetMode ();
|
||||
acknowledgment->ackTxVector = m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, mode);
|
||||
if (hdr.IsQosData ())
|
||||
if ((!hdr.IsQosData ()
|
||||
|| !m_mac->GetQosTxop (hdr.GetQosTid ())->GetBaAgreementEstablished (receiver, hdr.GetQosTid ()))
|
||||
&& !hdr.IsBlockAckReq ())
|
||||
{
|
||||
acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (), WifiMacHeader::NORMAL_ACK);
|
||||
NS_LOG_DEBUG ("Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
|
||||
WifiNormalAck* acknowledgment = new WifiNormalAck;
|
||||
WifiMode mode = txParams.m_txVector.GetMode ();
|
||||
acknowledgment->ackTxVector = m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, mode);
|
||||
if (hdr.IsQosData ())
|
||||
{
|
||||
acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (), WifiMacHeader::NORMAL_ACK);
|
||||
}
|
||||
return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
|
||||
}
|
||||
|
||||
// we get here if mpdu is a QoS data frame related to an established Block Ack agreement
|
||||
// or mpdu is a BlockAckReq frame
|
||||
if (!hdr.IsBlockAckReq () && !IsResponseNeeded (mpdu, txParams))
|
||||
{
|
||||
NS_LOG_DEBUG ("A response is not needed: no ack for now, use Block Ack policy");
|
||||
if (txParams.m_acknowledgment
|
||||
&& txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
|
||||
{
|
||||
// no change if the ack method is already NONE
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WifiNoAck* acknowledgment = new WifiNoAck;
|
||||
if (hdr.IsQosData ())
|
||||
{
|
||||
acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (),
|
||||
WifiMacHeader::BLOCK_ACK);
|
||||
}
|
||||
return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
|
||||
}
|
||||
|
||||
// we get here if a response is needed
|
||||
uint8_t tid = GetTid (mpdu->GetPacket (), hdr);
|
||||
if (!hdr.IsBlockAckReq ()
|
||||
&& txParams.GetSize (receiver) == 0
|
||||
&& hdr.GetSequenceNumber ()
|
||||
== m_mac->GetQosTxop (tid)->GetBaStartingSequence (receiver, tid))
|
||||
{
|
||||
NS_LOG_DEBUG ("Sending a single MPDU, no previous frame to ack: request Normal Ack");
|
||||
WifiNormalAck* acknowledgment = new WifiNormalAck;
|
||||
WifiMode mode = txParams.m_txVector.GetMode ();
|
||||
acknowledgment->ackTxVector = m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, mode);
|
||||
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NORMAL_ACK);
|
||||
return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
|
||||
}
|
||||
|
||||
// we get here if multiple MPDUs are being/have been sent
|
||||
if (!hdr.IsBlockAckReq ()
|
||||
&& (txParams.GetSize (receiver) == 0 || m_useExplicitBar))
|
||||
{
|
||||
// in case of single MPDU, there are previous unacknowledged frames, thus
|
||||
// we cannot use Implicit Block Ack Request policy, otherwise we get a
|
||||
// normal ack as response
|
||||
NS_LOG_DEBUG ("Request to schedule a Block Ack Request");
|
||||
|
||||
WifiBarBlockAck* acknowledgment = new WifiBarBlockAck;
|
||||
WifiMode mode = txParams.m_txVector.GetMode ();
|
||||
acknowledgment->blockAckReqTxVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, mode);
|
||||
acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
|
||||
acknowledgment->barType = m_mac->GetQosTxop (tid)->GetBlockAckReqType (receiver, tid);
|
||||
acknowledgment->baType = m_mac->GetQosTxop (tid)->GetBlockAckType (receiver, tid);
|
||||
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::BLOCK_ACK);
|
||||
return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG ("A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
|
||||
WifiBlockAck* acknowledgment = new WifiBlockAck;
|
||||
WifiMode mode = txParams.m_txVector.GetMode ();
|
||||
acknowledgment->blockAckTxVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, mode);
|
||||
acknowledgment->baType = m_mac->GetQosTxop (tid)->GetBlockAckType (receiver, tid);
|
||||
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NORMAL_ACK);
|
||||
return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,38 @@ public:
|
||||
const WifiTxParameters& txParams);
|
||||
virtual std::unique_ptr<WifiAcknowledgment> TryAggregateMsdu (Ptr<const WifiMacQueueItem> msdu,
|
||||
const WifiTxParameters& txParams);
|
||||
|
||||
/**
|
||||
* Get the maximum distance between the starting sequence number of the Block
|
||||
* Ack agreement which the given MPDU belongs to and each of the sequence numbers
|
||||
* of the given MPDU and of all the QoS data frames included in the given TX
|
||||
* parameters.
|
||||
*
|
||||
* \param mpdu the given MPDU
|
||||
* \param txParams the given TX parameters
|
||||
* \return the maximum distance between the starting sequence number of the Block
|
||||
* Ack agreement which the given MPDU belongs to and each of the sequence
|
||||
* numbers of the given MPDU and of all the QoS data frames included in
|
||||
* the given TX parameters
|
||||
*/
|
||||
uint16_t GetMaxDistFromStartingSeq (Ptr<const WifiMacQueueItem> mpdu,
|
||||
const WifiTxParameters& txParams) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Determine whether the (A-)MPDU containing the given MPDU and the MPDUs (if any)
|
||||
* included in the given TX parameters requires an immediate response (Normal Ack,
|
||||
* Block Ack or Block Ack Request followed by Block Ack).
|
||||
*
|
||||
* \param mpdu the given MPDU.
|
||||
* \param txParams the given TX parameters.
|
||||
* \return true if the given PSDU requires an immediate response
|
||||
*/
|
||||
bool IsResponseNeeded (Ptr<const WifiMacQueueItem> mpdu,
|
||||
const WifiTxParameters& txParams) const;
|
||||
private:
|
||||
bool m_useExplicitBar; //!< true for sending BARs, false for using Implicit BAR policy
|
||||
double m_baThreshold; //!< Threshold to determine when a BlockAck must be requested
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user