diff --git a/src/wifi/model/ht/ht-frame-exchange-manager.cc b/src/wifi/model/ht/ht-frame-exchange-manager.cc index d46d8213f..8bdab7d7f 100644 --- a/src/wifi/model/ht/ht-frame-exchange-manager.cc +++ b/src/wifi/model/ht/ht-frame-exchange-manager.cc @@ -64,6 +64,10 @@ void HtFrameExchangeManager::DoDispose() { NS_LOG_FUNCTION(this); + if (m_flushGroupcastMpdusEvent.IsPending()) + { + m_flushGroupcastMpdusEvent.Cancel(); + } m_pendingAddBaResp.clear(); m_msduAggregator = nullptr; m_mpduAggregator = nullptr; @@ -1938,7 +1942,56 @@ HtFrameExchangeManager::EndReceiveAmpdu(Ptr psdu, GetWifiRemoteStationManager()->GetBlockAckTxVector(psdu->GetAddr2(), txVector), rxSignalInfo.snr); } + else if (psdu->GetAddr1().IsGroup() && (ackPolicy == WifiMacHeader::NO_ACK)) + { + // groupcast A-MPDU received + m_flushGroupcastMpdusEvent.Cancel(); + + /* + * There might be pending MPDUs from a previous groupcast transmission + * that have not been forwarded up yet (e.g. all transmission attempts + * of a given MPDU have failed). For groupcast transmissions using GCR-UR service, + * transmitter keeps advancing its window since there is no feedback from the + * recipients. In order to forward up previously received groupcast MPDUs and avoid + * following MPDUs not to be forwarded up, we flush the recipient window. The sequence + * number to use can easily be deduced since sequence number of groupcast MPDUs are + * consecutive. + */ + const auto startSeq = psdu->GetHeader(0).GetSequenceNumber(); + const auto groupAddress = psdu->GetHeader(0).IsQosAmsdu() + ? (*psdu->begin())->begin()->second.GetDestinationAddr() + : psdu->GetAddr1(); + FlushGroupcastMpdus(groupAddress, psdu->GetAddr2(), tid, startSeq); + + /* + * In case all MPDUs of all following transmissions are corrupted or + * if no following groupcast transmission happens, some groupcast MPDUs + * of the currently received A-MPDU would never be forwarded up. To prevent this, + * we schedule a flush of the recipient window once the MSDU lifetime limit elapsed. + */ + const auto stopSeq = (startSeq + perMpduStatus.size()) % 4096; + const auto maxDelay = m_mac->GetQosTxop(tid)->GetWifiMacQueue()->GetMaxDelay(); + m_flushGroupcastMpdusEvent = + Simulator::Schedule(maxDelay, + &HtFrameExchangeManager::FlushGroupcastMpdus, + this, + groupAddress, + psdu->GetAddr2(), + tid, + stopSeq); + } } } +void +HtFrameExchangeManager::FlushGroupcastMpdus(const Mac48Address& groupAddress, + const Mac48Address& originator, + uint8_t tid, + uint16_t seq) +{ + NS_LOG_FUNCTION(this << groupAddress << originator << tid << seq); + // We can flush the recipient window by indicating the reception of an implicit GCR BAR + GetBaManager(tid)->NotifyGotBlockAckRequest(originator, tid, seq, groupAddress); +} + } // namespace ns3 diff --git a/src/wifi/model/ht/ht-frame-exchange-manager.h b/src/wifi/model/ht/ht-frame-exchange-manager.h index 94e8ea8cd..98ee10a07 100644 --- a/src/wifi/model/ht/ht-frame-exchange-manager.h +++ b/src/wifi/model/ht/ht-frame-exchange-manager.h @@ -372,6 +372,22 @@ class HtFrameExchangeManager : public QosFrameExchangeManager */ virtual void MissedBlockAck(Ptr psdu, const WifiTxVector& txVector); + /** + * Perform required actions to ensure the receiver window is flushed when a groupcast A-MPDU is + * received via the GCR service. If there are pending groupcast MPDUs from that recipient and + * that traffic ID, these MPDUs are forwarded up, by assuming an implicit BAR from the + * originator. + * + * @param groupAddress the destination group address of the MPDUs + * @param originator MAC address of the sender of the groupcast MPDUs + * @param tid Traffic ID + * @param seq the starting sequence number of the recipient window + */ + void FlushGroupcastMpdus(const Mac48Address& groupAddress, + const Mac48Address& originator, + uint8_t tid, + uint16_t seq); + /// agreement key typedef (MAC address and TID) typedef std::pair AgreementKey; @@ -390,6 +406,9 @@ class HtFrameExchangeManager : public QosFrameExchangeManager Ptr m_psdu; //!< the A-MPDU being transmitted WifiTxParameters m_txParams; //!< the TX parameters for the current frame + + EventId m_flushGroupcastMpdusEvent; //!< the event to flush pending groupcast MPDUs from + //!< previously received A-MPDU }; } // namespace ns3