diff --git a/src/wifi/model/msdu-aggregator.cc b/src/wifi/model/msdu-aggregator.cc index 9743d4389..af4d59ebe 100644 --- a/src/wifi/model/msdu-aggregator.cc +++ b/src/wifi/model/msdu-aggregator.cc @@ -120,9 +120,9 @@ MsduAggregator::GetNextAmsdu (Mac48Address recipient, uint8_t tid, Ptr qosTxop = m_edca.find (QosUtilsMapTidToAc (tid))->second; Ptr queue = qosTxop->GetWifiMacQueue (); - Ptr peekedItem = queue->PeekByTidAndAddress (tid, recipient); + WifiMacQueue::ConstIterator peekedIt = queue->PeekByTidAndAddress (tid, recipient); - if (!peekedItem) + if (peekedIt == queue->end ()) { NS_LOG_DEBUG ("No packet with the given TID and address in the queue"); return 0; @@ -147,19 +147,19 @@ MsduAggregator::GetNextAmsdu (Mac48Address recipient, uint8_t tid, Ptr amsdu = Create (); uint8_t nMsdu = 0; - WifiMacHeader header = peekedItem->GetHeader (); - Time tstamp = peekedItem->GetTimeStamp (); - // We need to keep track of the first MSDU. If it is dequeued but aggregation - // fails, we need to re-insert it in the queue - Ptr first = peekedItem; + WifiMacHeader header = (*peekedIt)->GetHeader (); + Time tstamp = (*peekedIt)->GetTimeStamp (); + // We need to keep track of the first MSDU. When it is processed, it is not known + // if aggregation will succeed or not. + WifiMacQueue::ConstIterator first = peekedIt; // TODO Add support for the Max Number Of MSDUs In A-MSDU field in the Extended // Capabilities element sent by the recipient - while (peekedItem != 0) // && nMsdu < maxNMsdus + while (peekedIt != queue->end ()) { // check if aggregating the peeked MSDU violates the A-MSDU size limit - uint16_t newAmsduSize = GetSizeIfAggregated (peekedItem->GetPacket ()->GetSize (), + uint16_t newAmsduSize = GetSizeIfAggregated ((*peekedIt)->GetPacket ()->GetSize (), amsdu->GetSize ()); if (newAmsduSize > maxAmsduSize) @@ -177,36 +177,43 @@ MsduAggregator::GetNextAmsdu (Mac48Address recipient, uint8_t tid, break; } - // We can now safely aggregate the MSDU to the A-MSDU and remove it from the queue - Aggregate (peekedItem->GetPacket (), amsdu, + // We can now safely aggregate the MSDU to the A-MSDU + Aggregate ((*peekedIt)->GetPacket (), amsdu, qosTxop->MapSrcAddressForAggregation (header), qosTxop->MapDestAddressForAggregation (header)); - queue->Remove (peekedItem->GetPacket ()); - - nMsdu++; /* "The expiration of the A-MSDU lifetime timer occurs only when the lifetime * timer of all of the constituent MSDUs of the A-MSDU have expired" (Section * 10.12 of 802.11-2016) */ // The timestamp of the A-MSDU is the most recent among those of the MSDUs - tstamp = Max (tstamp, peekedItem->GetTimeStamp ()); + tstamp = Max (tstamp, (*peekedIt)->GetTimeStamp ()); - peekedItem = queue->PeekByTidAndAddress (tid, recipient); + // If it is the first MSDU, move to the next one + if (nMsdu == 0) + { + peekedIt++; + } + // otherwise, remove it from the queue + else + { + peekedIt = queue->Remove (peekedIt); + } + + nMsdu++; + + peekedIt = queue->PeekByTidAndAddress (tid, recipient, peekedIt); } if (nMsdu < 2) { NS_LOG_DEBUG ("Aggregation failed (could not aggregate at least two MSDUs)"); - - // re-insert the first MSDU in the queue if it was removed - if (nMsdu == 1) - { - queue->PushFront (Create (*first)); - } return 0; } + // Aggregation succeeded, we have to remove the first MSDU + queue->Remove (first); + header.SetQosAmsdu (); header.SetAddr3 (qosTxop->GetLow ()->GetBssid ()); diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index 467aedd53..019734e10 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -190,15 +190,17 @@ QosTxop::PeekNextFrame (void) { NS_LOG_FUNCTION (this); Ptr item; + WifiMacQueue::ConstIterator it; // check if there is a packet in the MacLow aggregation queue for (uint8_t tid = 0; tid < 8; tid++) { if (QosUtilsMapTidToAc (tid) == m_ac) { - item = m_low->GetAggregateQueue ()->PeekByTid (tid); - if (item != 0) + it = m_low->GetAggregateQueue ()->PeekByTid (tid); + if (it != m_low->GetAggregateQueue ()->end ()) { + item = *it; break; } } @@ -220,10 +222,11 @@ QosTxop::PeekNextFrame (void) } // otherwise, check if there is a packet in the EDCA queue - item = m_queue->PeekFirstAvailable (m_qosBlockedDestinations); + it = m_queue->PeekFirstAvailable (m_qosBlockedDestinations); - if (item != 0) + 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 (); @@ -245,10 +248,11 @@ QosTxop::PeekNextFrameByTidAndAddress (uint8_t tid, Mac48Address recipient) Ptr item; // check if there is a packet in the MacLow aggregation queue - item = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); + WifiMacQueue::ConstIterator it = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); - if (item != 0) + if (it != m_low->GetAggregateQueue ()->end ()) { + item = *it; NS_LOG_DEBUG ("packet peeked from MacLow aggregation queue, " << *item); return item; } @@ -263,10 +267,11 @@ QosTxop::PeekNextFrameByTidAndAddress (uint8_t tid, Mac48Address recipient) } // otherwise, check if there is a packet in the EDCA queue - item = m_queue->PeekByTidAndAddress (tid, recipient); + it = m_queue->PeekByTidAndAddress (tid, recipient); - if (item != 0) + 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 (); @@ -367,10 +372,11 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto && GetBaAgreementEstablished (recipient, peekedItem->GetHeader ().GetQosTid ())) { uint8_t tid = peekedItem->GetHeader ().GetQosTid (); - testItem = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); + WifiMacQueue::ConstIterator testIt = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); - if (testItem) + 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); @@ -399,9 +405,9 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto if (peekedItem->GetHeader ().IsQosData ()) { uint8_t tid = peekedItem->GetHeader ().GetQosTid (); - testItem = m_queue->PeekByTidAndAddress (tid, recipient); + WifiMacQueue::ConstIterator testIt = m_queue->PeekByTidAndAddress (tid, recipient); - NS_ASSERT (testItem != 0 && testItem->GetPacket () == peekedItem->GetPacket ()); + NS_ASSERT (testIt != m_queue->end () && (*testIt)->GetPacket () == peekedItem->GetPacket ()); // try A-MSDU aggregation if (m_low->GetMsduAggregator () != 0 && !recipient.IsBroadcast () && aggregate) diff --git a/src/wifi/model/wifi-mac-queue.cc b/src/wifi/model/wifi-mac-queue.cc index 2f4b89f0c..7224321d9 100644 --- a/src/wifi/model/wifi-mac-queue.cc +++ b/src/wifi/model/wifi-mac-queue.cc @@ -53,12 +53,16 @@ WifiMacQueue::GetTypeId (void) MakeEnumAccessor (&WifiMacQueue::m_dropPolicy), MakeEnumChecker (WifiMacQueue::DROP_OLDEST, "DropOldest", WifiMacQueue::DROP_NEWEST, "DropNewest")) + .AddTraceSource ("Expired", "MPDU dropped because its lifetime expired.", + MakeTraceSourceAccessor (&WifiMacQueue::m_traceExpired), + "ns3::WifiMacQueueItem::TracedCallback") ; return tid; } WifiMacQueue::WifiMacQueue () - : NS_LOG_TEMPLATE_DEFINE ("WifiMacQueue") + : m_expiredPacketsPresent (false), + NS_LOG_TEMPLATE_DEFINE ("WifiMacQueue") { } @@ -67,6 +71,8 @@ WifiMacQueue::~WifiMacQueue () NS_LOG_FUNCTION_NOARGS (); } +const WifiMacQueue::ConstIterator WifiMacQueue::EMPTY = std::list> ().end (); + void WifiMacQueue::SetMaxQueueSize (QueueSize size) { @@ -102,6 +108,7 @@ WifiMacQueue::TtlExceeded (ConstIterator &it) { NS_LOG_DEBUG ("Removing packet that stayed in the queue for too long (" << Simulator::Now () - (*it)->GetTimeStamp () << ")"); + m_traceExpired (*it); auto curr = it++; DoRemove (curr); return true; @@ -112,59 +119,57 @@ WifiMacQueue::TtlExceeded (ConstIterator &it) bool WifiMacQueue::Enqueue (Ptr item) { - NS_LOG_FUNCTION (this << item); - NS_ASSERT_MSG (GetMaxSize ().GetUnit () == QueueSizeUnit::PACKETS, - "WifiMacQueues must be in packet mode"); + NS_LOG_FUNCTION (this << *item); - QueueBase::SetMaxSize (GetMaxQueueSize ()); //Make sure QueueBase has the same maximum queue size - - // if the queue is full, remove the first stale packet (if any) encountered - // starting from the head of the queue, in order to make room for the new packet. - if (QueueBase::GetNPackets () == GetMaxSize ().GetValue ()) - { - ConstIterator it = begin (); - while (it != end () && !TtlExceeded (it)) - { - it++; - } - } - - if (QueueBase::GetNPackets () == GetMaxSize ().GetValue () && m_dropPolicy == DROP_OLDEST) - { - NS_LOG_DEBUG ("Remove the oldest item in the queue"); - DoRemove (begin ()); - } - - return DoEnqueue (end (), item); + return Insert (end (), item); } bool WifiMacQueue::PushFront (Ptr item) { - NS_LOG_FUNCTION (this << item); + NS_LOG_FUNCTION (this << *item); + + return Insert (begin (), item); +} + +bool +WifiMacQueue::Insert (ConstIterator pos, Ptr item) +{ + NS_LOG_FUNCTION (this << *item); NS_ASSERT_MSG (GetMaxSize ().GetUnit () == QueueSizeUnit::PACKETS, "WifiMacQueues must be in packet mode"); QueueBase::SetMaxSize (GetMaxQueueSize ()); //Make sure QueueBase has the same maximum queue size - // if the queue is full, remove the first stale packet (if any) encountered - // starting from the head of the queue, in order to make room for the new packet. - if (QueueBase::GetNPackets () == GetMaxSize ().GetValue ()) + // insert the item if the queue is not full + if (QueueBase::GetNPackets () < GetMaxSize ().GetValue ()) { - ConstIterator it = begin (); - while (it != end () && !TtlExceeded (it)) - { - it++; - } + return DoEnqueue (pos, item); } - if (QueueBase::GetNPackets () == GetMaxSize ().GetValue () && m_dropPolicy == DROP_OLDEST) + // the queue is full; scan the list in the attempt to remove stale packets + ConstIterator it = begin (); + while (it != end ()) + { + if (it == pos && TtlExceeded (it)) + { + return DoEnqueue (it, item); + } + if (TtlExceeded (it)) + { + return DoEnqueue (pos, item); + } + it++; + } + + // the queue is still full, remove the oldest item if the policy is drop oldest + if (m_dropPolicy == DROP_OLDEST) { NS_LOG_DEBUG ("Remove the oldest item in the queue"); DoRemove (begin ()); } - return DoEnqueue (begin (), item); + return DoEnqueue (pos, item); } Ptr @@ -186,82 +191,90 @@ Ptr WifiMacQueue::DequeueByAddress (Mac48Address dest) { NS_LOG_FUNCTION (this << dest); + ConstIterator it = PeekByAddress (dest); - for (ConstIterator it = begin (); it != end (); ) + if (it == end ()) { - if (!TtlExceeded (it)) - { - if ((*it)->GetHeader ().IsData () && (*it)->GetDestinationAddress () == dest) - { - return DoDequeue (it); - } - - it++; - } + return 0; } - NS_LOG_DEBUG ("The queue is empty"); - return 0; + return Dequeue (it); } Ptr WifiMacQueue::DequeueByTid (uint8_t tid) { NS_LOG_FUNCTION (this << +tid); - for (ConstIterator it = begin (); it != end (); ) - { - if (!TtlExceeded (it)) - { - if ((*it)->GetHeader ().IsQosData () && (*it)->GetHeader ().GetQosTid () == tid) - { - return DoDequeue (it); - } + ConstIterator it = PeekByTid (tid); - it++; - } + if (it == end ()) + { + return 0; } - NS_LOG_DEBUG ("The queue is empty"); - return 0; + return Dequeue (it); } Ptr WifiMacQueue::DequeueByTidAndAddress (uint8_t tid, Mac48Address dest) { - NS_LOG_FUNCTION (this << dest); - for (ConstIterator it = begin (); it != end (); ) - { - if (!TtlExceeded (it)) - { - if ((*it)->GetHeader ().IsQosData () && (*it)->GetDestinationAddress () == dest - && (*it)->GetHeader ().GetQosTid () == tid) - { - return DoDequeue (it); - } + NS_LOG_FUNCTION (this << +tid << dest); + ConstIterator it = PeekByTidAndAddress (tid, dest); - it++; - } + if (it == end ()) + { + return 0; } - NS_LOG_DEBUG ("The queue is empty"); - return 0; + return Dequeue (it); } Ptr WifiMacQueue::DequeueFirstAvailable (const Ptr blockedPackets) { NS_LOG_FUNCTION (this); - for (ConstIterator it = begin (); it != end (); ) - { - if (!TtlExceeded (it)) - { - if (!(*it)->GetHeader ().IsQosData () - || !blockedPackets->IsBlocked ((*it)->GetHeader ().GetAddr1 (), (*it)->GetHeader ().GetQosTid ())) - { - return DoDequeue (it); - } + ConstIterator it = PeekFirstAvailable (blockedPackets); + if (it == end ()) + { + return 0; + } + return Dequeue (it); +} + +Ptr +WifiMacQueue::Dequeue (ConstIterator pos) +{ + NS_LOG_FUNCTION (this); + + if (!m_expiredPacketsPresent) + { + if (TtlExceeded (pos)) + { + NS_LOG_DEBUG ("Packet lifetime expired"); + return 0; + } + return DoDequeue (pos); + } + + // remove stale items queued before the given position + ConstIterator it = begin (); + while (it != end ()) + { + if (it == pos) + { + // reset the flag signaling the presence of expired packets before returning + m_expiredPacketsPresent = false; + + if (TtlExceeded (it)) + { + return 0; + } + return DoDequeue (it); + } + else if (!TtlExceeded (it)) + { it++; } } - NS_LOG_DEBUG ("The queue is empty"); + NS_LOG_DEBUG ("Invalid iterator"); return 0; } @@ -277,71 +290,122 @@ WifiMacQueue::Peek (void) const { return DoPeek (it); } + // signal the presence of expired packets + m_expiredPacketsPresent = true; } NS_LOG_DEBUG ("The queue is empty"); return 0; } -Ptr -WifiMacQueue::PeekByTid (uint8_t tid) +WifiMacQueue::ConstIterator +WifiMacQueue::PeekByAddress (Mac48Address dest, ConstIterator pos) const +{ + NS_LOG_FUNCTION (this << dest); + ConstIterator it = (pos != EMPTY ? pos : begin ()); + while (it != end ()) + { + // skip packets that stayed in the queue for too long. They will be + // actually removed from the queue by the next call to a non-const method + if (Simulator::Now () <= (*it)->GetTimeStamp () + m_maxDelay) + { + if (((*it)->GetHeader ().IsData () || (*it)->GetHeader ().IsQosData ()) + && (*it)->GetDestinationAddress () == dest) + { + return it; + } + } + else + { + // signal the presence of expired packets + m_expiredPacketsPresent = true; + } + it++; + } + NS_LOG_DEBUG ("The queue is empty"); + return end (); +} + +WifiMacQueue::ConstIterator +WifiMacQueue::PeekByTid (uint8_t tid, ConstIterator pos) const { NS_LOG_FUNCTION (this << +tid); - for (ConstIterator it = begin (); it != end (); ) + ConstIterator it = (pos != EMPTY ? pos : begin ()); + while (it != end ()) { - if (!TtlExceeded (it)) + // skip packets that stayed in the queue for too long. They will be + // actually removed from the queue by the next call to a non-const method + if (Simulator::Now () <= (*it)->GetTimeStamp () + m_maxDelay) { if ((*it)->GetHeader ().IsQosData () && (*it)->GetHeader ().GetQosTid () == tid) { - return DoPeek (it); + return it; } - - it++; } + else + { + // signal the presence of expired packets + m_expiredPacketsPresent = true; + } + it++; } NS_LOG_DEBUG ("The queue is empty"); - return 0; + return end (); } -Ptr -WifiMacQueue::PeekByTidAndAddress (uint8_t tid, Mac48Address dest) +WifiMacQueue::ConstIterator +WifiMacQueue::PeekByTidAndAddress (uint8_t tid, Mac48Address dest, ConstIterator pos) const { - NS_LOG_FUNCTION (this << dest); - for (ConstIterator it = begin (); it != end (); ) + NS_LOG_FUNCTION (this << +tid << dest); + ConstIterator it = (pos != EMPTY ? pos : begin ()); + while (it != end ()) { - if (!TtlExceeded (it)) + // skip packets that stayed in the queue for too long. They will be + // actually removed from the queue by the next call to a non-const method + if (Simulator::Now () <= (*it)->GetTimeStamp () + m_maxDelay) { if ((*it)->GetHeader ().IsQosData () && (*it)->GetDestinationAddress () == dest && (*it)->GetHeader ().GetQosTid () == tid) { - return DoPeek (it); + return it; } - - it++; } + else + { + // signal the presence of expired packets + m_expiredPacketsPresent = true; + } + it++; } NS_LOG_DEBUG ("The queue is empty"); - return 0; + return end (); } -Ptr -WifiMacQueue::PeekFirstAvailable (const Ptr blockedPackets) +WifiMacQueue::ConstIterator +WifiMacQueue::PeekFirstAvailable (const Ptr blockedPackets, ConstIterator pos) const { NS_LOG_FUNCTION (this); - for (ConstIterator it = begin (); it != end (); ) + ConstIterator it = (pos != EMPTY ? pos : begin ()); + while (it != end ()) { - if (!TtlExceeded (it)) + // skip packets that stayed in the queue for too long. They will be + // actually removed from the queue by the next call to a non-const method + if (Simulator::Now () <= (*it)->GetTimeStamp () + m_maxDelay) { - if (!(*it)->GetHeader ().IsQosData () + if (!(*it)->GetHeader ().IsQosData () || !blockedPackets || !blockedPackets->IsBlocked ((*it)->GetHeader ().GetAddr1 (), (*it)->GetHeader ().GetQosTid ())) { - return DoPeek (it); + return it; } - - it++; } + else + { + // signal the presence of expired packets + m_expiredPacketsPresent = true; + } + it++; } NS_LOG_DEBUG ("The queue is empty"); - return 0; + return end (); } Ptr @@ -381,6 +445,40 @@ WifiMacQueue::Remove (Ptr packet) return false; } +WifiMacQueue::ConstIterator +WifiMacQueue::Remove (ConstIterator pos, bool removeExpired) +{ + NS_LOG_FUNCTION (this); + + if (!removeExpired) + { + ConstIterator curr = pos++; + DoRemove (curr); + return pos; + } + + // remove stale items queued before the given position + ConstIterator it = begin (); + while (it != end ()) + { + if (it == pos) + { + // reset the flag signaling the presence of expired packets before returning + m_expiredPacketsPresent = false; + + ConstIterator curr = pos++; + DoRemove (curr); + return pos; + } + else if (!TtlExceeded (it)) + { + it++; + } + } + NS_LOG_DEBUG ("Invalid iterator"); + return end (); +} + uint32_t WifiMacQueue::GetNPacketsByAddress (Mac48Address dest) { diff --git a/src/wifi/model/wifi-mac-queue.h b/src/wifi/model/wifi-mac-queue.h index f57412602..973a643f7 100644 --- a/src/wifi/model/wifi-mac-queue.h +++ b/src/wifi/model/wifi-mac-queue.h @@ -72,6 +72,12 @@ public: DROP_OLDEST }; + /// allow the usage of iterators and const iterators + using Queue::ConstIterator; + using Queue::Iterator; + using Queue::begin; + using Queue::end; + /** * \brief Set the maximum size of this queue * @@ -111,6 +117,14 @@ public: * \return true if success, false if the packet has been dropped */ bool PushFront (Ptr item); + /** + * Enqueue the given Wifi MAC queue item before the given position. + * + * \param pos the position before which the item is to be inserted + * \param item the Wifi MAC queue item to be enqueued + * \return true if success, false if the packet has been dropped + */ + bool Insert (ConstIterator pos, Ptr item); /** * Dequeue the packet in the front of the queue. * @@ -118,8 +132,8 @@ public: */ Ptr Dequeue (void); /** - * Search and return, if present in the queue, the first packet having the - * address indicated by type equal to addr. + * Search and return, if present in the queue, the first packet (either Data + * frame or QoS Data frame) having the receiver address equal to addr. * This method removes the packet from the queue. * It is typically used by ns3::Txop during the CF period. * @@ -163,7 +177,16 @@ public: * * \return packet */ - Ptr DequeueFirstAvailable (const Ptr blockedPackets); + Ptr DequeueFirstAvailable (const Ptr blockedPackets = nullptr); + /** + * Dequeue the item at position pos in the queue. Return a null + * pointer if the given iterator is invalid, the queue is empty or the + * lifetime of the item pointed to by the given iterator is expired. + * + * \param pos the position of the item to be dequeued + * \return the dequeued item, if any + */ + Ptr Dequeue (WifiMacQueue::ConstIterator pos); /** * Peek the packet in the front of the queue. The packet is not removed. * @@ -171,36 +194,55 @@ public: */ Ptr Peek (void) const; /** - * Search and return, if present in the queue, the first packet having the - * tid equal to tid. This method does not remove the packet from the queue. + * Search and return, if present in the queue, the first packet (either Data + * frame or QoS Data frame) having the receiver address equal to addr. + * If pos is a valid iterator, the search starts from the packet pointed + * to by the given iterator. + * This method does not remove the packet from the queue. * - * \param tid the given TID + * \param dest the given destination + * \param pos the iterator pointing to the packet the search starts from * - * \return packet + * \return an iterator pointing to the peeked packet */ - Ptr PeekByTid (uint8_t tid); + ConstIterator PeekByAddress (Mac48Address dest, ConstIterator pos = EMPTY) const; /** * Search and return, if present in the queue, the first packet having the - * address indicated by type equal to addr, and tid - * equal to tid. This method does not remove the packet from the queue. - * It is typically used by ns3::QosTxop in order to perform correct MSDU - * aggregation (A-MSDU). + * tid equal to tid. If pos is a valid iterator, the search starts + * from the packet pointed to by the given iterator. + * This method does not remove the packet from the queue. + * + * \param tid the given TID + * \param pos the iterator pointing to the packet the search starts from + * + * \return an iterator pointing to the peeked packet + */ + ConstIterator PeekByTid (uint8_t tid, ConstIterator pos = EMPTY) const; + /** + * Search and return, if present in the queue, the first packet having the + * receiver address equal to dest, and tid equal to tid. + * If pos is a valid iterator, the search starts from the packet pointed + * to by the given iterator. This method does not remove the packet from the queue. + * It is typically used by ns3::QosTxop in order to perform correct MSDU aggregation + * (A-MSDU). * * \param tid the given TID * \param dest the given destination + * \param pos the iterator pointing to the packet the search starts from * - * \return packet + * \return an iterator pointing to the peeked packet */ - Ptr PeekByTidAndAddress (uint8_t tid, - Mac48Address dest); + ConstIterator PeekByTidAndAddress (uint8_t tid, Mac48Address dest, ConstIterator pos = EMPTY) const; /** * Return first available packet for transmission. The packet is not removed from queue. * * \param blockedPackets + * \param pos the iterator pointing to the packet the search starts from * - * \return packet + * \return an iterator pointing to the peeked packet */ - Ptr PeekFirstAvailable (const Ptr blockedPackets); + ConstIterator PeekFirstAvailable (const Ptr blockedPackets = nullptr, + ConstIterator pos = EMPTY) const; /** * Remove the packet in the front of the queue. * @@ -217,6 +259,17 @@ public: * \return true if the packet was removed, false otherwise */ bool Remove (Ptr packet); + /** + * Remove the item at position pos in the queue and return an iterator + * pointing to the item following the removed one. If removeExpired is + * true, all the items in the queue from the head to the given position are + * removed if their lifetime expired. + * + * \param pos the position of the item to be removed + * \param removeExpired true to remove expired items + * \return an iterator pointing to the item following the removed one + */ + ConstIterator Remove (ConstIterator pos, bool removeExpired = false); /** * Return the number of packets having destination address specified by * dest. @@ -272,6 +325,11 @@ private: QueueSize m_maxSize; //!< max queue size Time m_maxDelay; //!< Time to live for packets in the queue DropPolicy m_dropPolicy; //!< Drop behavior of queue + mutable bool m_expiredPacketsPresent; //!> True if expired packets are in the queue + static const ConstIterator EMPTY; //!< Invalid iterator to signal an empty queue + + /// Traced callback: fired when a packet is dropped due to lifetime expiration + TracedCallback > m_traceExpired; NS_LOG_TEMPLATE_DECLARE; //!< redefinition of the log component };