diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index 6f3a5f60d..b9a00abfd 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -95,6 +95,7 @@ QosTxop::QosTxop () : m_typeOfStation (STA), m_blockAckType (COMPRESSED_BLOCK_ACK), m_startTxop (Seconds (0)), + m_txopDuration (Seconds (0)), m_isAccessRequestedForRts (false), m_currentIsFragmented (false) { @@ -415,6 +416,88 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto return item; } +Ptr +QosTxop::PeekNextMpdu (uint8_t tid, Mac48Address recipient) +{ + return PeekNextMpdu ({nullptr, WifiMacQueue::EMPTY}, tid, recipient); +} + +Ptr +QosTxop::PeekNextMpdu (WifiMacQueueItem::QueueIteratorPair queueIt, uint8_t tid, Mac48Address recipient) +{ + NS_LOG_FUNCTION (this << +tid << recipient); + + // lambda to peek the next frame + auto peek = [this, &tid, &recipient, &queueIt] () -> WifiMacQueue::ConstIterator + { + if (tid == 8 && recipient.IsBroadcast ()) // undefined TID and recipient + { + return queueIt.queue->PeekFirstAvailable (m_qosBlockedDestinations, queueIt.it); + } + if (m_qosBlockedDestinations->IsBlocked (recipient, tid)) + { + return queueIt.queue->end (); + } + return queueIt.queue->PeekByTidAndAddress (tid, recipient, queueIt.it); + }; + + if (queueIt.queue == nullptr && queueIt.it == WifiMacQueue::EMPTY) + { + // check if there is a packet in the BlockAckManager retransmit queue + queueIt.queue = PeekPointer (m_baManager->GetRetransmitQueue ()); + } + + if (queueIt.queue == PeekPointer (m_baManager->GetRetransmitQueue ())) + { + queueIt.it = peek (); + // remove old packets + while (queueIt.it != m_baManager->GetRetransmitQueue ()->end () && IsQosOldPacket (*queueIt.it)) + { + NS_LOG_DEBUG ("Removing an old packet from BlockAckManager retransmit queue: " << **queueIt.it); + queueIt.it = m_baManager->GetRetransmitQueue ()->Remove (queueIt.it); + queueIt.it = peek (); + } + if (queueIt.it != m_baManager->GetRetransmitQueue ()->end ()) + { + NS_LOG_DEBUG ("Packet peeked from BlockAckManager retransmit queue: " << **queueIt.it); + return *queueIt.it; + } + // otherwise, check if there is a packet in the EDCA queue + queueIt = {PeekPointer (m_queue), WifiMacQueue::EMPTY}; + } + + queueIt.it = peek (); + if (queueIt.it != m_queue->end ()) + { + // 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 (&(*queueIt.it)->GetHeader ()); + if ((*queueIt.it)->GetHeader ().IsQosData ()) + { + Mac48Address recipient = (*queueIt.it)->GetHeader ().GetAddr1 (); + uint8_t tid = (*queueIt.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 = (*queueIt.it)->GetHeader (); + // Assign a sequence number if this is not a fragment nor a retransmission + if (!(*queueIt.it)->IsFragment () && !hdr.IsRetry ()) + { + hdr.SetSequenceNumber (sequence); + } + NS_LOG_DEBUG ("Packet peeked from EDCA queue: " << **queueIt.it); + return *queueIt.it; + } + + return 0; +} + MacLowTransmissionParameters QosTxop::GetTransmissionParameters (Ptr frame) const { @@ -1156,6 +1239,52 @@ QosTxop::TerminateTxop (void) RestartAccessIfNeeded (); } +void +QosTxop::NotifyChannelAccessed (Time txopDuration) +{ + NS_LOG_FUNCTION (this << txopDuration); + + NS_ASSERT (txopDuration != Time::Min ()); + m_startTxop = Simulator::Now (); + m_txopDuration = txopDuration; + Txop::NotifyChannelAccessed (); +} + +bool +QosTxop::IsTxopStarted (void) const +{ + NS_LOG_FUNCTION (this << !m_startTxop.IsZero ()); + return (!m_startTxop.IsZero ()); +} + +void +QosTxop::NotifyChannelReleased (void) +{ + NS_LOG_FUNCTION (this); + + if (m_startTxop.IsStrictlyPositive ()) + { + NS_LOG_DEBUG ("Terminating TXOP. Duration = " << Simulator::Now () - m_startTxop); + m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop); + } + m_startTxop = Seconds (0); + Txop::NotifyChannelReleased (); +} + +Time +QosTxop::GetRemainingTxop (void) const +{ + NS_ASSERT (m_startTxop.IsStrictlyPositive ()); + Time remainingTxop = m_txopDuration; + remainingTxop -= (Simulator::Now () - m_startTxop); + if (remainingTxop.IsStrictlyNegative ()) + { + remainingTxop = Seconds (0); + } + NS_LOG_FUNCTION (this << remainingTxop); + return remainingTxop; +} + Time QosTxop::GetTxopRemaining (void) const { diff --git a/src/wifi/model/qos-txop.h b/src/wifi/model/qos-txop.h index 6e9efe671..24022e04b 100644 --- a/src/wifi/model/qos-txop.h +++ b/src/wifi/model/qos-txop.h @@ -125,6 +125,8 @@ public: void EndTxNoAck (void); void RestartAccessIfNeeded (void); void StartAccessIfNeeded (void); + virtual void NotifyChannelAccessed (Time txopDuration); + void NotifyChannelReleased (void); Time GetTxopRemaining (void) const; bool NeedFragmentation (void) const; Ptr GetFragmentPacket (WifiMacHeader *hdr); @@ -383,6 +385,39 @@ public: Ptr DequeuePeekedFrame (Ptr peekedItem, WifiTxVector txVector, bool aggregate = true, uint32_t ampduSize = 0, Time ppduDurationLimit = Time::Min ()); + /** + * Peek the next frame to transmit to the given receiver and of the given + * TID from the block ack manager retransmit queue first and, if not found, from + * the EDCA queue. If tid is equal to 8 (invalid value) and recipient + * is the broadcast address, the first available frame is returned. + * Note that A-MSDU aggregation is never attempted (this is relevant if the + * frame is peeked from the EDCA queue). If the frame is peeked from the EDCA + * queue, it is assigned a sequence number peeked from MacTxMiddle. + * + * \param tid traffic ID. + * \param recipient the receiver station address. + * \returns the peeked frame. + */ + Ptr PeekNextMpdu (uint8_t tid = 8, + Mac48Address recipient = Mac48Address::GetBroadcast ()); + /** + * Peek the next frame to transmit to the given receiver and of the given + * TID from the block ack manager retransmit queue first and, if not found, from + * the EDCA queue. If tid is equal to 8 (invalid value) and recipient + * is the broadcast address, the first available frame is returned. + * Note that A-MSDU aggregation is never attempted (this is relevant if the + * frame is peeked from the EDCA queue). If the frame is peeked from the EDCA + * queue, it is assigned a sequence number peeked from MacTxMiddle. + * + * \param queueIt the QueueIteratorPair pointing to the queue item from which the + * search for an MPDU starts, if the QueueIteratorPair is valid + * \param tid traffic ID. + * \param recipient the receiver station address. + * \returns the peeked frame. + */ + Ptr PeekNextMpdu (WifiMacQueueItem::QueueIteratorPair queueIt, + uint8_t tid = 8, + Mac48Address recipient = Mac48Address::GetBroadcast ()); /** * Compute the MacLow transmission parameters for the given frame. Allowed frames * are those handled by a QosTxop (QoS data frames, BlockAckReq frames, ADDBA @@ -437,6 +472,19 @@ public: */ Mac48Address MapDestAddressForAggregation (const WifiMacHeader &hdr); + /** + * Return true if a TXOP has started. + * + * \return true if a TXOP has started, false otherwise. + */ + virtual bool IsTxopStarted (void) const; + /** + * Return the remaining duration in the current TXOP. + * + * \return the remaining duration in the current TXOP. + */ + virtual Time GetRemainingTxop (void) const; + protected: // Overridden from Txop void DoDispose (void); @@ -542,6 +590,7 @@ private: Time m_currentPacketTimestamp; //!< the current packet timestamp uint16_t m_blockAckInactivityTimeout; //!< the BlockAck inactivity timeout value (in TUs, i.e. blocks of 1024 microseconds) Time m_startTxop; //!< the start TXOP time + Time m_txopDuration; //!< the duration of a TXOP bool m_isAccessRequestedForRts; //!< flag whether access is requested to transmit a RTS frame bool m_currentIsFragmented; //!< flag whether current packet is fragmented Time m_addBaResponseTimeout; //!< timeout for ADDBA response diff --git a/src/wifi/model/txop.cc b/src/wifi/model/txop.cc index dc9b16a47..c7ab9d9f8 100644 --- a/src/wifi/model/txop.cc +++ b/src/wifi/model/txop.cc @@ -471,9 +471,9 @@ Txop::NotifyAccessRequested (void) } void -Txop::NotifyChannelAccessed (void) +Txop::NotifyChannelAccessed (Time txopDuration) { - NS_LOG_FUNCTION (this); + NS_LOG_FUNCTION (this << txopDuration); m_access = GRANTED; } diff --git a/src/wifi/model/txop.h b/src/wifi/model/txop.h index 14595f3fc..fb80c6bee 100644 --- a/src/wifi/model/txop.h +++ b/src/wifi/model/txop.h @@ -341,9 +341,11 @@ public: /** * Called by the FrameExchangeManager to notify that channel access has - * been granted. + * been granted for the given amount of time. + * + * \param txopDuration the duration of the TXOP gained (zero for DCF) */ - virtual void NotifyChannelAccessed (void); + virtual void NotifyChannelAccessed (Time txopDuration = Seconds (0)); /** * Called by the FrameExchangeManager to notify the completion of the transmissions. * This method generates a new backoff and restarts access if needed. diff --git a/src/wifi/test/channel-access-manager-test.cc b/src/wifi/test/channel-access-manager-test.cc index 40309bdd1..f702ae111 100644 --- a/src/wifi/test/channel-access-manager-test.cc +++ b/src/wifi/test/channel-access-manager-test.cc @@ -61,7 +61,7 @@ private: /// Inherited void DoDispose (void); - void NotifyChannelAccessed (void); + void NotifyChannelAccessed (Time txopDuration = Seconds (0)); typedef std::pair ExpectedGrant; //!< the expected grant typedef typedef std::list ExpectedGrants; //!< the collection of expected grants typedef @@ -431,7 +431,7 @@ TxopTest::DoDispose (void) template void -TxopTest::NotifyChannelAccessed (void) +TxopTest::NotifyChannelAccessed (Time txopDuration) { Txop::m_access = Txop::NOT_REQUESTED; m_test->NotifyAccessGranted (m_i);