diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 30db63bee..2c7a60626 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -36,6 +36,7 @@ Bugs fixed - Bug 2636 - Add to doxygen a list of all registered TypeIds - Bug 2928 - BlockAckManager::NeedBarRetransmission returns "true" infinitely - Bug 2985 - PhyTxEnd tracecallback not implemented +- Bug 1909, Issue #41 - wifi: Implementation of ACK timeout - Issue #22 - wifi: Station long retry counter is incremented twice if BlockAck was not received - Issue #40 - IdealWifiManager not working if stations are moving - Issue #84 - Wi-Fi removing wrong header due to copy-paste error diff --git a/examples/wireless/examples-to-run.py b/examples/wireless/examples-to-run.py index 9cea91d45..1ff15394c 100755 --- a/examples/wireless/examples-to-run.py +++ b/examples/wireless/examples-to-run.py @@ -48,8 +48,8 @@ cpp_examples = [ ("wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=745", "True", "True"), ("wifi-he-network --simulationTime=0.25 --frequency=2.4 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=238", "True", "True"), ("wifi-he-network --simulationTime=0.3 --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=223", "True", "True"), - ("wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=0 --nMpdus=32 --minExpectedThroughput=50 --maxExpectedThroughput=51", "True", "True"), - ("wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=1 --nMpdus=32 --minExpectedThroughput=57 --maxExpectedThroughput=58", "True", "True"), + ("wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=0 --nMpdus=32 --minExpectedThroughput=59 --maxExpectedThroughput=60", "True", "True"), + ("wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=1 --nMpdus=32 --minExpectedThroughput=55 --maxExpectedThroughput=56", "True", "True"), ("wifi-mixed-network --simulationTime=1", "True", "True"), ("wifi-aggregation --simulationTime=1 --verifyResults=1", "True", "True"), ("wifi-txop-aggregation --simulationTime=1 --verifyResults=1", "True", "True"), diff --git a/src/mesh/test/dot11s/hwmp-simplest-regression-test-0-1.pcap b/src/mesh/test/dot11s/hwmp-simplest-regression-test-0-1.pcap index 16e37045d..d0db66434 100644 Binary files a/src/mesh/test/dot11s/hwmp-simplest-regression-test-0-1.pcap and b/src/mesh/test/dot11s/hwmp-simplest-regression-test-0-1.pcap differ diff --git a/src/mesh/test/dot11s/hwmp-simplest-regression-test-1-1.pcap b/src/mesh/test/dot11s/hwmp-simplest-regression-test-1-1.pcap index 3bb49f0d7..1293f85dd 100644 Binary files a/src/mesh/test/dot11s/hwmp-simplest-regression-test-1-1.pcap and b/src/mesh/test/dot11s/hwmp-simplest-regression-test-1-1.pcap differ diff --git a/src/wifi/model/mac-low.cc b/src/wifi/model/mac-low.cc index 4ae455b63..e2c32df8e 100644 --- a/src/wifi/model/mac-low.cc +++ b/src/wifi/model/mac-low.cc @@ -47,6 +47,11 @@ #undef NS_LOG_APPEND_CONTEXT #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] " +// Time (in nanoseconds) to be added to the PSDU duration to yield the duration +// of the timer that is started when the PHY indicates the start of the reception +// of a frame and we are waiting for a response. +#define PSDU_DURATION_SAFEGUARD 400 + namespace ns3 { NS_LOG_COMPONENT_DEFINE ("MacLow"); @@ -248,6 +253,7 @@ void MacLow::SetPhy (const Ptr phy) { m_phy = phy; + m_phy->TraceConnectWithoutContext ("PhyRxPayloadBegin", MakeCallback (&MacLow::RxStartIndication, this)); m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::DeaggregateAmpduAndReceive, this)); m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this)); SetupPhyMacLowListener (phy); @@ -262,6 +268,7 @@ MacLow::GetPhy (void) const void MacLow::ResetPhy (void) { + m_phy->TraceDisconnectWithoutContext ("PhyRxPayloadBegin", MakeCallback (&MacLow::RxStartIndication, this)); m_phy->SetReceiveOkCallback (MakeNullCallback, double, WifiTxVector, std::vector> ()); m_phy->SetReceiveErrorCallback (MakeNullCallback> ()); RemovePhyMacLowListener (m_phy); @@ -715,6 +722,48 @@ MacLow::IsWithinSizeAndTimeLimits (uint32_t mpduSize, Mac48Address receiver, uin return true; } +void +MacLow::RxStartIndication (WifiTxVector txVector, Time psduDuration) +{ + NS_LOG_FUNCTION (this); + NS_LOG_DEBUG ("PSDU reception started for " << psduDuration.ToDouble (Time::US) + << " us (txVector: " << txVector << ")"); + NS_ASSERT (psduDuration.IsStrictlyPositive ()); + + if (m_normalAckTimeoutEvent.IsRunning ()) + { + // we are waiting for a Normal Ack and something arrived + NS_LOG_DEBUG ("Rescheduling Normal Ack timeout"); + m_normalAckTimeoutEvent.Cancel (); + NotifyAckTimeoutResetNow (); + m_normalAckTimeoutEvent = Simulator::Schedule (psduDuration + NanoSeconds (PSDU_DURATION_SAFEGUARD), + &MacLow::NormalAckTimeout, this); + } + else if (m_blockAckTimeoutEvent.IsRunning ()) + { + // we are waiting for a BlockAck and something arrived + NS_LOG_DEBUG ("Rescheduling Block Ack timeout"); + m_blockAckTimeoutEvent.Cancel (); + NotifyAckTimeoutResetNow (); + m_blockAckTimeoutEvent = Simulator::Schedule (psduDuration + NanoSeconds (PSDU_DURATION_SAFEGUARD), + &MacLow::BlockAckTimeout, this); + } + else if (m_ctsTimeoutEvent.IsRunning ()) + { + // we are waiting for a CTS and something arrived + NS_LOG_DEBUG ("Rescheduling CTS timeout"); + m_ctsTimeoutEvent.Cancel (); + NotifyCtsTimeoutResetNow (); + m_ctsTimeoutEvent = Simulator::Schedule (psduDuration + NanoSeconds (PSDU_DURATION_SAFEGUARD), + &MacLow::CtsTimeout, this); + } + else if (m_navCounterResetCtsMissed.IsRunning ()) + { + NS_LOG_DEBUG ("Cannot reset NAV"); + m_navCounterResetCtsMissed.Cancel (); + } +} + void MacLow::ReceiveError (Ptr psdu) { @@ -874,18 +923,11 @@ MacLow::ReceiveOk (Ptr mpdu, double rxSnr, WifiTxVector txVect rxSnr, txVector.GetMode (), tag.Get (), m_currentPacket->GetSize ()); } - bool gotAck = false; - if (m_txParams.MustWaitNormalAck () - && m_normalAckTimeoutEvent.IsRunning ()) - { - m_normalAckTimeoutEvent.Cancel (); - NotifyAckTimeoutResetNow (); - gotAck = true; - } - if (gotAck) - { - m_currentTxop->GotAck (); - } + // cancel the Normal Ack timer + m_normalAckTimeoutEvent.Cancel (); + NotifyAckTimeoutResetNow (); + m_currentTxop->GotAck (); + if (m_txParams.HasNextPacket ()) { if (m_stationManager->GetRifsPermitted ()) @@ -1565,20 +1607,21 @@ MacLow::NotifyNav (Ptr packet, const WifiMacHeader &hdr) /** * A STA that used information from an RTS frame as the most recent basis to update its NAV setting * is permitted to reset its NAV if no PHY-RXSTART.indication is detected from the PHY during a - * period with a duration of (2 * aSIFSTime) + (CTS_Time) + (2 * aSlotTime) starting at the - * PHY-RXEND.indication corresponding to the detection of the RTS frame. The “CTS_Time” shall - * be calculated using the length of the CTS frame and the data rate at which the RTS frame - * used for the most recent NAV update was received. + * period with a duration of (2 * aSIFSTime) + (CTS_Time) + aRxPHYStartDelay + (2 * aSlotTime) + * starting at the PHY-RXEND.indication corresponding to the detection of the RTS frame. The + * “CTS_Time” shall be calculated using the length of the CTS frame and the data rate at which + * the RTS frame used for the most recent NAV update was received. */ WifiMacHeader cts; cts.SetType (WIFI_MAC_CTL_CTS); WifiTxVector txVector = GetRtsTxVector (Create (packet, hdr)); Time navCounterResetCtsMissedDelay = m_phy->CalculateTxDuration (cts.GetSerializedSize (), txVector, m_phy->GetFrequency ()) + - Time (2 * GetSifs ()) + Time (2 * GetSlotTime ()); + Time (2 * GetSifs ()) + Time (2 * GetSlotTime ()) + + m_phy->CalculatePhyPreambleAndHeaderDuration (txVector); m_navCounterResetCtsMissed = Simulator::Schedule (navCounterResetCtsMissedDelay, - &MacLow::NavCounterResetCtsMissed, this, - Simulator::Now ()); + &MacLow::DoNavResetNow, this, + Seconds (0)); } } } @@ -1818,8 +1861,11 @@ MacLow::SendRtsForPacket (void) rts.SetDuration (duration); Time txDuration = m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, m_phy->GetFrequency ()); - Time timerDelay = txDuration + GetCtsTimeout (); - + // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with + // a value of aSIFSTime + aSlotTime + aRxPHYStartDelay (IEEE 802.11-2016 sec. 10.3.2.7). + // aRxPHYStartDelay equals the time to transmit the PHY header. + Time timerDelay = txDuration + GetSifs () + GetSlotTime () + + m_phy->CalculatePhyPreambleAndHeaderDuration (rtsTxVector); NS_ASSERT (m_ctsTimeoutEvent.IsExpired ()); NotifyCtsTimeoutStartNow (timerDelay); m_ctsTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::CtsTimeout, this); @@ -1833,23 +1879,26 @@ MacLow::StartDataTxTimers (WifiTxVector dataTxVector) Time txDuration = m_phy->CalculateTxDuration (m_currentPacket->GetSize (), dataTxVector, m_phy->GetFrequency ()); if (m_txParams.MustWaitNormalAck () && !IsCfPeriod ()) { - Time timerDelay = txDuration + GetAckTimeout (); + // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting + // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016). + // aRxPHYStartDelay equals the time to transmit the PHY header. + WifiTxVector ackTxVector = GetAckTxVector (m_currentPacket->GetAddr1 (), + dataTxVector.GetMode ()); + Time timerDelay = txDuration + GetSifs () + GetSlotTime () + + m_phy->CalculatePhyPreambleAndHeaderDuration (ackTxVector); NS_ASSERT (m_normalAckTimeoutEvent.IsExpired ()); NotifyAckTimeoutStartNow (timerDelay); m_normalAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::NormalAckTimeout, this); } - else if (m_txParams.MustWaitBlockAck () && m_txParams.GetBlockAckType () == BlockAckType::BASIC_BLOCK_ACK) + else if (m_txParams.MustWaitBlockAck ()) { - Time timerDelay = txDuration + GetBasicBlockAckTimeout (); - NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ()); - NotifyAckTimeoutStartNow (timerDelay); - m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this); - } - else if (m_txParams.MustWaitBlockAck () && - (m_txParams.GetBlockAckType () == BlockAckType::COMPRESSED_BLOCK_ACK - || m_txParams.GetBlockAckType () == BlockAckType::EXTENDED_COMPRESSED_BLOCK_ACK)) - { - Time timerDelay = txDuration + GetCompressedBlockAckTimeout (); + // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting + // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016). + // aRxPHYStartDelay equals the time to transmit the PHY header. + WifiTxVector blockAckTxVector = GetBlockAckTxVector (m_currentPacket->GetAddr1 (), + dataTxVector.GetMode ()); + Time timerDelay = txDuration + GetSifs () + GetSlotTime () + + m_phy->CalculatePhyPreambleAndHeaderDuration (blockAckTxVector); NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ()); NotifyAckTimeoutStartNow (timerDelay); m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this); diff --git a/src/wifi/model/mac-low.h b/src/wifi/model/mac-low.h index 93a9c8c6b..6c37b1195 100644 --- a/src/wifi/model/mac-low.h +++ b/src/wifi/model/mac-low.h @@ -367,6 +367,19 @@ public: MacLowTransmissionParameters parameters, Ptr txop); + /** + * \param txVector the TXVECTOR decoded from PHY header. + * \param psduDuration the duration of the PSDU that is about to be received. + * + * This method is typically invoked by the lower PHY layer to notify + * the MAC layer that the reception of a PSDU is starting. + * This is equivalent to the PHY-RXSTART primitive. + * If the reception is correct for at least one MPDU of the PSDU + * the DeaggregateAmpduAndReceive will be called after \p psduDuration. + * Otherwise, ReceiveError will be called after the same duration. + */ + void RxStartIndication (WifiTxVector txVector, Time psduDuration); + /** * \param mpdu MPDU received * \param rxSnr snr of MPDU received in linear scale diff --git a/src/wifi/test/wifi-test.cc b/src/wifi/test/wifi-test.cc index 841ed3ea5..9af138d89 100644 --- a/src/wifi/test/wifi-test.cc +++ b/src/wifi/test/wifi-test.cc @@ -2143,7 +2143,7 @@ Bug2470TestCase::DoRun (void) // Block ADDBA request 3 times (== maximum number of MAC frame transmissions in the ADDBA response timeout interval) blackList.push_back (4); blackList.push_back (5); - blackList.push_back (8); + blackList.push_back (6); apPem->SetList (blackList); {