From 7fd53be0aee6c24fbf8a88581276de1f6a4dd630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deronne?= Date: Mon, 25 Sep 2023 20:20:07 +0200 Subject: [PATCH] wifi: Extend Block Ack Manager for GCR Block Acks --- src/wifi/model/block-ack-manager.cc | 135 ++++++++++++++++++++++++++++ src/wifi/model/block-ack-manager.h | 26 ++++++ 2 files changed, 161 insertions(+) diff --git a/src/wifi/model/block-ack-manager.cc b/src/wifi/model/block-ack-manager.cc index 14e8b1bb1..a98859007 100644 --- a/src/wifi/model/block-ack-manager.cc +++ b/src/wifi/model/block-ack-manager.cc @@ -254,6 +254,7 @@ BlockAckManager::UpdateOriginatorAgreement(const MgtAddBaResponseHeader& respHdr if (const auto gcrGroupAddr = respHdr.GetGcrGroupAddress()) { agreement.SetGcrGroupAddress(*gcrGroupAddr); + m_gcrBlockAcks.emplace(*gcrGroupAddr, GcrBlockAcks{}); } if (!it->second.first.IsEstablished()) { @@ -678,6 +679,140 @@ BlockAckManager::NotifyGotBlockAck(uint8_t linkId, return {nSuccessfulMpdus, nFailedMpdus}; } +std::optional> +BlockAckManager::NotifyGotGcrBlockAck(uint8_t linkId, + const CtrlBAckResponseHeader& blockAck, + const Mac48Address& recipient, + const GcrManager::GcrMembers& members) +{ + NS_LOG_FUNCTION(this << linkId << blockAck << recipient); + NS_ABORT_MSG_IF(!blockAck.IsGcr(), "GCR Block Ack is expected"); + NS_ABORT_MSG_IF(members.count(recipient) == 0, + "Received GCR Block Ack response from unexpected recipient"); + + const auto tid = blockAck.GetTidInfo(); + auto it = GetOriginatorBaAgreement(recipient, tid, blockAck.GetGcrGroupAddress()); + if (it == m_originatorAgreements.end() || !it->second.first.IsEstablished()) + { + return {}; + } + + NS_ASSERT_MSG(it->second.first.GetGcrGroupAddress().has_value() && + it->second.first.GetGcrGroupAddress().value() == + blockAck.GetGcrGroupAddress(), + "No GCR agreement for group address " << blockAck.GetGcrGroupAddress()); + if (it->second.first.m_inactivityEvent.IsPending()) + { + /* Upon reception of a BlockAck frame, the inactivity timer at the + originator must be reset. + For more details see section 11.5.3 in IEEE802.11e standard */ + it->second.first.m_inactivityEvent.Cancel(); + Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout()); + it->second.first.m_inactivityEvent = + Simulator::Schedule(timeout, + &BlockAckManager::InactivityTimeout, + this, + recipient, + tid, + blockAck.GetGcrGroupAddress()); + } + + auto itGcrBlockAcks = m_gcrBlockAcks.find(blockAck.GetGcrGroupAddress()); + NS_ASSERT(itGcrBlockAcks != m_gcrBlockAcks.end()); + NS_ASSERT(itGcrBlockAcks->second.count(recipient) == 0); + itGcrBlockAcks->second[recipient] = blockAck; + + if (itGcrBlockAcks->second.size() < members.size()) + { + // we need to collect feedback from all members + NS_LOG_DEBUG("Expecting more GCR Block ACK(s)"); + return {}; + } + + std::vector acked; + for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end(); ++queueIt) + { + auto currentSeq = (*queueIt)->GetHeader().GetSequenceNumber(); + NS_LOG_DEBUG("Current seq=" << currentSeq); + auto received = true; + for ([[maybe_unused]] const auto& [recipient, gcrBlockAcks] : itGcrBlockAcks->second) + { + received &= gcrBlockAcks.IsPacketReceived(currentSeq, 0); + } + acked.emplace_back(received); + } + + uint16_t nSuccessfulMpdus = 0; + uint16_t nFailedMpdus = 0; + const auto now = Simulator::Now(); + std::list> ackedMpdus; + auto countAndNotify = true; + for (const auto& member : members) + { + std::size_t index = 0; + it = GetOriginatorBaAgreement(member, tid, blockAck.GetGcrGroupAddress()); + NS_ASSERT(acked.size() == it->second.second.size()); + for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();) + { + if (acked.at(index++)) + { + it->second.first.NotifyAckedMpdu(*queueIt); + if (countAndNotify) + { + nSuccessfulMpdus++; + if (!m_txOkCallback.IsNull()) + { + m_txOkCallback(*queueIt); + } + ackedMpdus.emplace_back(*queueIt); + } + queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now); + } + else + { + ++queueIt; + } + } + countAndNotify = false; + } + + // Dequeue all acknowledged MPDUs at once + m_queue->DequeueIfQueued(ackedMpdus); + + // Remaining outstanding MPDUs have not been acknowledged + countAndNotify = true; + for (const auto& member : members) + { + it = GetOriginatorBaAgreement(member, tid, blockAck.GetGcrGroupAddress()); + for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();) + { + // transmission actually failed if the MPDU is inflight only on the same link on + // which we received the BlockAck frame + auto linkIds = (*queueIt)->GetInFlightLinkIds(); + + if (linkIds.size() == 1 && *linkIds.begin() == linkId) + { + if (countAndNotify) + { + nFailedMpdus++; + if (!m_txFailedCallback.IsNull()) + { + m_txFailedCallback(*queueIt); + } + } + queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now); + continue; + } + + queueIt = HandleInFlightMpdu(linkId, queueIt, STAY_INFLIGHT, it, now); + } + countAndNotify = false; + } + + itGcrBlockAcks->second.clear(); + return std::make_pair(nSuccessfulMpdus, nFailedMpdus); +} + void BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, const Mac48Address& recipient, uint8_t tid) { diff --git a/src/wifi/model/block-ack-manager.h b/src/wifi/model/block-ack-manager.h index 24499c185..73ecf4a28 100644 --- a/src/wifi/model/block-ack-manager.h +++ b/src/wifi/model/block-ack-manager.h @@ -222,6 +222,27 @@ class BlockAckManager : public Object const std::set& tids, size_t index = 0); + /** + * @param linkId the ID of the given link + * @param blockAck The received BlockAck frame. + * @param recipient Sender of BlockAck frame. + * @param members the list of member STAs for that GCR group + * @return a pair of values indicating the number of successfully received MPDUs + * and the number of failed MPDUs if GCR Block Ack frames for all member STAs + * have been received. + * + * Invoked upon receipt of a GCR Block Ack frame on the given link. Typically, this function + * is called by the frame exchange manager. Stores the received Block Ack response for each + * GCR member STA. Once all responses have been received, it performs a check on which MPDUs, + * previously sent with Ack Policy set to Block Ack, were correctly received by the recipient. + * An acknowledged MPDU is removed from the buffer, retransmitted otherwise. + */ + std::optional> NotifyGotGcrBlockAck( + uint8_t linkId, + const CtrlBAckResponseHeader& blockAck, + const Mac48Address& recipient, + const GcrManager::GcrMembers& members); + /** * @param linkId the ID of the given link * @param recipient Sender of the expected BlockAck frame. @@ -644,6 +665,11 @@ class BlockAckManager : public Object std::list m_sendBarIfDataQueued; ///< list of BA agreements for which a BAR shall ///< only be sent if data is queued + /// List of received GCR BlockAck frames indexed by originator + using GcrBlockAcks = std::map; + std::map + m_gcrBlockAcks; ///< received GCR Block ACKs + uint8_t m_blockAckThreshold; ///< block ack threshold Ptr m_queue; ///< queue Callback>