mirror of
https://github.com/espressif/openthread.git
synced 2026-08-04 01:47:47 +00:00
[dataset] enforce maximum delay timer value and improve handling (#10023)
This commit makes the following improvements to Delay Timer TLV handling in Pending Operational Datasets: - Enforces maximum delay adhering to the Thread spec's maximum Delay Timer value (72 hours), clamping larger values. - Defines min, max, and default delay timer constants in `DelayTimerTlv`. - Adds `CalculateRemainingDelay()` helper method to calculate remaining delay. - Removes code handling delay values exceeding the OpenThread `Timer` limitation (now redundant due to the stricter 72-hour maximum).
This commit is contained in:
@@ -473,19 +473,9 @@ Error Dataset::AppendMleDatasetTlv(Type aType, Message &aMessage) const
|
||||
}
|
||||
else if (cur->GetType() == Tlv::kDelayTimer)
|
||||
{
|
||||
uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
|
||||
uint32_t delayTimer = cur->ReadValueAs<DelayTimerTlv>();
|
||||
uint32_t remainingDelay = DelayTimerTlv::CalculateRemainingDelay(*cur, mUpdateTime);
|
||||
|
||||
if (delayTimer > elapsed)
|
||||
{
|
||||
delayTimer -= elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
delayTimer = 0;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = Tlv::Append<DelayTimerTlv>(aMessage, delayTimer));
|
||||
SuccessOrExit(error = Tlv::Append<DelayTimerTlv>(aMessage, remainingDelay));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -106,25 +106,10 @@ Error DatasetLocal::Read(Dataset &aDataset) const
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t elapsed;
|
||||
uint32_t delayTimer;
|
||||
Tlv *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
|
||||
Tlv *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
|
||||
|
||||
VerifyOrExit(tlv != nullptr);
|
||||
|
||||
elapsed = TimerMilli::GetNow() - mUpdateTime;
|
||||
delayTimer = tlv->ReadValueAs<DelayTimerTlv>();
|
||||
|
||||
if (delayTimer > elapsed)
|
||||
{
|
||||
delayTimer -= elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
delayTimer = 0;
|
||||
}
|
||||
|
||||
tlv->WriteValueAs<DelayTimerTlv>(delayTimer);
|
||||
tlv->WriteValueAs<DelayTimerTlv>(DelayTimerTlv::CalculateRemainingDelay(*tlv, mUpdateTime));
|
||||
}
|
||||
|
||||
aDataset.mUpdateTime = TimerMilli::GetNow();
|
||||
|
||||
@@ -725,10 +725,7 @@ void PendingDatasetManager::StartDelayTimer(void)
|
||||
tlv = dataset.FindTlv(Tlv::kDelayTimer);
|
||||
VerifyOrExit(tlv != nullptr);
|
||||
|
||||
delay = tlv->ReadValueAs<DelayTimerTlv>();
|
||||
|
||||
// the Timer implementation does not support the full 32 bit range
|
||||
delay = Min(delay, Timer::kMaxDelay);
|
||||
delay = Min(tlv->ReadValueAs<DelayTimerTlv>(), DelayTimerTlv::kMaxDelay);
|
||||
|
||||
mDelayTimer.StartAt(dataset.GetUpdateTime(), delay);
|
||||
LogInfo("delay timer started %lu", ToUlong(delay));
|
||||
@@ -739,25 +736,9 @@ exit:
|
||||
|
||||
void PendingDatasetManager::HandleDelayTimer(void)
|
||||
{
|
||||
Tlv *tlv;
|
||||
Dataset dataset;
|
||||
|
||||
IgnoreError(Read(dataset));
|
||||
|
||||
// if the Delay Timer value is larger than what our Timer implementation can handle, we have to compute
|
||||
// the remainder and wait some more.
|
||||
if ((tlv = dataset.FindTlv(Tlv::kDelayTimer)) != nullptr)
|
||||
{
|
||||
uint32_t elapsed = mDelayTimer.GetFireTime() - dataset.GetUpdateTime();
|
||||
uint32_t delay = tlv->ReadValueAs<DelayTimerTlv>();
|
||||
|
||||
if (elapsed < delay)
|
||||
{
|
||||
mDelayTimer.StartAt(mDelayTimer.GetFireTime(), delay - elapsed);
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("pending delay timer expired");
|
||||
|
||||
dataset.ConvertToActive();
|
||||
@@ -765,9 +746,6 @@ void PendingDatasetManager::HandleDelayTimer(void)
|
||||
Get<ActiveDatasetManager>().Save(dataset);
|
||||
|
||||
Clear();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
template <>
|
||||
|
||||
@@ -182,12 +182,6 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Default Delay Timer value for a Pending Operational Dataset (ms)
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kDefaultDelayTimer = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_DEFAULT_DELAY;
|
||||
|
||||
/**
|
||||
* Defines a generic Dataset TLV to read from a message.
|
||||
*
|
||||
|
||||
@@ -202,11 +202,11 @@ Error DatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo
|
||||
|
||||
case Tlv::kDelayTimer:
|
||||
{
|
||||
uint32_t delayTimer = datasetTlv.ReadValueAs<DelayTimerTlv>();
|
||||
uint32_t delayTimer = Min(datasetTlv.ReadValueAs<DelayTimerTlv>(), DelayTimerTlv::kMaxDelay);
|
||||
|
||||
if (doesAffectNetworkKey && delayTimer < kDefaultDelayTimer)
|
||||
if (doesAffectNetworkKey && delayTimer < DelayTimerTlv::kDefaultDelay)
|
||||
{
|
||||
delayTimer = kDefaultDelayTimer;
|
||||
delayTimer = DelayTimerTlv::kDefaultDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ RegisterLogModule("MeshCoPLeader");
|
||||
Leader::Leader(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mTimer(aInstance)
|
||||
, mDelayTimerMinimal(kMinDelayTimer)
|
||||
, mDelayTimerMinimal(DelayTimerTlv::kMinDelay)
|
||||
, mSessionId(Random::NonCrypto::GetUint16())
|
||||
{
|
||||
}
|
||||
@@ -218,7 +218,7 @@ Error Leader::SetDelayTimerMinimal(uint32_t aDelayTimerMinimal)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit((aDelayTimerMinimal != 0 && aDelayTimerMinimal < kMinDelayTimer), error = kErrorInvalidArgs);
|
||||
VerifyOrExit((aDelayTimerMinimal != 0 && aDelayTimerMinimal < DelayTimerTlv::kMinDelay), error = kErrorInvalidArgs);
|
||||
mDelayTimerMinimal = aDelayTimerMinimal;
|
||||
|
||||
exit:
|
||||
|
||||
@@ -104,7 +104,6 @@ public:
|
||||
void SetEmptyCommissionerData(void);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kMinDelayTimer = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_MINIMUM_DELAY; // (msec)
|
||||
static constexpr uint32_t kTimeoutLeaderPetition = 50; // TIMEOUT_LEAD_PET (seconds)
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
|
||||
@@ -158,6 +158,23 @@ const char *StateTlv::StateToString(State aState)
|
||||
return aState == kReject ? kStateStrings[2] : kStateStrings[aState];
|
||||
}
|
||||
|
||||
uint32_t DelayTimerTlv::CalculateRemainingDelay(const Tlv &aDelayTimerTlv, TimeMilli aUpdateTime)
|
||||
{
|
||||
uint32_t delay = Min(aDelayTimerTlv.ReadValueAs<DelayTimerTlv>(), kMaxDelay);
|
||||
uint32_t elapsed = TimerMilli::GetNow() - aUpdateTime;
|
||||
|
||||
if (delay > elapsed)
|
||||
{
|
||||
delay -= elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
bool ChannelMaskTlv::IsValid(void) const
|
||||
{
|
||||
uint32_t channelMask;
|
||||
|
||||
@@ -611,7 +611,48 @@ typedef SimpleTlvInfo<Tlv::kPendingTimestamp, Timestamp> PendingTimestampTlv;
|
||||
* Defines Delay Timer TLV constants and types.
|
||||
*
|
||||
*/
|
||||
typedef UintTlvInfo<Tlv::kDelayTimer, uint32_t> DelayTimerTlv;
|
||||
class DelayTimerTlv : public UintTlvInfo<Tlv::kDelayTimer, uint32_t>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Minimum Delay Timer value (in msec).
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kMinDelay = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_MINIMUM_DELAY;
|
||||
|
||||
/**
|
||||
* Maximum Delay Timer value (in msec).
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kMaxDelay = (72 * Time::kOneHourInMsec);
|
||||
|
||||
/**
|
||||
* Default Delay Timer value (in msec).
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kDefaultDelay = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_DEFAULT_DELAY;
|
||||
|
||||
/**
|
||||
* Calculates the remaining delay in milliseconds, based on the value read from a Delay Timer TLV and the specified
|
||||
* update time.
|
||||
*
|
||||
* Ensures that the calculated delay does not exceed `kMaxDelay`. Also accounts for time already elapsed since
|
||||
* @p aUpdateTime.
|
||||
*
|
||||
* Caller MUST ensure that @p aDelayTimerTlv is a Delay Timer TLV, otherwise behavior is undefined.
|
||||
*
|
||||
* @param[in] aDelayTimerTlv The delay timer TLV to read delay from.
|
||||
* @param[in] aUpdateTimer The update time of the Dataset.
|
||||
*
|
||||
* @return The remaining delay (in msec).
|
||||
*
|
||||
*/
|
||||
static uint32_t CalculateRemainingDelay(const Tlv &aDelayTimerTlv, TimeMilli aUpdateTime);
|
||||
|
||||
static_assert(kMinDelay <= kMaxDelay, "TMF_PENDING_DATASET_MINIMUM_DELAY is larger than max allowed");
|
||||
static_assert(kDefaultDelay <= kMaxDelay, "TMF_PENDING_DATASET_DEFAULT_DELAY is larger than max allowed");
|
||||
static_assert(kDefaultDelay >= kMinDelay, "TMF_PENDING_DATASET_DEFAULT_DELAY is smaller than min allowed");
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements Channel Mask TLV generation and parsing.
|
||||
|
||||
Reference in New Issue
Block a user