wifi: Add Block Ack support to WifiDefaultAckManager

This commit is contained in:
Stefano Avallone
2020-11-29 19:57:10 +01:00
parent 255499b3c7
commit ef0ce76a62
4 changed files with 300 additions and 6 deletions

View File

@@ -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);

View File

@@ -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.
*

View File

@@ -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);
}

View File

@@ -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
};