diff --git a/include/openthread/link.h b/include/openthread/link.h index ef099a278..4d311b756 100644 --- a/include/openthread/link.h +++ b/include/openthread/link.h @@ -429,6 +429,9 @@ OTAPI uint32_t OTCALL otLinkGetPollPeriod(otInstance *aInstance); * @note Minimal non-zero value should be `OPENTHREAD_CONFIG_MINIMUM_POLL_PERIOD` (10ms). * Or zero to clear user-specified poll period. * + * @note User-specified value should be no more than the maximal value 0x3FFFFFF ((1 << 26) - 1) allowed, + * otherwise it would be cilpped by the maximal value. + * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aPollPeriod data poll period in milliseconds. * diff --git a/src/core/thread/data_poll_manager.cpp b/src/core/thread/data_poll_manager.cpp index 2b42f38e5..a07ad122e 100644 --- a/src/core/thread/data_poll_manager.cpp +++ b/src/core/thread/data_poll_manager.cpp @@ -53,8 +53,9 @@ namespace ot { DataPollManager::DataPollManager(Instance &aInstance) : InstanceLocator(aInstance) , mTimerStartTime(0) - , mExternalPollPeriod(0) , mPollPeriod(0) + , mExternalPollPeriod(0) + , mFastPollsUsers(0) , mTimer(aInstance, &DataPollManager::HandlePollTimer, this) , mEnabled(false) , mAttachMode(false) @@ -89,6 +90,7 @@ void DataPollManager::StopPolling(void) mPollTimeoutCounter = 0; mPollTxFailureCounter = 0; mRemainingFastPolls = 0; + mFastPollsUsers = 0; mEnabled = false; } @@ -164,9 +166,15 @@ otError DataPollManager::SetExternalPollPeriod(uint32_t aPeriod) { otError error = OT_ERROR_NONE; - if (aPeriod != 0 && aPeriod < OPENTHREAD_CONFIG_MINIMUM_POLL_PERIOD) + if (aPeriod != 0) { - ExitNow(error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(aPeriod >= OPENTHREAD_CONFIG_MINIMUM_POLL_PERIOD, error = OT_ERROR_INVALID_ARGS); + + // Clipped by the maximal value. + if (aPeriod > kMaxExternalPeriod) + { + aPeriod = kMaxExternalPeriod; + } } if (mExternalPollPeriod != aPeriod) @@ -212,7 +220,12 @@ void DataPollManager::HandlePollSent(otError aError) if (mRemainingFastPolls != 0) { mRemainingFastPolls--; - shouldRecalculatePollPeriod = (mRemainingFastPolls == 0); + + if (mRemainingFastPolls == 0) + { + shouldRecalculatePollPeriod = true; + mFastPollsUsers = 0; + } } if (mRetxMode == true) @@ -330,6 +343,11 @@ void DataPollManager::SendFastPolls(uint8_t aNumFastPolls) { bool shouldRecalculatePollPeriod = (mRemainingFastPolls == 0); + if (mFastPollsUsers < kMaxFastPollsUsers) + { + mFastPollsUsers++; + } + if (aNumFastPolls == 0) { aNumFastPolls = kDefaultFastPolls; @@ -351,6 +369,27 @@ void DataPollManager::SendFastPolls(uint8_t aNumFastPolls) } } +otError DataPollManager::StopFastPolls(void) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mFastPollsUsers != 0); + + // If `mFastPollsUsers` hits the max, let it be cleared + // from `HandlePollSent()` (after all fast polls are sent). + VerifyOrExit(mFastPollsUsers < kMaxFastPollsUsers); + + mFastPollsUsers--; + + VerifyOrExit(mFastPollsUsers == 0, error = OT_ERROR_BUSY); + + mRemainingFastPolls = 0; + ScheduleNextPoll(kRecalculatePollPeriod); + +exit: + return error; +} + void DataPollManager::ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector) { if (aPollPeriodSelector == kRecalculatePollPeriod) diff --git a/src/core/thread/data_poll_manager.hpp b/src/core/thread/data_poll_manager.hpp index b1857bc21..e9ee82f5f 100644 --- a/src/core/thread/data_poll_manager.hpp +++ b/src/core/thread/data_poll_manager.hpp @@ -62,8 +62,9 @@ class DataPollManager : public InstanceLocator public: enum { - kDefaultFastPolls = 8, ///< Default number of fast poll transmissions (@sa StartFastPolls). - kMaxFastPolls = 15, ///< Maximum number of fast poll transmissions allowed. + kDefaultFastPolls = 8, ///< Default number of fast poll transmissions (@sa StartFastPolls). + kMaxFastPolls = 15, ///< Maximum number of fast poll transmissions allowed. + kMaxFastPollsUsers = 63, ///< Maximum number of the users of fast poll transmissions allowed. }; /** @@ -111,6 +112,9 @@ public: * Minimal non-zero value should be `OPENTHREAD_CONFIG_MINIMUM_POLL_PERIOD` (10ms). Or zero to clear user-specified * poll period. * + * User-specified value should be no more than the maximal value 0x3FFFFFF ((1 << 26) - 1) allowed, otherwise it + * would be cilpped by the maximal value. + * * @param[in] aPeriod The data poll period in milliseconds. * * @retval OT_ERROR_NONE Successfully set/cleared user-specified poll period. @@ -183,11 +187,26 @@ public: * If @p aNumFastPolls is zero the default value specified by `kDefaultFastPolls` is used instead. The number of * fast polls is clipped by maximum value specified by `kMaxFastPolls`. * + * Note that per `SendFastPolls()` would increase the internal reference count until up to the allowed maximum + * value. If there are retransmission mechanism in the caller component, it should be responsible to call + * `StopFastPolls()` the same times as `SendFastPolls()` it triggered to decrease the reference count properly, + * guaranteeing to exit fast poll mode gracefully. Otherwise, fast poll would continue until all data polls are sent + * out. + * * @param[in] aNumFastPolls If non-zero, number of fast polls to send, if zero, default value is used instead. * */ void SendFastPolls(uint8_t aNumFastPolls); + /** + * This method asks data poll manager to stop fast polls when the expecting response is received. + * + * @retval OT_ERROR_NONE Successfully stopped fast polls when no other responses are expected. + * @retval OT_ERROR_BUSY There are other callers who are waiting for responses. + * + */ + otError StopFastPolls(void); + /** * This method gets the maximum data polling period in use. * @@ -204,6 +223,8 @@ private: kNoBufferRetxPollPeriod = 200, ///< Poll retx due to no buffer space. kFastPollPeriod = 188, ///< Period used for fast polls. kMinPollPeriod = OPENTHREAD_CONFIG_MINIMUM_POLL_PERIOD, ///< Minimum allowed poll period. + kMaxExternalPeriod = ((1 << 26) - 1), ///< Maximum allowed user-specified period. + ///< i.e. (0x3FFFFF)ms, about 18.64 hours. }; enum @@ -225,8 +246,9 @@ private: uint32_t GetDefaultPollPeriod(void) const; uint32_t mTimerStartTime; - uint32_t mExternalPollPeriod; uint32_t mPollPeriod; + uint32_t mExternalPollPeriod : 26; //< In milliseconds. + uint8_t mFastPollsUsers : 6; //< Number of callers which request fast polls. TimerMilli mTimer; diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index f59920e38..6ea4517f5 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2845,6 +2845,16 @@ otError Mle::HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo otLogWarnMleErr(error, "Failed to process Data Response"); } + if (mDataRequestState == kDataRequestNone && !IsRxOnWhenIdle()) + { + // Here simply stops fast data poll request by Mle Data Request. + // Note that in some cases fast data poll may continue after below stop operation until + // running out the specified number. E.g. other component also trigger fast poll, and + // is waiting for response; or the corner case where multiple Mle Data Request attempts + // happened due to the retransmission mechanism. + IgnoreReturnValue(Get().StopFastPolls()); + } + return error; }