diff --git a/src/wifi/model/channel-access-manager.cc b/src/wifi/model/channel-access-manager.cc index 6d94fb403..6886a33de 100644 --- a/src/wifi/model/channel-access-manager.cc +++ b/src/wifi/model/channel-access-manager.cc @@ -333,6 +333,7 @@ ChannelAccessManager::DoGrantDcfAccess (void) { Ptr txop = *i; if (txop->GetAccessStatus () == Txop::REQUESTED + && (!txop->IsQosTxop () || !StaticCast (txop)->EdcaDisabled ()) && GetBackoffEndFor (txop) <= Simulator::Now () ) { /** @@ -541,6 +542,19 @@ ChannelAccessManager::DoRestartAccessTimeoutIfNeeded (void) } } +void +ChannelAccessManager::DisableEdcaFor (Ptr qosTxop, Time duration) +{ + NS_LOG_FUNCTION (this << qosTxop << duration); + NS_ASSERT (qosTxop->IsQosTxop ()); + UpdateBackoff (); + Time resume = Simulator::Now () + duration; + NS_LOG_DEBUG ("Backoff will resume at time " << resume << " with " + << qosTxop->GetBackoffSlots () << " remaining slot(s)"); + qosTxop->UpdateBackoffSlotsNow (0, resume); + DoRestartAccessTimeoutIfNeeded (); +} + void ChannelAccessManager::NotifyRxStartNow (Time duration) { diff --git a/src/wifi/model/channel-access-manager.h b/src/wifi/model/channel-access-manager.h index 68dfa9edb..b52832af1 100644 --- a/src/wifi/model/channel-access-manager.h +++ b/src/wifi/model/channel-access-manager.h @@ -114,6 +114,17 @@ public: */ Time GetAccessGrantStart (bool ignoreNav = false) const; + /** + * \param qosTxop a QosTxop that needs to be disabled + * \param duration the amount of time during which the QosTxop is disabled + * + * Disable the given EDCA for the given amount of time. This EDCA will not be + * granted channel access during this period and the backoff timer will be frozen. + * After this period, the EDCA will start normal operations again by resuming + * the backoff timer. + */ + void DisableEdcaFor (Ptr qosTxop, Time duration); + /** * \param duration expected duration of reception * diff --git a/src/wifi/model/he/he-frame-exchange-manager.cc b/src/wifi/model/he/he-frame-exchange-manager.cc index 18ac6ac27..95aea6dbb 100644 --- a/src/wifi/model/he/he-frame-exchange-manager.cc +++ b/src/wifi/model/he/he-frame-exchange-manager.cc @@ -1506,6 +1506,21 @@ HeFrameExchangeManager::ReceiveMpdu (Ptr mpdu, RxSignalInfo rx ret.second, rxSignalInfo.snr, tag.Get (staId), m_txParams.m_txVector); } + + if (m_psduMap.at (staId)->GetHeader (0).IsQosData () + && (blockAck.GetAckType (index) // Ack or All-ack context + || std::any_of (blockAck.GetBitmap (index).begin (), + blockAck.GetBitmap (index).end (), + [](uint8_t b) { return b != 0; }))) + { + NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).HasData ()); + NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).GetQosTid () == tid); + // the station has received a response from the AP for the HE TB PPDU + // transmitted in response to a Basic Trigger Frame and at least one + // MPDU was acknowledged. Therefore, it needs to update the access + // parameters if it received an MU EDCA Parameter Set element. + m_mac->GetQosTxop (tid)->StartMuEdcaTimerNow (); + } } // cancel the timer diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index e8213ebd3..2868230e7 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -96,7 +96,8 @@ QosTxop::QosTxop () m_muCwMin (0), m_muCwMax (0), m_muAifsn (0), - m_muEdcaTimer (Seconds (0)) + m_muEdcaTimer (Seconds (0)), + m_muEdcaTimerStartTime (Seconds (0)) { NS_LOG_FUNCTION (this); m_qosBlockedDestinations = Create (); @@ -177,6 +178,63 @@ QosTxop::SetMuEdcaTimer (Time timer) m_muEdcaTimer = timer; } +void +QosTxop::StartMuEdcaTimerNow (void) +{ + NS_LOG_FUNCTION (this); + m_muEdcaTimerStartTime = Simulator::Now (); + if (EdcaDisabled ()) + { + NS_LOG_DEBUG ("Disable EDCA for " << m_muEdcaTimer.As (Time::MS)); + m_channelAccessManager->DisableEdcaFor (this, m_muEdcaTimer); + } +} + +bool +QosTxop::MuEdcaTimerRunning (void) const +{ + return (m_muEdcaTimerStartTime.IsStrictlyPositive () && m_muEdcaTimer.IsStrictlyPositive () + && m_muEdcaTimerStartTime + m_muEdcaTimer > Simulator::Now ()); +} + +bool +QosTxop::EdcaDisabled (void) const +{ + return (MuEdcaTimerRunning () && m_muAifsn == 0); +} + +uint32_t +QosTxop::GetMinCw (void) const +{ + if (!MuEdcaTimerRunning ()) + { + return m_cwMin; + } + NS_ASSERT (!EdcaDisabled ()); + return m_muCwMin; +} + +uint32_t +QosTxop::GetMaxCw (void) const +{ + if (!MuEdcaTimerRunning ()) + { + return m_cwMax; + } + NS_ASSERT (!EdcaDisabled ()); + return m_muCwMax; +} + +uint8_t +QosTxop::GetAifsn (void) const +{ + if (!MuEdcaTimerRunning ()) + { + return m_aifsn; + } + return m_muAifsn; +} + Ptr QosTxop::GetBaManager (void) { diff --git a/src/wifi/model/qos-txop.h b/src/wifi/model/qos-txop.h index daaf6a610..bb4e1981a 100644 --- a/src/wifi/model/qos-txop.h +++ b/src/wifi/model/qos-txop.h @@ -416,6 +416,47 @@ public: * \param timer the timer duration. */ void SetMuEdcaTimer (Time timer); + /** + * Start the MU EDCA Timer. + */ + void StartMuEdcaTimerNow (void); + /** + * Return true if the MU EDCA Timer is running, false otherwise. + * + * \return whether the MU EDCA Timer is running + */ + bool MuEdcaTimerRunning (void) const; + /** + * Return true if the EDCA is disabled (the MU EDCA Timer is running and the + * MU AIFSN is zero), false otherwise. + * + * \return whether the EDCA is disabled + */ + bool EdcaDisabled (void) const; + /** + * Return the minimum contention window size from the EDCA Parameter Set + * or the MU EDCA Parameter Set, depending on whether the MU EDCA Timer is + * running or not. + * + * \return the currently used minimum contention window size. + */ + uint32_t GetMinCw (void) const override; + /** + * Return the maximum contention window size from the EDCA Parameter Set + * or the MU EDCA Parameter Set, depending on whether the MU EDCA Timer is + * running or not. + * + * \return the currently used maximum contention window size. + */ + uint32_t GetMaxCw (void) const override; + /** + * Return the number of slots that make up an AIFS according to the + * EDCA Parameter Set or the MU EDCA Parameter Set, depending on whether the + * MU EDCA Timer is running or not. + * + * \return the number of slots that currently make up an AIFS. + */ + uint8_t GetAifsn (void) const override; protected: void DoDispose (void) override; @@ -451,10 +492,11 @@ private: Time m_failedAddBaTimeout; //!< timeout after failed BA agreement bool m_useExplicitBarAfterMissedBlockAck; //!< flag whether explicit BlockAckRequest should be sent upon missed BlockAck Response - uint32_t m_muCwMin; //!< the MU CW minimum - uint32_t m_muCwMax; //!< the MU CW maximum - uint8_t m_muAifsn; //!< the MU AIFSN - Time m_muEdcaTimer; //!< the MU EDCA Timer + uint32_t m_muCwMin; //!< the MU CW minimum + uint32_t m_muCwMax; //!< the MU CW maximum + uint8_t m_muAifsn; //!< the MU AIFSN + Time m_muEdcaTimer; //!< the MU EDCA Timer + Time m_muEdcaTimerStartTime; //!< last start time of the MU EDCA Timer TracedCallback m_txopTrace; //!< TXOP trace callback }; diff --git a/src/wifi/model/txop.cc b/src/wifi/model/txop.cc index 07c155087..4060ca3d1 100644 --- a/src/wifi/model/txop.cc +++ b/src/wifi/model/txop.cc @@ -186,7 +186,7 @@ void Txop::ResetCw (void) { NS_LOG_FUNCTION (this); - m_cw = m_cwMin; + m_cw = GetMinCw (); m_cwTrace = m_cw; } @@ -195,7 +195,9 @@ Txop::UpdateFailedCw (void) { NS_LOG_FUNCTION (this); //see 802.11-2012, section 9.19.2.5 - m_cw = std::min ( 2 * (m_cw + 1) - 1, m_cwMax); + m_cw = std::min ( 2 * (m_cw + 1) - 1, GetMaxCw ()); + // if the MU EDCA timer is running, CW cannot be less than MU CW min + m_cw = std::max (m_cw, GetMinCw ()); m_cwTrace = m_cw; } diff --git a/src/wifi/model/txop.h b/src/wifi/model/txop.h index d523c3140..068b99040 100644 --- a/src/wifi/model/txop.h +++ b/src/wifi/model/txop.h @@ -166,19 +166,19 @@ public: * * \return the minimum contention window size. */ - uint32_t GetMinCw (void) const; + virtual uint32_t GetMinCw (void) const; /** * Return the maximum contention window size. * * \return the maximum contention window size. */ - uint32_t GetMaxCw (void) const; + virtual uint32_t GetMaxCw (void) const; /** * Return the number of slots that make up an AIFS. * * \return the number of slots that make up an AIFS. */ - uint8_t GetAifsn (void) const; + virtual uint8_t GetAifsn (void) const; /** * Return the TXOP limit. *