From d6c31ad130abfe1a804310db54b14faa02ad29a4 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Fri, 19 Apr 2019 12:03:25 +0200 Subject: [PATCH] wifi: QosTxop does not return packets outside of the current transmit window Also, make use of the new variants of the WifiMacQueue methods and remove unused BlockAckManager methods --- src/wifi/model/block-ack-manager.cc | 178 +-------------------------- src/wifi/model/block-ack-manager.h | 38 ++---- src/wifi/model/qos-txop.cc | 181 ++++++++++++++++++++-------- src/wifi/model/qos-txop.h | 17 +-- 4 files changed, 151 insertions(+), 263 deletions(-) diff --git a/src/wifi/model/block-ack-manager.cc b/src/wifi/model/block-ack-manager.cc index 4e99257df..0cad3cb06 100644 --- a/src/wifi/model/block-ack-manager.cc +++ b/src/wifi/model/block-ack-manager.cc @@ -222,6 +222,12 @@ BlockAckManager::UpdateAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Ad m_unblockPackets (recipient, tid); } +Ptr +BlockAckManager::GetRetransmitQueue (void) +{ + return m_retryPackets; +} + void BlockAckManager::StorePacket (Ptr mpdu) { @@ -252,178 +258,6 @@ BlockAckManager::StorePacket (Ptr mpdu) } } -Ptr -BlockAckManager::GetNextPacket (bool removePacket) -{ - NS_LOG_FUNCTION (this << removePacket); - Ptr item; - uint8_t tid; - Mac48Address recipient; - CleanupBuffers (); - if (!m_retryPackets->IsEmpty ()) - { - NS_LOG_DEBUG ("Retry buffer size is " << m_retryPackets->GetNPackets ()); - WifiMacQueue::ConstIterator it = m_retryPackets->begin (); - while (it != m_retryPackets->end ()) - { - if ((*it)->GetHeader ().IsQosData ()) - { - tid = (*it)->GetHeader ().GetQosTid (); - } - else - { - NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data"); - } - recipient = (*it)->GetHeader ().GetAddr1 (); - AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid)); - NS_ASSERT (agreement != m_agreements.end ()); - if (removePacket) - { - if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (), (*it)->GetHeader ().GetSequenceNumber ())) - { - //Standard says the originator should not send a packet with seqnum < winstart - NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " - << (*it)->GetHeader ().GetSequenceNumber () << " " - << agreement->second.first.GetStartingSequence ()); - agreement->second.second.remove ((*it)); - it = m_retryPackets->Remove (it); - continue; - } - else if (((((*it)->GetHeader ().GetSequenceNumber () - agreement->second.first.GetStartingSequence ()) + 4096) % 4096) > (agreement->second.first.GetBufferSize () - 1)) - { - agreement->second.first.SetStartingSequence ((*it)->GetHeader ().GetSequenceNumber ()); - } - } - item = *it; - item->GetHeader ().SetRetry (); - if (item->GetHeader ().IsQosData ()) - { - tid = item->GetHeader ().GetQosTid (); - } - else - { - NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data"); - } - recipient = item->GetHeader ().GetAddr1 (); - if (!agreement->second.first.IsHtSupported () - && (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED) - || SwitchToBlockAckIfNeeded (recipient, tid, item->GetHeader ().GetSequenceNumber ()))) - { - item->GetHeader ().SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); - } - else - { - /* From section 9.10.3 in IEEE802.11e standard: - * In order to improve efficiency, originators using the Block Ack facility - * may send MPDU frames with the Ack Policy subfield in QoS control frames - * set to Normal Ack if only a few MPDUs are available for transmission.[...] - * When there are sufficient number of MPDUs, the originator may switch back to - * the use of Block Ack. - */ - item->GetHeader ().SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); - if (removePacket) - { - AgreementsI i = m_agreements.find (std::make_pair (recipient, tid)); - i->second.second.remove (*it); - } - } - if (removePacket) - { - NS_LOG_INFO ("Retry packet seq = " << item->GetHeader ().GetSequenceNumber ()); - it = m_retryPackets->Remove (it); - NS_LOG_DEBUG ("Removed one packet, retry buffer size = " << m_retryPackets->GetNPackets ()); - } - break; - } - } - return item; -} - -Ptr -BlockAckManager::PeekNextPacketByTidAndAddress (uint8_t tid, Mac48Address recipient) -{ - NS_LOG_FUNCTION (this); - Ptr item = 0; - CleanupBuffers (); - AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid)); - NS_ASSERT (agreement != m_agreements.end ()); - WifiMacQueue::ConstIterator it = m_retryPackets->begin (); - for (; it != m_retryPackets->end (); it++) - { - if (!(*it)->GetHeader ().IsQosData ()) - { - NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data"); - } - if ((*it)->GetHeader ().GetAddr1 () == recipient && (*it)->GetHeader ().GetQosTid () == tid) - { - if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (), (*it)->GetHeader ().GetSequenceNumber ())) - { - //standard says the originator should not send a packet with seqnum < winstart - NS_LOG_DEBUG ("The Retry packet have sequence number < WinStartO --> Discard " - << (*it)->GetHeader ().GetSequenceNumber () << " " - << agreement->second.first.GetStartingSequence ()); - agreement->second.second.remove ((*it)); - it = m_retryPackets->Remove (it); - it--; - continue; - } - else if (((((*it)->GetHeader ().GetSequenceNumber () - agreement->second.first.GetStartingSequence ()) + 4096) % 4096) > (agreement->second.first.GetBufferSize () - 1)) - { - agreement->second.first.SetStartingSequence ((*it)->GetHeader ().GetSequenceNumber ()); - } - WifiMacHeader hdr = (*it)->GetHeader (); - hdr.SetRetry (); - item = Create ((*it)->GetPacket (), hdr, (*it)->GetTimeStamp ()); - NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ()); - if (!agreement->second.first.IsHtSupported () - && (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED) - || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ()))) - { - hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); - } - else - { - /* From section 9.10.3 in IEEE802.11e standard: - * In order to improve efficiency, originators using the Block Ack facility - * may send MPDU frames with the Ack Policy subfield in QoS control frames - * set to Normal Ack if only a few MPDUs are available for transmission.[...] - * When there are sufficient number of MPDUs, the originator may switch back to - * the use of Block Ack. - */ - hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); - } - NS_LOG_DEBUG ("Peeked one packet from retry buffer size = " << m_retryPackets->GetNPackets () ); - return item; - } - } - return item; -} - -bool -BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber) -{ - NS_LOG_FUNCTION (this << seqnumber); - WifiMacQueue::ConstIterator it = m_retryPackets->begin (); - for (; it != m_retryPackets->end (); it++) - { - if (!(*it)->GetHeader ().IsQosData ()) - { - NS_FATAL_ERROR ("Packet in blockAck manager retry queue is not Qos Data"); - } - if ((*it)->GetHeader ().GetAddr1 () == recipient && (*it)->GetHeader ().GetQosTid () == tid - && (*it)->GetHeader ().GetSequenceNumber () == seqnumber) - { - WifiMacHeader hdr = (*it)->GetHeader (); - AgreementsI i = m_agreements.find (std::make_pair (recipient, tid)); - i->second.second.remove ((*it)); - m_retryPackets->Remove (it); - NS_LOG_DEBUG ("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << +tid << " " << recipient << " Buffer Size = " << m_retryPackets->GetNPackets ()); - return true; - } - } - return false; -} - bool BlockAckManager::HasBar (Bar &bar, bool remove) { diff --git a/src/wifi/model/block-ack-manager.h b/src/wifi/model/block-ack-manager.h index 117c9cfc8..a68ededb5 100644 --- a/src/wifi/model/block-ack-manager.h +++ b/src/wifi/model/block-ack-manager.h @@ -153,15 +153,6 @@ public: * if the packet, in a block ack frame, is indicated by recipient as not received. */ void StorePacket (Ptr mpdu); - /** - * \param removePacket flag to indicate whether the packet should be removed from the queue. - * - * \return the packet - * - * This methods returns a packet (if exists) indicated as not received in - * corresponding block ack bitmap. - */ - Ptr GetNextPacket (bool removePacket); /** * Returns true if the BAR is scheduled. Returns false otherwise. * @@ -290,6 +281,12 @@ public: * and buffered packets) is greater of nPackets, they are transmitted using block ack mechanism. */ void SetBlockAckThreshold (uint8_t nPackets); + /** + * \return the retransmit queue. + * + * Return the retransmit queue. + */ + Ptr GetRetransmitQueue (void); /** * \param queue The WifiMacQueue object. @@ -355,27 +352,8 @@ public: */ bool AlreadyExists (uint16_t currentSeq, Mac48Address recipient, uint8_t tid) const; /** - * Remove a packet after you peek in the queue and get it - * \param tid the Traffic ID - * \param recipient the destination address - * \param seqnumber sequence number - * \returns true if a packet was removed - */ - bool RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber); - /** - * Peek in retransmit queue and get the next packet having address indicated - * by type equals to addr, and tid equals to tid. - * This method doesn't remove the packet from this queue. - * - * \param hdr wifi mac header - * \param tid Traffic ID - * \param timestamp timestamp - * - * \returns Ptr - */ - Ptr PeekNextPacketByTidAndAddress (uint8_t tid, Mac48Address recipient); - /** - * This function returns true if the lifetime of the packets a BAR refers to didn't expire yet else it returns false. + * This function returns true if the lifetime of the packets a BAR refers to didn't + * expire yet otherwise it returns false. * If it return false then the BAR will be discarded (i.e. will not be re-transmitted) * * \param tid Traffic ID diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index fd05e583a..507782bb1 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -173,17 +173,36 @@ QosTxop::PeekNextSequenceNumberFor (const WifiMacHeader *hdr) return m_txMiddle->PeekNextSequenceNumberFor (hdr); } -Ptr -QosTxop::PeekNextRetransmitPacket (uint8_t tid, Mac48Address recipient) +bool +QosTxop::IsQosOldPacket (Ptr mpdu) { - return m_baManager->PeekNextPacketByTidAndAddress (tid, recipient); + NS_LOG_FUNCTION (this << *mpdu); + + if (!mpdu->GetHeader ().IsQosData ()) + { + return false; + } + + Mac48Address recipient = mpdu->GetHeader ().GetAddr1 (); + uint8_t tid = mpdu->GetHeader ().GetQosTid (); + + if (!GetBaAgreementEstablished (recipient, tid)) + { + return false; + } + + if (QosUtilsIsOldPacket (GetBaStartingSequence (recipient, tid), + mpdu->GetHeader ().GetSequenceNumber ())) + { + return true; + } + return false; } Ptr QosTxop::PeekNextFrame (void) { NS_LOG_FUNCTION (this); - Ptr item; WifiMacQueue::ConstIterator it; // check if there is a packet in the MacLow aggregation queue @@ -192,92 +211,131 @@ QosTxop::PeekNextFrame (void) if (QosUtilsMapTidToAc (tid) == m_ac) { it = m_low->GetAggregateQueue ()->PeekByTid (tid); + // remove old packets + while (it != m_low->GetAggregateQueue ()->end () && IsQosOldPacket (*it)) + { + NS_LOG_DEBUG ("removing an old packet from MacLow aggregation queue: " << **it); + it = m_low->GetAggregateQueue ()->Remove (it); + it = m_low->GetAggregateQueue ()->PeekByTid (tid, it); + } if (it != m_low->GetAggregateQueue ()->end ()) { - item = *it; - break; + NS_LOG_DEBUG ("packet peeked from MacLow aggregation queue: " << **it); + return *it; } } } - if (item != 0) - { - NS_LOG_DEBUG ("packet peeked from MacLow aggregation queue, " << *item); - return item; - } - // otherwise, check if there is a packet in the BlockAckManager retransmit queue - item = m_baManager->GetNextPacket (false); - - if (item != 0) + it = m_baManager->GetRetransmitQueue ()->PeekFirstAvailable (); + // remove old packets + while (it != m_baManager->GetRetransmitQueue ()->end () && IsQosOldPacket (*it)) { - NS_LOG_DEBUG ("packet peeked from BlockAckManager retransmit queue: " << *item); - return item; + NS_LOG_DEBUG ("removing an old packet from BlockAckManager retransmit queue: " << **it); + it = m_baManager->GetRetransmitQueue ()->Remove (it); + it = m_baManager->GetRetransmitQueue ()->PeekFirstAvailable (nullptr, it); + } + if (it != m_baManager->GetRetransmitQueue ()->end ()) + { + NS_LOG_DEBUG ("packet peeked from BlockAckManager retransmit queue: " << **it); + return *it; } // otherwise, check if there is a packet in the EDCA queue it = m_queue->PeekFirstAvailable (m_qosBlockedDestinations); - if (it != m_queue->end ()) { - item = *it; - // set the sequence number by just peeking the next value - uint16_t sequence = m_txMiddle->PeekNextSequenceNumberFor (&item->GetHeader ()); - WifiMacHeader hdr = item->GetHeader (); + // peek the next sequence number and check if it is within the transmit window + // in case of QoS data frame + uint16_t sequence = m_txMiddle->PeekNextSequenceNumberFor (&(*it)->GetHeader ()); + if ((*it)->GetHeader ().IsQosData ()) + { + Mac48Address recipient = (*it)->GetHeader ().GetAddr1 (); + uint8_t tid = (*it)->GetHeader ().GetQosTid (); + + if (GetBaAgreementEstablished (recipient, tid) + && !IsInWindow (sequence, GetBaStartingSequence (recipient, tid), GetBaBufferSize (recipient, tid))) + { + NS_LOG_DEBUG ("packet beyond the end of the current transmit window"); + return 0; + } + } + + WifiMacHeader hdr = (*it)->GetHeader (); hdr.SetSequenceNumber (sequence); hdr.SetFragmentNumber (0); hdr.SetNoMoreFragments (); hdr.SetNoRetry (); - item = Create (item->GetPacket (), hdr, item->GetTimeStamp ()); + Ptr item = Create ((*it)->GetPacket (), hdr, (*it)->GetTimeStamp ()); NS_LOG_DEBUG ("packet peeked from EDCA queue: " << *item); + return item; } - return item; + return 0; } Ptr QosTxop::PeekNextFrameByTidAndAddress (uint8_t tid, Mac48Address recipient) { NS_LOG_FUNCTION (this << +tid << recipient); - Ptr item; + WifiMacQueue::ConstIterator it; // check if there is a packet in the MacLow aggregation queue - WifiMacQueue::ConstIterator it = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); - + it = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); + // remove old packets + while (it != m_low->GetAggregateQueue ()->end () && IsQosOldPacket (*it)) + { + NS_LOG_DEBUG ("removing an old packet from MacLow aggregation queue: " << **it); + it = m_low->GetAggregateQueue ()->Remove (it); + it = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient, it); + } if (it != m_low->GetAggregateQueue ()->end ()) { - item = *it; - NS_LOG_DEBUG ("packet peeked from MacLow aggregation queue, " << *item); - return item; + NS_LOG_DEBUG ("packet peeked from MacLow aggregation queue: " << **it); + return *it; } // otherwise, check if there is a packet in the BlockAckManager retransmit queue - item = m_baManager->PeekNextPacketByTidAndAddress (tid, recipient); - - if (item != 0) + it = m_baManager->GetRetransmitQueue ()->PeekByTidAndAddress (tid, recipient); + // remove old packets + while (it != m_baManager->GetRetransmitQueue ()->end () && IsQosOldPacket (*it)) { - NS_LOG_DEBUG ("packet peeked from BlockAckManager retransmit queue: " << *item); - return item; + NS_LOG_DEBUG ("removing an old packet from BlockAckManager retransmit queue: " << **it); + it = m_baManager->GetRetransmitQueue ()->Remove (it); + it = m_baManager->GetRetransmitQueue ()->PeekByTidAndAddress (tid, recipient, it); + } + if (it != m_baManager->GetRetransmitQueue ()->end ()) + { + NS_LOG_DEBUG ("packet peeked from BlockAckManager retransmit queue: " << **it); + return *it; } // otherwise, check if there is a packet in the EDCA queue it = m_queue->PeekByTidAndAddress (tid, recipient); - if (it != m_queue->end ()) { - item = *it; - // set the sequence number by just peeking the next value - uint16_t sequence = m_txMiddle->PeekNextSequenceNumberFor (&item->GetHeader ()); - WifiMacHeader hdr = item->GetHeader (); + // peek the next sequence number and check if it is within the transmit window + // in case of QoS data frame + uint16_t sequence = m_txMiddle->PeekNextSequenceNumberFor (&(*it)->GetHeader ()); + if ((*it)->GetHeader ().IsQosData () + && GetBaAgreementEstablished (recipient, tid) + && !IsInWindow (sequence, GetBaStartingSequence (recipient, tid), GetBaBufferSize (recipient, tid))) + { + NS_LOG_DEBUG ("packet beyond the end of the current transmit window"); + return 0; + } + + WifiMacHeader hdr = (*it)->GetHeader (); hdr.SetSequenceNumber (sequence); hdr.SetFragmentNumber (0); hdr.SetNoMoreFragments (); hdr.SetNoRetry (); - item = Create (item->GetPacket (), hdr, item->GetTimeStamp ()); + Ptr item = Create ((*it)->GetPacket (), hdr, (*it)->GetTimeStamp ()); NS_LOG_DEBUG ("packet peeked from EDCA queue: " << *item); + return item; } - return item; + return 0; } bool @@ -356,6 +414,7 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto Mac48Address recipient = peekedItem->GetHeader ().GetAddr1 (); Ptr item; Ptr testItem; + WifiMacQueue::ConstIterator testIt; // the packet can only have been peeked from the Block Ack manager retransmit // queue or the MacLow aggregation queue if: @@ -366,26 +425,32 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto && GetBaAgreementEstablished (recipient, peekedItem->GetHeader ().GetQosTid ())) { uint8_t tid = peekedItem->GetHeader ().GetQosTid (); - WifiMacQueue::ConstIterator testIt = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); + testIt = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); if (testIt != m_low->GetAggregateQueue ()->end ()) { testItem = *testIt; // if not null, the test packet must equal the peeked packet NS_ASSERT (testItem->GetPacket () == peekedItem->GetPacket ()); - item = m_low->GetAggregateQueue ()->DequeueByTidAndAddress (tid, recipient); + // we should not be asked to dequeue an old packet + NS_ASSERT (!QosUtilsIsOldPacket (GetBaStartingSequence (recipient, tid), + testItem->GetHeader ().GetSequenceNumber ())); + item = m_low->GetAggregateQueue ()->Dequeue (testIt); NS_LOG_DEBUG ("dequeued from aggregation queue: " << *item); return item; } - testItem = m_baManager->PeekNextPacketByTidAndAddress (tid, recipient); + testIt = m_baManager->GetRetransmitQueue ()->PeekByTidAndAddress (tid, recipient); - if (testItem) + if (testIt != m_baManager->GetRetransmitQueue ()->end ()) { + testItem = *testIt; // if not null, the test packet must equal the peeked packet NS_ASSERT (testItem->GetPacket () == peekedItem->GetPacket ()); - item = Create (*peekedItem); - m_baManager->RemovePacket (tid, recipient, testItem->GetHeader ().GetSequenceNumber ()); + // we should not be asked to dequeue an old packet + NS_ASSERT (!QosUtilsIsOldPacket (GetBaStartingSequence (recipient, tid), + testItem->GetHeader ().GetSequenceNumber ())); + item = m_baManager->GetRetransmitQueue ()->Dequeue (testIt); NS_LOG_DEBUG ("dequeued from BA manager queue: " << *item); return item; } @@ -394,15 +459,26 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto // NOTE if frames other than QoS Data frame can be aggregated into A-MPDUs and hence // potentially stored in the MacLow aggregation queue, then handle them here - // the packet has been peeked from the EDCA queue. If it is a QoS Data frame and - // it is not a broadcast frame, attempt A-MSDU aggregation if aggregate is true + // the packet has been peeked from the EDCA queue. + uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor (&peekedItem->GetHeader ()); + + // If it is a QoS Data frame and it is not a broadcast frame, attempt A-MSDU + // aggregation if aggregate is true if (peekedItem->GetHeader ().IsQosData ()) { uint8_t tid = peekedItem->GetHeader ().GetQosTid (); - WifiMacQueue::ConstIterator testIt = m_queue->PeekByTidAndAddress (tid, recipient); + testIt = m_queue->PeekByTidAndAddress (tid, recipient); NS_ASSERT (testIt != m_queue->end () && (*testIt)->GetPacket () == peekedItem->GetPacket ()); + // check if the peeked packet is within the transmit window + if (GetBaAgreementEstablished (recipient, tid) + && !IsInWindow (sequence, GetBaStartingSequence (recipient, tid), GetBaBufferSize (recipient, tid))) + { + NS_LOG_DEBUG ("packet beyond the end of the current transmit window"); + return 0; + } + // try A-MSDU aggregation if (m_low->GetMsduAggregator () != 0 && !recipient.IsBroadcast () && aggregate) { @@ -415,7 +491,7 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto } else // aggregation was not attempted or failed { - item = m_queue->DequeueByTidAndAddress (tid, recipient); + item = m_queue->Dequeue (testIt); } } else @@ -428,7 +504,6 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto // Assign a sequence number to the MSDU or A-MSDU dequeued from the EDCA queue NS_ASSERT (item != 0); - uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor (&item->GetHeader ()); item->GetHeader ().SetSequenceNumber (sequence); item->GetHeader ().SetFragmentNumber (0); item->GetHeader ().SetNoMoreFragments (); diff --git a/src/wifi/model/qos-txop.h b/src/wifi/model/qos-txop.h index 9407c2100..308a2f2ad 100644 --- a/src/wifi/model/qos-txop.h +++ b/src/wifi/model/qos-txop.h @@ -379,14 +379,6 @@ public: * \return the next sequence number. */ uint16_t PeekNextSequenceNumberFor (const WifiMacHeader *hdr); - /** - * Peek in retransmit queue and get the next packet without removing it from the queue. - * - * \param tid traffic ID. - * \param recipient the receiver station address. - * \returns the packet. - */ - Ptr PeekNextRetransmitPacket (uint8_t tid, Mac48Address recipient); /** * Peek the next frame to transmit from the Block Ack manager retransmit * queue first and, if not found, from the EDCA queue. @@ -541,6 +533,15 @@ private: * \param bar the block ack request. */ void SendBlockAckRequest (const Bar &bar); + /** + * Check if the given MPDU is to be considered old according to the current + * starting sequence number of the transmit window, provided that a block ack + * agreement has been established with the recipient for the given TID. + * + * \param mpdu the given MPDU + * \return true if the MPDU is to be considered old, false otherwise + */ + bool IsQosOldPacket (Ptr mpdu); /** * For now is typically invoked to complete transmission of a packets sent with ack policy * Block Ack: the packet is buffered and dcf is reset.