diff --git a/src/wifi/model/wifi-acknowledgment.cc b/src/wifi/model/wifi-acknowledgment.cc index 429c7306c..0e595ae87 100644 --- a/src/wifi/model/wifi-acknowledgment.cc +++ b/src/wifi/model/wifi-acknowledgment.cc @@ -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); diff --git a/src/wifi/model/wifi-acknowledgment.h b/src/wifi/model/wifi-acknowledgment.h index ba5f25395..17ca85480 100644 --- a/src/wifi/model/wifi-acknowledgment.h +++ b/src/wifi/model/wifi-acknowledgment.h @@ -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 @@ -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. * diff --git a/src/wifi/model/wifi-default-ack-manager.cc b/src/wifi/model/wifi-default-ack-manager.cc index 6e8bd6dcc..9b4dfa829 100644 --- a/src/wifi/model/wifi-default-ack-manager.cc +++ b/src/wifi/model/wifi-default-ack-manager.cc @@ -43,6 +43,21 @@ WifiDefaultAckManager::GetTypeId (void) .SetParent () .SetGroupName ("Wifi") .AddConstructor () + .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 (0.0, 1.0)) ; return tid; } @@ -57,6 +72,82 @@ WifiDefaultAckManager::~WifiDefaultAckManager () NS_LOG_FUNCTION_NOARGS (); } +uint16_t +WifiDefaultAckManager::GetMaxDistFromStartingSeq (Ptr 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 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 mpdu, + const WifiTxParameters& txParams) const +{ + NS_LOG_FUNCTION (this << *mpdu << &txParams); + + uint8_t tid = mpdu->GetHeader ().GetQosTid (); + Mac48Address receiver = mpdu->GetHeader ().GetAddr1 (); + Ptr 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 WifiDefaultAckManager::TryAddMpdu (Ptr mpdu, const WifiTxParameters& txParams) @@ -66,6 +157,15 @@ WifiDefaultAckManager::TryAddMpdu (Ptr 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 mpdu, return std::unique_ptr (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 (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 (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 (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 (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 (acknowledgment); } diff --git a/src/wifi/model/wifi-default-ack-manager.h b/src/wifi/model/wifi-default-ack-manager.h index 54285751e..f366c5221 100644 --- a/src/wifi/model/wifi-default-ack-manager.h +++ b/src/wifi/model/wifi-default-ack-manager.h @@ -51,6 +51,38 @@ public: const WifiTxParameters& txParams); virtual std::unique_ptr TryAggregateMsdu (Ptr 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 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 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 };