diff --git a/src/wifi/model/block-ack-manager.cc b/src/wifi/model/block-ack-manager.cc index 165659dd4..f03b475e9 100644 --- a/src/wifi/model/block-ack-manager.cc +++ b/src/wifi/model/block-ack-manager.cc @@ -195,9 +195,22 @@ BlockAckManager::UpdateAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Ad agreement.SetBufferSize (respHdr->GetBufferSize () + 1); agreement.SetTimeout (respHdr->GetTimeout ()); agreement.SetAmsduSupport (respHdr->IsAmsduSupported ()); - // update the starting sequence number because some frames may have been sent - // under Normal Ack policy after the transmission of the ADDBA Request frame - agreement.SetStartingSequence (m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient)); + // When the Add BA Response is received, there may be a packet transmitted + // under the normal ack policy that needs to be retransmitted. If so, such + // packet is placed in the retransmit queue. If this is the case, the starting + // sequence number is the sequence number of such packet. Otherwise, it is + // the sequence number that will be assigned to the next packet to be transmitted. + uint16_t startSeq; + WifiMacQueue::ConstIterator mpduIt = m_retryPackets->PeekByTidAndAddress (tid, recipient); + if (mpduIt != m_retryPackets->end ()) + { + startSeq = (*mpduIt)->GetHeader ().GetSequenceNumber (); + } + else + { + startSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient); + } + agreement.SetStartingSequence (startSeq); agreement.InitTxWindow (); if (respHdr->IsImmediateBlockAck ()) { diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index 532135b8c..9ea010259 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -474,6 +474,12 @@ QosTxop::NotifyAccessGranted (void) NS_LOG_DEBUG ("the lifetime of current packet expired"); m_currentPacket = 0; } + // If the current packet is a QoS Data frame, then there must be no block ack agreement + // established with the receiver for the TID of the packet. Indeed, retransmission + // of MPDUs sent under a block ack agreement is handled through the retransmit queue. + NS_ASSERT (m_currentPacket == 0 || !m_currentHdr.IsQosData () + || !GetBaAgreementEstablished (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ())); + if (m_currentPacket == 0) { if (m_baManager->HasBar (m_currentBar)) @@ -1412,6 +1418,22 @@ QosTxop::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address r if (respHdr->GetStatusCode ().IsSuccess ()) { NS_LOG_DEBUG ("block ack agreement established with " << recipient); + // Even though a (destination, TID) pair is "blocked" (i.e., no more packets + // are sent) when an Add BA Request is sent to the destination, + // the current packet may still be non-null when the Add BA Response is received. + // In fact, if the Add BA Request timer expires, the (destination, TID) pair is + // "unblocked" and packets to the destination are sent again (under normal + // ack policy). Thus, there may be a packet needing to be retransmitted + // when the Add BA Response is received. If this is the case, let the Block + // Ack manager handle its retransmission. + if (m_currentPacket != 0 && m_currentHdr.IsQosData () + && m_currentHdr.GetAddr1 () == recipient && m_currentHdr.GetQosTid () == tid) + { + Ptr mpdu = Create (m_currentPacket, m_currentHdr, + m_currentPacketTimestamp); + m_baManager->GetRetransmitQueue ()->Enqueue (mpdu); + m_currentPacket = 0; + } m_baManager->UpdateAgreement (respHdr, recipient); } else