diff --git a/src/wifi/model/mac-low.cc b/src/wifi/model/mac-low.cc index a419d2974..f5a411ac1 100644 --- a/src/wifi/model/mac-low.cc +++ b/src/wifi/model/mac-low.cc @@ -131,10 +131,7 @@ MacLow::MacLow () m_cfAckInfo () { NS_LOG_FUNCTION (this); - for (uint8_t i = 0; i < 8; i++) - { - m_aggregateQueue[i] = CreateObject (); - } + m_aggregateQueue = CreateObject (); } MacLow::~MacLow () @@ -193,10 +190,7 @@ MacLow::DoDispose (void) delete m_phyMacLowListener; m_phyMacLowListener = 0; } - for (uint8_t i = 0; i < 8; i++) - { - m_aggregateQueue[i] = 0; - } + m_aggregateQueue = 0; m_ampdu = false; } @@ -543,90 +537,40 @@ MacLow::StartTransmission (Ptr packet, m_txParams.DisableRts (); } + /* The packet received by this function can be any of the following: + * (a) a management frame dequeued from the Txop + * (b) a non-QoS data frame dequeued from the Txop + * (c) a QoS data or DELBA Request frame dequeued from a QosTxop + * (d) a BlockAckReq or ADDBA Request frame + */ if (!hdr->IsQosData () || hdr->GetAddr1 ().IsBroadcast ()) { - //This is mainly encountered when a higher priority control or management frame is - //sent between A-MPDU transmissions. It avoids to unexpectedly flush the aggregate - //queue when previous RTS request has failed. + // We don't try to aggregate management frames or non-QoS data frames m_ampdu = false; } - else if (hdr->IsQosData () && !m_aggregateQueue[GetTid (packet, *hdr)]->IsEmpty ()) - { - //m_aggregateQueue > 0 occurs when a RTS/CTS exchange failed before an A-MPDU transmission. - //In that case, we transmit the same A-MPDU as previously. - uint32_t sentMpdus = m_aggregateQueue[GetTid (packet, *hdr)]->GetNPackets (); - m_ampdu = true; - if (sentMpdus > 1) - { - AcIndex ac = QosUtilsMapTidToAc (GetTid (packet, *hdr)); - std::map >::const_iterator edcaIt = m_edca.find (ac); - if (edcaIt->second->GetBaBufferSize (hdr->GetAddr1 (), hdr->GetQosTid ()) > 64) - { - m_txParams.EnableExtendedCompressedBlockAck (); - } - else - { - m_txParams.EnableCompressedBlockAck (); - } - } - else if (hdr->IsQosData ()) - { - //VHT/HE single MPDUs are followed by normal ACKs - m_txParams.EnableAck (); - } - std::vector> mpduList; - for (uint32_t i = 0; i < sentMpdus; i++) - { - Ptr newPacket; - newPacket = Create (m_txPackets[GetTid (packet, *hdr)].at (i)->GetPacket (), - m_txPackets[GetTid (packet, *hdr)].at (i)->GetHeader ()); - mpduList.push_back (newPacket); - } - m_currentPacket = Create (mpduList); - m_currentTxVector = GetDataTxVector (*m_currentPacket->begin ()); - } else if (m_mpduAggregator != 0) { - //Perform MPDU aggregation if possible + /* We get here if the received packet is any of the following: + * (a) a QoS data frame + * (b) a BlockAckRequest + */ uint8_t tid = GetTid (packet, *hdr); Ptr qosTxop = m_edca.find (QosUtilsMapTidToAc (tid))->second; std::vector> mpduList; - mpduList = m_mpduAggregator->GetNextAmpdu (Create (packet, *hdr), - m_currentTxVector); + //Perform MPDU aggregation if possible + mpduList = m_mpduAggregator->GetNextAmpdu (*m_currentPacket->begin (), m_currentTxVector); if (mpduList.size () > 1) { m_ampdu = true; - for (auto& mpdu : mpduList) - { - // Store the MPDU in the aggregate queue - NS_LOG_DEBUG ("Adding packet with sequence number " << mpdu->GetHeader ().GetSequenceNumber () - << " to A-MPDU, packet size = " << mpdu->GetSize () - << ", A-MPDU size = " << m_currentPacket->GetSize ()); - m_aggregateQueue[tid]->Enqueue (mpdu); - - // Complete the processing of the MPDU - if (mpdu->GetHeader ().IsQosData ()) - { - if (!m_txParams.MustSendRts ()) - { - qosTxop->CompleteMpduTx (mpdu); - } - else - { - InsertInTxQueue (mpdu, tid); - } - } - } - m_currentPacket = Create (mpduList); // assume implicit block ack for now qosTxop->CompleteAmpduTransfer (hdr->GetAddr1 (), tid); - if (qosTxop->GetBaBufferSize (hdr->GetAddr1 (), hdr->GetQosTid ()) > 64) + if (qosTxop->GetBaBufferSize (hdr->GetAddr1 (), tid) > 64) { m_txParams.EnableExtendedCompressedBlockAck (); } @@ -643,22 +587,10 @@ MacLow::StartTransmission (Ptr packet, { // VHT/HE single MPDU m_ampdu = true; - Ptr mpdu = Create (packet, *hdr); + Ptr mpdu = *m_currentPacket->begin (); mpdu->GetHeader ().SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); m_currentPacket = Create (mpdu, true); - // Store the MPDU in the aggregate queue - NS_LOG_DEBUG ("Adding packet with sequence number " << mpdu->GetHeader ().GetSequenceNumber () - << " to S-MPDU, packet size = " << mpdu->GetSize () - << ", S-MPDU size = " << m_currentPacket->GetSize ()); - m_aggregateQueue[tid]->Enqueue (mpdu); - - // Complete the processing of the MPDU - if (m_txParams.MustSendRts ()) - { - InsertInTxQueue (mpdu, tid); - } - if (qosTxop->GetBaAgreementEstablished (hdr->GetAddr1 (), tid)) { qosTxop->CompleteAmpduTransfer (hdr->GetAddr1 (), tid); @@ -908,10 +840,6 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiTxVector txVector, bool } } m_ampdu = false; - if (m_currentPacket->GetHeader (0).IsQosData ()) - { - FlushAggregateQueue (m_currentPacket->GetHeader (0).GetQosTid ()); - } } else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self && (m_txParams.MustWaitBasicBlockAck () || m_txParams.MustWaitCompressedBlockAck () || m_txParams.MustWaitExtendedCompressedBlockAck ()) @@ -920,7 +848,6 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiTxVector txVector, bool NS_LOG_DEBUG ("got block ack from " << hdr.GetAddr2 ()); SnrTag tag; packet->RemovePacketTag (tag); - FlushAggregateQueue (GetTid (packet, hdr)); CtrlBAckResponseHeader blockAck; packet->RemoveHeader (blockAck); m_blockAckTimeoutEvent.Cancel (); @@ -1177,6 +1104,12 @@ rxPacket: return; } +Ptr +MacLow::GetAggregateQueue (void) const +{ + return m_aggregateQueue; +} + uint32_t MacLow::GetCfEndSize (void) const { @@ -1676,6 +1609,18 @@ MacLow::ForwardDown (Ptr psdu, WifiTxVector txVector) { NS_LOG_DEBUG ("Sending A-MPDU"); } + + if (psdu->GetNMpdus () > 1) + { + for (auto& mpdu : *PeekPointer (psdu)) + { + if (mpdu->GetHeader ().IsQosData ()) + { + auto edcaIt = m_edca.find (QosUtilsMapTidToAc (mpdu->GetHeader ().GetQosTid ())); + edcaIt->second->CompleteMpduTx (mpdu); + } + } + } } m_phy->SendPacket (psdu->GetPacket (), txVector); } @@ -1707,6 +1652,20 @@ MacLow::CtsTimeout (void) /// we should restart a new cts timeout now until the expected /// end of rx if there was a rx start before now. m_stationManager->ReportRtsFailed (m_currentPacket->GetAddr1 (), &m_currentPacket->GetHeader (0)); + // if the current packet is being sent under block ack agreement, store the MPDUs + // in the aggregation queue. If not, the retransmission is handled by the QosTxop + if (m_currentPacket->GetNMpdus () > 1 || + (m_currentPacket->GetHeader (0).IsQosData () + && DynamicCast (m_currentTxop)->GetBaAgreementEstablished (m_currentPacket->GetAddr1 (), + m_currentPacket->GetHeader (0).GetQosTid ()))) + { + for (auto& mpdu : *PeekPointer (m_currentPacket)) + { + NS_LOG_DEBUG ("Storing packet with sequence number " << mpdu->GetHeader ().GetSequenceNumber () + << " in the aggregation queue"); + m_aggregateQueue->Enqueue (mpdu); + } + } Ptr txop = m_currentTxop; m_currentTxop = 0; m_ampdu = false; @@ -1724,10 +1683,6 @@ MacLow::NormalAckTimeout (void) Ptr txop = m_currentTxop; m_currentTxop = 0; m_ampdu = false; - if (m_currentPacket->GetHeader (0).IsQosData ()) - { - FlushAggregateQueue (GetTid (m_currentPacket->GetPayload (0), m_currentPacket->GetHeader (0))); - } txop->MissedAck (); } @@ -1739,9 +1694,7 @@ MacLow::BlockAckTimeout (void) Ptr txop = m_currentTxop; m_currentTxop = 0; m_ampdu = false; - uint8_t tid = GetTid (m_currentPacket->GetPayload (0), m_currentPacket->GetHeader (0)); txop->MissedBlockAck (m_currentPacket->GetNMpdus ()); - FlushAggregateQueue (tid); } void @@ -2113,20 +2066,6 @@ MacLow::SendDataAfterCts (Time duration) */ NS_ASSERT (m_currentPacket != 0); - if (m_currentPacket->GetHeader (0).IsQosData ()) - { - uint8_t tid = GetTid (m_currentPacket->GetPayload (0), m_currentPacket->GetHeader (0)); - if (!m_aggregateQueue[tid]->IsEmpty ()) - { - for (std::vector>::size_type i = 0; i != m_txPackets[tid].size (); i++) - { - AcIndex ac = QosUtilsMapTidToAc (tid); - std::map >::const_iterator edcaIt = m_edca.find (ac); - edcaIt->second->CompleteMpduTx (m_txPackets[tid].at (i)); - } - } - } - StartDataTxTimers (m_currentTxVector); Time newDuration = Seconds (0); if (m_txParams.MustWaitBasicBlockAck ()) @@ -2761,25 +2700,6 @@ MacLow::DeaggregateAmpduAndReceive (Ptr aggregatedPacket, double rxSnr, } } -void -MacLow::FlushAggregateQueue (uint8_t tid) -{ - NS_LOG_FUNCTION (this << +tid); - if (!m_aggregateQueue[tid]->IsEmpty ()) - { - NS_LOG_DEBUG ("Flush aggregate queue"); - m_aggregateQueue[tid]->Flush (); - } - m_txPackets[tid].clear (); -} - -void -MacLow::InsertInTxQueue (Ptr mpdu, uint8_t tid) -{ - NS_LOG_FUNCTION (this); - m_txPackets[tid].push_back (mpdu); -} - Time MacLow::GetRemainingCfpDuration (void) const { diff --git a/src/wifi/model/mac-low.h b/src/wifi/model/mac-low.h index 423b28a0c..b4966df42 100644 --- a/src/wifi/model/mac-low.h +++ b/src/wifi/model/mac-low.h @@ -420,13 +420,6 @@ public: */ void DeaggregateAmpduAndReceive (Ptr aggregatedPacket, double rxSnr, WifiTxVector txVector, std::vector statusPerMpdu); - /** - * - * This function is called to flush the aggregate queue, which is used for A-MPDU - * \param tid the Traffic ID - * - */ - void FlushAggregateQueue (uint8_t tid); /** * Return a TXVECTOR for the DATA frame given the destination. @@ -479,6 +472,14 @@ public: */ void SetMpduAggregator (const Ptr aggr); + /** + * Get the aggregate queue, which stores the MPDUs that were part of an A-MPDU + * that could not be transmitted because the RTS/CTS exchange failed + * + * \return the aggregate queue + */ + Ptr GetAggregateQueue (void) const; + private: /** * Cancel all scheduled events. Called before beginning a transmission @@ -854,14 +855,6 @@ private: * \param phy the WifiPhy this MacLow is connected to */ void RemovePhyMacLowListener (Ptr phy); - /** - * Insert in a temporary queue. - * It is only used with a RTS/CTS exchange for an A-MPDU transmission. - * - * \param mpdu MPDU to be inserted in the A-MPDU tx queue - * \param tid the Traffic ID of the MPDU to be inserted in the A-MPDU tx queue - */ - void InsertInTxQueue (Ptr mpdu, uint8_t tid); Ptr m_phy; //!< Pointer to WifiPhy (actually send/receives frames) Ptr m_mac; //!< Pointer to WifiMac (to fetch configuration) @@ -952,8 +945,7 @@ private: QueueEdcas m_edca; //!< EDCA queues bool m_ctsToSelfSupported; //!< Flag whether CTS-to-self is supported - Ptr m_aggregateQueue[8]; //!< Queues per TID used for MPDU aggregation - std::vector> m_txPackets[8]; //!< Contain temporary items to be sent with the next A-MPDU transmission for a given TID, once RTS/CTS exchange has succeeded. + Ptr m_aggregateQueue; //!< Queue storing MPDUs after RTS/CTS exchange failure WifiTxVector m_currentTxVector; //!< TXVECTOR used for the current packet transmission CfAckInfo m_cfAckInfo; //!< Info about piggyback ACKs used in PCF diff --git a/src/wifi/model/mpdu-aggregator.cc b/src/wifi/model/mpdu-aggregator.cc index 621709681..0901bb316 100644 --- a/src/wifi/model/mpdu-aggregator.cc +++ b/src/wifi/model/mpdu-aggregator.cc @@ -317,6 +317,7 @@ std::vector> MpduAggregator::GetNextAmpdu (Ptr mpdu, WifiTxVector txVector, Time ppduDurationLimit) const { + NS_LOG_FUNCTION (this << *mpdu << ppduDurationLimit); std::vector> mpduList; Mac48Address recipient = mpdu->GetHeader ().GetAddr1 (); @@ -339,167 +340,58 @@ MpduAggregator::GetNextAmpdu (Ptr mpdu, WifiTxVector txV if (edcaIt->second->GetBaAgreementEstablished (recipient, tid)) { /* here is performed mpdu aggregation */ - uint16_t startingSequenceNumber = 0; - uint16_t currentSequenceNumber = 0; - uint8_t qosPolicy = 0; - bool retry = false; - Ptr nextMpdu = mpdu; - uint16_t nMpdus = 0; // number of aggregated MPDUs + uint16_t startingSequenceNumber = mpdu->GetHeader ().GetSequenceNumber (); + Ptr nextMpdu; uint16_t maxMpdus = edcaIt->second->GetBaBufferSize (recipient, tid); uint32_t currentAmpduSize = 0; - Ptr queue = edcaIt->second->GetWifiMacQueue (); - Ptr phy = edcaIt->second->GetLow ()->GetPhy (); - // Get the maximum PPDU Duration based on the preamble type. It must be a - // non null value because aggregation is available for HT, VHT and HE, which - // also provide a limit on the maximum PPDU duration - Time maxPpduDuration = GetPpduMaxTime (txVector.GetPreambleType ()); - NS_ASSERT (maxPpduDuration.IsStrictlyPositive ()); - - // the limit on the PPDU duration is the minimum between the maximum PPDU - // duration (depending on the PPDU format) and the additional limit provided - // by the caller (if non-zero) - if (ppduDurationLimit.IsStrictlyPositive ()) + // check if the received MPDU meets the size and duration constraints + if (edcaIt->second->IsWithinSizeAndTimeLimits (mpdu, txVector, 0, ppduDurationLimit)) { - maxPpduDuration = std::min (maxPpduDuration, ppduDurationLimit); + // mpdu can be aggregated + nextMpdu = Copy (mpdu); } while (nextMpdu != 0) { - /* nextMpdu may be any of the following: - * (a) an A-MSDU (with all the constituent MSDUs dequeued from - * the EDCA queue) - * (b) an MSDU dequeued (1st iteration) or peeked (other iterations) - * from the EDCA queue - * (c) a retransmitted MSDU or A-MSDU dequeued (1st iteration) or - * peeked (other iterations) from the BA Manager queue - * (d) a control or management frame (only 1st iteration, for now) - */ + /* if we are here, nextMpdu can be aggregated to the A-MPDU. + * nextMpdu may be any of the following: + * (a) an A-MSDU (with all the constituent MSDUs dequeued from + * the EDCA queue) + * (b) an MSDU dequeued from the EDCA queue + * (c) a retransmitted MSDU or A-MSDU dequeued from the BA Manager queue + * (d) an MPDU that was aggregated in an A-MPDU which was not + * transmitted (e.g., because the RTS/CTS exchange failed) + */ - // Check if aggregating nextMpdu violates the constraints on the - // maximum A-MPDU size or on the maximum PPDU duration. This is - // guaranteed by MsduAggregator::Aggregate in the case of (a) + currentAmpduSize = GetSizeIfAggregated (nextMpdu->GetSize (), currentAmpduSize); - uint32_t ampduSize = GetSizeIfAggregated (nextMpdu->GetSize (), currentAmpduSize); + NS_LOG_DEBUG ("Adding packet with sequence number " << nextMpdu->GetHeader ().GetSequenceNumber () + << " to A-MPDU, packet size = " << nextMpdu->GetSize () + << ", A-MPDU size = " << currentAmpduSize); - if (ampduSize > maxAmpduSize || - phy->CalculateTxDuration (ampduSize, txVector, phy->GetFrequency ()) > maxPpduDuration) - { - NS_LOG_DEBUG ("No other MPDU can be aggregated: " << (ampduSize == 0 ? "size" : "time") - << " limit exceeded"); - break; - } + // Always use the Normal Ack policy (Implicit Block Ack), for now + nextMpdu->GetHeader ().SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); - // nextMpdu can be aggregated - nMpdus++; - currentAmpduSize = ampduSize; - - // Update the header of nextMpdu in case it is not a retransmitted packet - WifiMacHeader nextHeader = nextMpdu->GetHeader (); - - if (nMpdus == 1) // first MPDU - { - if (!mpdu->GetHeader ().IsBlockAckReq ()) - { - if (!mpdu->GetHeader ().IsBlockAck ()) - { - startingSequenceNumber = mpdu->GetHeader ().GetSequenceNumber (); - nextHeader.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); - } - else - { - NS_FATAL_ERROR ("BlockAck is not handled"); - } - - currentSequenceNumber = mpdu->GetHeader ().GetSequenceNumber (); - } - else - { - qosPolicy = 3; //if the last subframe is block ack req then set ack policy of all frames to blockack - CtrlBAckRequestHeader blockAckReq; - mpdu->GetPacket ()->PeekHeader (blockAckReq); - startingSequenceNumber = blockAckReq.GetStartingSequence (); - } - /// \todo We should also handle Ack and BlockAck - } - else if (retry == false) - { - currentSequenceNumber = edcaIt->second->GetNextSequenceNumberFor (&nextHeader); - nextHeader.SetSequenceNumber (currentSequenceNumber); - nextHeader.SetFragmentNumber (0); - nextHeader.SetNoMoreFragments (); - nextHeader.SetNoRetry (); - } - - if (qosPolicy == 0) - { - nextHeader.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); - } - else - { - nextHeader.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); - } - - mpduList.push_back (Create (nextMpdu->GetPacket (), nextHeader, - nextMpdu->GetTimeStamp ())); - - // Except for the first iteration, complete the processing of the - // current MPDU, which includes removal from the respective queue - // (needed for cases (b) and (c) because the packet was just peeked) - if (nMpdus >= 2 && nextHeader.IsQosData ()) - { - if (retry) - { - edcaIt->second->RemoveRetransmitPacket (tid, recipient, - nextHeader.GetSequenceNumber ()); - } - else if (nextHeader.IsQosData () && !nextHeader.IsQosAmsdu ()) - { - queue->Remove (nextMpdu->GetPacket ()); - } - } + mpduList.push_back (nextMpdu); // If allowed by the BA agreement, get the next MPDU nextMpdu = 0; - if ((nMpdus == 1 || retry) // check retransmit in the 1st iteration or if retry is true - && (nextMpdu = edcaIt->second->PeekNextRetransmitPacket (tid, recipient)) != 0) + Ptr peekedMpdu; + peekedMpdu = edcaIt->second->PeekNextFrameByTidAndAddress (tid, recipient); + if (peekedMpdu != 0) { - retry = true; - currentSequenceNumber = nextMpdu->GetHeader ().GetSequenceNumber (); + uint16_t currentSequenceNumber = peekedMpdu->GetHeader ().GetSequenceNumber (); - if (!IsInWindow (currentSequenceNumber, startingSequenceNumber, maxMpdus)) + if (IsInWindow (currentSequenceNumber, startingSequenceNumber, maxMpdus)) { - break; - } - } - else - { - retry = false; - nextMpdu = queue->PeekByTidAndAddress (tid, recipient); - - if (nextMpdu) - { - currentSequenceNumber = edcaIt->second->PeekNextSequenceNumberFor (&nextMpdu->GetHeader ()); - - if (!IsInWindow (currentSequenceNumber, startingSequenceNumber, maxMpdus)) - { - break; - } - - // Attempt A-MSDU aggregation - Ptr amsdu; - if (edcaIt->second->GetLow ()->GetMsduAggregator () != 0) - { - amsdu = edcaIt->second->GetLow ()->GetMsduAggregator ()->GetNextAmsdu (recipient, tid, - txVector, - currentAmpduSize, - maxPpduDuration); - if (amsdu) - { - nextMpdu = amsdu; - } - } + // dequeue the frame if constraints on size and duration limit are met. + // Note that the dequeued MPDU differs from the peeked MPDU if A-MSDU + // aggregation is performed during the dequeue + NS_LOG_DEBUG ("Trying to aggregate another MPDU"); + nextMpdu = edcaIt->second->DequeuePeekedFrame (peekedMpdu, txVector, true, + currentAmpduSize, ppduDurationLimit); } } } @@ -509,7 +401,6 @@ MpduAggregator::GetNextAmpdu (Ptr mpdu, WifiTxVector txV mpduList.clear (); } } - return mpduList; } diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index cc9dac615..a82fa081e 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -190,7 +190,26 @@ QosTxop::PeekNextFrame (void) NS_LOG_FUNCTION (this); Ptr item; - // check if there is a packet in the BlockAckManager retransmit queue + // 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) + { + break; + } + } + } + + 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) @@ -224,7 +243,16 @@ QosTxop::PeekNextFrameByTidAndAddress (uint8_t tid, Mac48Address recipient) NS_LOG_FUNCTION (this << +tid << recipient); Ptr item; - // check if there is a packet in the BlockAckManager retransmit queue + // check if there is a packet in the MacLow aggregation queue + item = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); + + 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->PeekNextPacketByTidAndAddress (tid, recipient); if (item != 0) @@ -330,7 +358,7 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto Ptr testItem; // the packet can only have been peeked from the Block Ack manager retransmit - // queue if: + // queue or the MacLow aggregation queue if: // - the peeked packet is a QoS Data frame AND // - the peeked packet is not a broadcast frame AND // - an agreement has been established @@ -338,6 +366,17 @@ QosTxop::DequeuePeekedFrame (Ptr peekedItem, WifiTxVecto && GetBaAgreementEstablished (recipient, peekedItem->GetHeader ().GetQosTid ())) { uint8_t tid = peekedItem->GetHeader ().GetQosTid (); + testItem = m_low->GetAggregateQueue ()->PeekByTidAndAddress (tid, recipient); + + if (testItem) + { + // if not null, the test packet must equal the peeked packet + NS_ASSERT (testItem->GetPacket () == peekedItem->GetPacket ()); + item = m_low->GetAggregateQueue ()->DequeueByTidAndAddress (tid, recipient); + NS_LOG_DEBUG ("dequeued from aggregation queue: " << *item); + return item; + } + testItem = m_baManager->PeekNextPacketByTidAndAddress (tid, recipient); if (testItem) @@ -351,6 +390,9 @@ 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 if (peekedItem->GetHeader ().IsQosData ()) @@ -403,6 +445,13 @@ QosTxop::NotifyAccessGranted (void) m_accessRequested = false; m_isAccessRequestedForRts = false; m_startTxop = Simulator::Now (); + // discard the current packet if it is a QoS Data frame with expired lifetime + if (m_currentPacket != 0 && m_currentHdr.IsQosData () + && (m_currentPacketTimestamp + m_queue->GetMaxDelay () < Simulator::Now ())) + { + NS_LOG_DEBUG ("the lifetime of current packet expired"); + m_currentPacket = 0; + } if (m_currentPacket == 0) { if (m_baManager->HasBar (m_currentBar)) @@ -613,7 +662,6 @@ QosTxop::MissedCts (void) if (GetAmpduExist (m_currentHdr.GetAddr1 ()) || m_currentHdr.IsQosData ()) { uint8_t tid = GetTid (m_currentPacket, m_currentHdr); - m_low->FlushAggregateQueue (tid); if (GetBaAgreementEstablished (m_currentHdr.GetAddr1 (), tid)) { @@ -653,6 +701,13 @@ QosTxop::MissedCts (void) { UpdateFailedCw (); m_cwTrace = GetCw (); + // if a BA agreement is established, packets have been stored in MacLow + // aggregation queue for retransmission + if (m_currentHdr.IsQosData () && GetBaAgreementEstablished (m_currentHdr.GetAddr1 (), + m_currentHdr.GetQosTid ())) + { + m_currentPacket = 0; + } } m_backoff = m_rng->GetInteger (0, GetCw ()); m_backoffTrace (m_backoff); diff --git a/src/wifi/test/wifi-aggregation-test.cc b/src/wifi/test/wifi-aggregation-test.cc index 97b4ef9b0..83935b1ff 100644 --- a/src/wifi/test/wifi-aggregation-test.cc +++ b/src/wifi/test/wifi-aggregation-test.cc @@ -147,9 +147,9 @@ AmpduAggregationTest::DoRun (void) (*m_mac->GetBEQueue ()->GetLow ()->m_currentPacket->begin ()); auto mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu - (Create (pkt, hdr), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); + (Create (pkt, hdr), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); NS_TEST_EXPECT_MSG_EQ (mpduList.empty (), true, "a single packet should not result in an A-MPDU"); - NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->GetNPackets (), 0, "aggregation queue is not flushed"); + NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->GetNPackets (), 0, "aggregation queue is not flushed"); //----------------------------------------------------------------------------------------------------- @@ -173,15 +173,15 @@ AmpduAggregationTest::DoRun (void) m_mac->GetBEQueue ()->GetWifiMacQueue ()->Enqueue (Create (pkt1, hdr1)); m_mac->GetBEQueue ()->GetWifiMacQueue ()->Enqueue (Create (pkt2, hdr2)); - mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu (Create (pkt, hdr), + mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu (Create (pkt, hdr), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); m_mac->GetBEQueue ()->GetLow ()->m_currentPacket = Create (mpduList); for (auto& mpdu : mpduList) { - m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->Enqueue (Create (*mpdu)); + m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->Enqueue (Create (*mpdu)); } - uint32_t aggregationQueueSize = m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->GetNPackets (); + uint32_t aggregationQueueSize = m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->GetNPackets (); NS_TEST_EXPECT_MSG_EQ (mpduList.empty (), false, "MPDU aggregation failed"); NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_currentPacket->GetSize (), 4606, "A-MPDU size is not correct"); NS_TEST_EXPECT_MSG_EQ (aggregationQueueSize, 3, "aggregation queue should not be empty"); @@ -192,7 +192,7 @@ AmpduAggregationTest::DoRun (void) uint32_t i = 0; for (; aggregationQueueSize > 0; aggregationQueueSize--, i++) { - dequeuedItem = m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->Dequeue (); + dequeuedItem = m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->Dequeue (); dequeuedHdr = dequeuedItem->GetHeader (); NS_TEST_EXPECT_MSG_EQ (dequeuedHdr.GetSequenceNumber (), i, "wrong sequence number"); } @@ -227,17 +227,17 @@ AmpduAggregationTest::DoRun (void) m_mac->GetBEQueue ()->GetWifiMacQueue ()->Enqueue (Create (pkt3, hdr3)); - mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu (Create (pkt1, hdr1), + mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu (Create (pkt1, hdr1), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); NS_TEST_EXPECT_MSG_EQ (mpduList.empty (), true, "a single packet for this destination should not result in an A-MPDU"); - NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->GetNPackets (), 0, "aggregation queue is not flushed"); + NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->GetNPackets (), 0, "aggregation queue is not flushed"); m_mac->GetBEQueue ()->m_currentHdr = hdr2; m_mac->GetBEQueue ()->m_currentPacket = pkt2->Copy (); mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu - (Create (pkt2, hdr2), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); + (Create (pkt2, hdr2), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); NS_TEST_EXPECT_MSG_EQ (mpduList.empty (), true, "no MPDU aggregation should be performed if there is no agreement"); - NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->GetNPackets (), 0, "aggregation queue is not flushed"); + NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->GetNPackets (), 0, "aggregation queue is not flushed"); m_manager->SetMaxSsrc (0); //set to 0 in order to fake that the maximum number of retries has been reached m_mac->GetBEQueue ()->MissedAck (); @@ -541,15 +541,15 @@ HeAggregationTest::DoRunSubTest (uint16_t bufferSize) m_mac->GetBEQueue ()->GetWifiMacQueue ()->Enqueue (Create (pkt, hdr)); } - auto mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu (Create (pkt, hdr), + auto mpduList = m_mac->GetBEQueue ()->GetLow ()->GetMpduAggregator ()-> GetNextAmpdu (Create (pkt, hdr), m_mac->GetBEQueue ()->GetLow ()->m_currentTxVector); for (auto& mpdu : mpduList) { - m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->Enqueue (Create (*mpdu)); + m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->Enqueue (Create (*mpdu)); } NS_TEST_EXPECT_MSG_EQ (mpduList.empty (), false, "MPDU aggregation failed"); - uint32_t aggregationQueueSize = m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue[0]->GetNPackets (); + uint32_t aggregationQueueSize = m_mac->GetBEQueue ()->GetLow ()->m_aggregateQueue->GetNPackets (); NS_TEST_EXPECT_MSG_EQ (aggregationQueueSize, bufferSize, "aggregation queue should countain " << bufferSize << " MPDUs"); uint16_t expectedRemainingPacketsInQueue = 300 - bufferSize + 1; NS_TEST_EXPECT_MSG_EQ (m_mac->GetBEQueue ()->GetWifiMacQueue ()->GetNPackets (), expectedRemainingPacketsInQueue, "queue should contain 300 - "<< bufferSize - 1 << " = "<< expectedRemainingPacketsInQueue << " packets");