[timer] fix elapsed overflow (#3789)

This commit fixes a bug in the commissioner when a joiner's expiration
time has alerady elapsed.

This commit also introduces convenience methods for computing time
elapsed and diffs.
This commit is contained in:
Yakun Xu
2019-05-02 08:44:37 -07:00
committed by Jonathan Hui
parent 267a3b3e29
commit ae4ef9eb3e
19 changed files with 126 additions and 64 deletions
+1 -1
View File
@@ -2011,7 +2011,7 @@ void Interpreter::HandleIcmpReceive(Message & aMessage,
if (aMessage.Read(aMessage.GetOffset(), sizeof(uint32_t), &timestamp) >= static_cast<int>(sizeof(uint32_t)))
{
mServer->OutputFormat(" time=%dms", TimerMilli::GetNow() - HostSwap32(timestamp));
mServer->OutputFormat(" time=%dms", TimerMilli::Elapsed(HostSwap32(timestamp)));
}
mServer->OutputFormat("\r\n");
+2 -2
View File
@@ -360,8 +360,8 @@ otError otThreadGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo)
aParentInfo->mPathCost = parent->GetCost();
aParentInfo->mLinkQualityIn = parent->GetLinkInfo().GetLinkQuality();
aParentInfo->mLinkQualityOut = parent->GetLinkQualityOut();
aParentInfo->mAge = static_cast<uint8_t>(TimerMilli::MsecToSec(TimerMilli::GetNow() - parent->GetLastHeard()));
aParentInfo->mAllocated = true;
aParentInfo->mAge = static_cast<uint8_t>(TimerMilli::MsecToSec(TimerMilli::Elapsed(parent->GetLastHeard())));
aParentInfo->mAllocated = true;
aParentInfo->mLinkEstablished = parent->GetState() == Neighbor::kStateValid;
exit:
+5 -4
View File
@@ -263,7 +263,7 @@ void CoapBase::HandleRetransmissionTimer(Timer &aTimer)
void CoapBase::HandleRetransmissionTimer(void)
{
uint32_t now = TimerMilli::GetNow();
uint32_t nextDelta = 0xffffffff;
uint32_t nextDelta = TimerMilli::kForeverDt;
CoapMetadata coapMetadata;
Message * message = static_cast<Message *>(mPendingRequests.GetHead());
Message * nextMessage = NULL;
@@ -276,10 +276,11 @@ void CoapBase::HandleRetransmissionTimer(void)
if (coapMetadata.IsLater(now))
{
uint32_t diff = TimerMilli::Elapsed(now, coapMetadata.mNextTimerShot);
// Calculate the next delay and choose the lowest.
if (coapMetadata.mNextTimerShot - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = coapMetadata.mNextTimerShot - now;
nextDelta = diff;
}
}
else if ((coapMetadata.mConfirmable) && (coapMetadata.mRetransmissionCount < kMaxRetransmit))
@@ -316,7 +317,7 @@ void CoapBase::HandleRetransmissionTimer(void)
message = nextMessage;
}
if (nextDelta != 0xffffffff)
if (nextDelta != TimerMilli::kForeverDt)
{
mRetransmissionTimer.Start(nextDelta);
}
+44 -4
View File
@@ -37,6 +37,7 @@
#include "openthread-core-config.h"
#include <stddef.h>
#include "utils/wrap_stdint.h"
#include <openthread/platform/alarm-micro.h>
@@ -69,10 +70,9 @@ class Timer : public InstanceLocator, public OwnerLocator
friend class TimerScheduler;
public:
enum
{
kMaxDt = (1UL << 31) - 1, //< Maximum permitted value for parameter `aDt` in `Start` and `StartAt` method.
};
static const uint32_t kMaxDt =
(1UL << 31) - 1; ///< Maximum permitted value for parameter `aDt` in `Start` and `StartAt` method.
static const uint32_t kForeverDt = 0xffffffff; ///< The special forever `aDt` value.
/**
* This function pointer is called when the timer expires.
@@ -181,6 +181,46 @@ public:
*/
void Stop(void);
/**
* This static method returns the time diff in milliseconds between @p aStart and @p aEnd.
*
* @param[in] aStart The start time.
* @param[in] aEnd The end time.
*
* @returns The time diff in milliseconds.
*
*/
static int32_t Diff(uint32_t aStart, uint32_t aEnd)
{
uint32_t diff = aEnd - aStart;
return reinterpret_cast<int32_t &>(diff);
}
/**
* This static method returns the time elapsed in milliseconds from @p aStart to @p aEnd.
*
* @note This method assumes @p aEnd is after @p aStart.
*
* @param[in] aStart The start time.
* @param[in] aEnd The end time.
*
* @returns The elapsed time in milliseconds.
*
*/
static uint32_t Elapsed(uint32_t aStart, uint32_t aEnd) { return aEnd - aStart; }
/**
* This static method returns the time passed in milliseconds since @p aStart.
*
* @note This method assumes now is after @p aStart.
*
* @param[in] aStart The start time.
*
* @returns The elapsed time in milliseconds.
*
*/
static uint32_t Elapsed(uint32_t aStart) { return Elapsed(aStart, GetNow()); }
/**
* This static method returns the current time in milliseconds.
*
+17 -11
View File
@@ -399,25 +399,31 @@ void Commissioner::HandleJoinerExpirationTimer(void)
void Commissioner::UpdateJoinerExpirationTimer(void)
{
uint32_t now = TimerMilli::GetNow();
uint32_t nextTimeout = 0xffffffff;
uint32_t nextTimeout = TimerMilli::kForeverDt;
// Check if timer should be set for next Joiner.
for (size_t i = 0; i < OT_ARRAY_LENGTH(mJoiners); i++)
{
{
if (!mJoiners[i].mValid)
{
continue;
}
int32_t diff;
if (mJoiners[i].mExpirationTime - now < nextTimeout)
{
nextTimeout = mJoiners[i].mExpirationTime - now;
}
if (!mJoiners[i].mValid)
{
continue;
}
diff = TimerMilli::Diff(now, mJoiners[i].mExpirationTime);
if (diff <= 0)
{
nextTimeout = 0;
break;
}
else if (static_cast<uint32_t>(diff) < nextTimeout)
{
nextTimeout = static_cast<uint32_t>(diff);
}
}
if (nextTimeout != 0xffffffff)
if (nextTimeout != TimerMilli::kForeverDt)
{
// Update the timer to the timeout of the next Joiner.
mJoinerExpirationTimer.Start(nextTimeout);
+1 -1
View File
@@ -479,7 +479,7 @@ otError Dataset::AppendMleDatasetTlv(Message &aMessage) const
}
else if (cur->GetType() == Tlv::kDelayTimer)
{
uint32_t elapsed = TimerMilli::GetNow() - mUpdateTime;
uint32_t elapsed = TimerMilli::Elapsed(mUpdateTime);
DelayTimerTlv delayTimer(static_cast<const DelayTimerTlv &>(*cur));
if (delayTimer.GetDelayTimer() > elapsed)
+1 -1
View File
@@ -109,7 +109,7 @@ otError DatasetLocal::Read(Dataset &aDataset) const
delayTimer = static_cast<DelayTimerTlv *>(aDataset.Get(Tlv::kDelayTimer));
VerifyOrExit(delayTimer);
elapsed = TimerMilli::GetNow() - mUpdateTime;
elapsed = TimerMilli::Elapsed(mUpdateTime);
if (delayTimer->GetDelayTimer() > elapsed)
{
+1 -1
View File
@@ -315,7 +315,7 @@ otError Dhcp6Client::AppendElapsedTime(Message &aMessage)
ElapsedTime option;
option.Init();
option.SetElapsedTime(static_cast<uint16_t>(TimerMilli::MsecToSec(TimerMilli::GetNow() - mStartTime)));
option.SetElapsedTime(static_cast<uint16_t>(TimerMilli::MsecToSec(TimerMilli::Elapsed(mStartTime))));
return aMessage.Append(&option, sizeof(option));
}
+11 -5
View File
@@ -395,7 +395,7 @@ void Client::HandleRetransmissionTimer(Timer &aTimer)
void Client::HandleRetransmissionTimer(void)
{
uint32_t now = TimerMilli::GetNow();
uint32_t nextDelta = 0xffffffff;
uint32_t nextDelta = TimerMilli::kForeverDt;
QueryMetadata queryMetadata;
Message * message = mPendingQueries.GetHead();
Message * nextMessage = NULL;
@@ -408,21 +408,27 @@ void Client::HandleRetransmissionTimer(void)
if (queryMetadata.IsLater(now))
{
uint32_t diff = TimerMilli::Elapsed(now, queryMetadata.mTransmissionTime);
// Calculate the next delay and choose the lowest.
if (queryMetadata.mTransmissionTime - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = queryMetadata.mTransmissionTime - now;
nextDelta = diff;
}
}
else if (queryMetadata.mRetransmissionCount < kMaxRetransmit)
{
uint32_t diff;
// Increment retransmission counter and timer.
queryMetadata.mRetransmissionCount++;
queryMetadata.mTransmissionTime = now + kResponseTimeout;
queryMetadata.UpdateIn(*message);
diff = TimerMilli::Elapsed(now, queryMetadata.mTransmissionTime);
// Check if retransmission time is lower than current lowest.
if (queryMetadata.mTransmissionTime - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = queryMetadata.mTransmissionTime - now;
}
@@ -443,7 +449,7 @@ void Client::HandleRetransmissionTimer(void)
message = nextMessage;
}
if (nextDelta != 0xffffffff)
if (nextDelta != TimerMilli::kForeverDt)
{
mRetransmissionTimer.Start(nextDelta);
}
+12 -6
View File
@@ -334,7 +334,7 @@ void Mpl::HandleRetransmissionTimer(Timer &aTimer)
void Mpl::HandleRetransmissionTimer(void)
{
uint32_t now = TimerMilli::GetNow();
uint32_t nextDelta = 0xffffffff;
uint32_t nextDelta = TimerMilli::kForeverDt;
MplBufferedMessageMetadata messageMetadata;
Message *message = mBufferedMessageSet.GetHead();
@@ -347,10 +347,12 @@ void Mpl::HandleRetransmissionTimer(void)
if (messageMetadata.IsLater(now))
{
uint32_t diff = TimerMilli::Elapsed(now, messageMetadata.GetTransmissionTime());
// Calculate the next retransmission time and choose the lowest.
if (messageMetadata.GetTransmissionTime() - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = messageMetadata.GetTransmissionTime() - now;
nextDelta = diff;
}
}
else
@@ -360,6 +362,8 @@ void Mpl::HandleRetransmissionTimer(void)
if (messageMetadata.GetTransmissionCount() < GetTimerExpirations())
{
uint32_t diff;
Message *messageCopy = message->Clone(message->GetLength() - sizeof(MplBufferedMessageMetadata));
if (messageCopy != NULL)
@@ -375,10 +379,12 @@ void Mpl::HandleRetransmissionTimer(void)
messageMetadata.GenerateNextTransmissionTime(now, kDataMessageInterval);
messageMetadata.UpdateIn(*message);
diff = TimerMilli::Elapsed(now, messageMetadata.GetTransmissionTime());
// Check if retransmission time is lower than the current lowest one.
if (messageMetadata.GetTransmissionTime() - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = messageMetadata.GetTransmissionTime() - now;
nextDelta = diff;
}
}
else
@@ -407,7 +413,7 @@ void Mpl::HandleRetransmissionTimer(void)
message = nextMessage;
}
if (nextDelta != 0xffffffff)
if (nextDelta != TimerMilli::kForeverDt)
{
mRetransmissionTimer.Start(nextDelta);
}
+12 -6
View File
@@ -269,7 +269,7 @@ void Client::HandleRetransmissionTimer(Timer &aTimer)
void Client::HandleRetransmissionTimer(void)
{
uint32_t now = TimerMilli::GetNow();
uint32_t nextDelta = 0xffffffff;
uint32_t nextDelta = TimerMilli::kForeverDt;
QueryMetadata queryMetadata;
Message * message = mPendingQueries.GetHead();
Message * nextMessage = NULL;
@@ -282,23 +282,29 @@ void Client::HandleRetransmissionTimer(void)
if (queryMetadata.IsLater(now))
{
uint32_t diff = TimerMilli::Elapsed(now, queryMetadata.mTransmissionTime);
// Calculate the next delay and choose the lowest.
if (queryMetadata.mTransmissionTime - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = queryMetadata.mTransmissionTime - now;
nextDelta = diff;
}
}
else if (queryMetadata.mRetransmissionCount < kMaxRetransmit)
{
uint32_t diff;
// Increment retransmission counter and timer.
queryMetadata.mRetransmissionCount++;
queryMetadata.mTransmissionTime = now + kResponseTimeout;
queryMetadata.UpdateIn(*message);
diff = TimerMilli::Elapsed(now, queryMetadata.mTransmissionTime);
// Check if retransmission time is lower than current lowest.
if (queryMetadata.mTransmissionTime - now < nextDelta)
if (diff < nextDelta)
{
nextDelta = queryMetadata.mTransmissionTime - now;
nextDelta = diff;
}
// Retransmit
@@ -317,7 +323,7 @@ void Client::HandleRetransmissionTimer(void)
message = nextMessage;
}
if (nextDelta != 0xffffffff)
if (nextDelta != TimerMilli::kForeverDt)
{
mRetransmissionTimer.Start(nextDelta);
}
+1 -1
View File
@@ -622,7 +622,7 @@ void AddressResolver::HandleAddressQuery(Coap::Message &aMessage, const Ip6::Mes
if (child.HasIp6Address(GetInstance(), targetTlv.GetTarget()))
{
mlIidTlv.SetIid(child.GetExtAddress());
lastTransactionTimeTlv.SetTime(TimerMilli::GetNow() - child.GetLastHeard());
lastTransactionTimeTlv.SetTime(TimerMilli::Elapsed(child.GetLastHeard()));
SendAddressQueryResponse(targetTlv, mlIidTlv, &lastTransactionTimeTlv, aMessageInfo.GetPeerAddr());
ExitNow();
}
+3 -3
View File
@@ -1816,7 +1816,7 @@ void Mle::HandleDelayedResponseTimer(void)
{
DelayedResponseHeader delayedResponse;
uint32_t now = TimerMilli::GetNow();
uint32_t nextDelay = 0xffffffff;
uint32_t nextDelay = TimerMilli::kForeverDt;
Message * message = mDelayedResponses.GetHead();
Message * nextMessage = NULL;
@@ -1864,7 +1864,7 @@ void Mle::HandleDelayedResponseTimer(void)
message = nextMessage;
}
if (nextDelay != 0xffffffff)
if (nextDelay != TimerMilli::kForeverDt)
{
mDelayedResponseTimer.Start(nextDelay);
}
@@ -3953,7 +3953,7 @@ void Mle::HandleParentSearchTimer(void)
// from `UpdateParentSearchState()`. We want to limit this to happen
// only once within a backoff interval.
if (TimerMilli::GetNow() - mParentSearchBackoffCancelTime >= kParentSearchBackoffInterval)
if (TimerMilli::Elapsed(mParentSearchBackoffCancelTime) >= kParentSearchBackoffInterval)
{
mParentSearchBackoffWasCanceled = false;
otLogInfoMle("PeriodicParentSearch: Backoff cancellation is allowed on parent switch");
+5 -5
View File
@@ -1649,7 +1649,7 @@ otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::Messa
}
#endif
}
else if ((TimerMilli::GetNow() - child->GetLastHeard()) < kParentRequestRouterTimeout)
else if (TimerMilli::Elapsed(child->GetLastHeard()) < kParentRequestRouterTimeout)
{
ExitNow(error = OT_ERROR_DUPLICATED);
}
@@ -1790,7 +1790,7 @@ void MleRouter::HandleStateUpdateTimer(void)
break;
}
if ((TimerMilli::GetNow() - child.GetLastHeard()) >= timeout)
if (TimerMilli::Elapsed(child.GetLastHeard()) >= timeout)
{
otLogInfoMle("Child timeout expired");
RemoveNeighbor(child);
@@ -1814,7 +1814,7 @@ void MleRouter::HandleStateUpdateTimer(void)
continue;
}
age = TimerMilli::GetNow() - router.GetLastHeard();
age = TimerMilli::Elapsed(router.GetLastHeard());
if (router.GetState() == Neighbor::kStateValid)
{
@@ -3609,7 +3609,7 @@ otError MleRouter::GetChildInfo(Child &aChild, otChildInfo &aChildInfo)
aChildInfo.mRloc16 = aChild.GetRloc16();
aChildInfo.mChildId = GetChildId(aChild.GetRloc16());
aChildInfo.mNetworkDataVersion = aChild.GetNetworkDataVersion();
aChildInfo.mAge = TimerMilli::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
aChildInfo.mAge = TimerMilli::MsecToSec(TimerMilli::Elapsed(aChild.GetLastHeard()));
aChildInfo.mLinkQualityIn = aChild.GetLinkInfo().GetLinkQuality();
aChildInfo.mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
aChildInfo.mLastRssi = aChild.GetLinkInfo().GetLastRss();
@@ -3687,7 +3687,7 @@ exit:
if (neighbor != NULL)
{
aNeighInfo.mExtAddress = neighbor->GetExtAddress();
aNeighInfo.mAge = TimerMilli::MsecToSec(TimerMilli::GetNow() - neighbor->GetLastHeard());
aNeighInfo.mAge = TimerMilli::MsecToSec(TimerMilli::Elapsed(neighbor->GetLastHeard()));
aNeighInfo.mRloc16 = neighbor->GetRloc16();
aNeighInfo.mLinkFrameCounter = neighbor->GetLinkFrameCounter();
aNeighInfo.mMleFrameCounter = neighbor->GetMleFrameCounter();
+1 -2
View File
@@ -1000,8 +1000,7 @@ otError NetworkData::SendServerDataNotification(uint16_t aRloc16)
Coap::Message * message = NULL;
Ip6::MessageInfo messageInfo;
VerifyOrExit(!mLastAttemptWait || static_cast<int32_t>(TimerMilli::GetNow() - mLastAttempt) < kDataResubmitDelay,
error = OT_ERROR_ALREADY);
VerifyOrExit(!mLastAttemptWait || TimerMilli::Elapsed(mLastAttempt) < kDataResubmitDelay, error = OT_ERROR_ALREADY);
VerifyOrExit((message = Get<Coap::Coap>().NewMessage()) != NULL, error = OT_ERROR_NO_BUFS);
+1 -1
View File
@@ -1575,7 +1575,7 @@ void Leader::HandleTimer(void)
continue;
}
if ((TimerMilli::GetNow() - mContextLastUsed[i]) >= TimerMilli::SecToMsec(mContextIdReuseDelay))
if (TimerMilli::Elapsed(mContextLastUsed[i]) >= TimerMilli::SecToMsec(mContextIdReuseDelay))
{
FreeContext(kMinContextId + i);
}
+2 -2
View File
@@ -436,7 +436,7 @@ otError RouterTable::GetRouterInfo(uint16_t aRouterId, otRouterInfo &aRouterInfo
aRouterInfo.mPathCost = router->GetCost();
aRouterInfo.mLinkQualityIn = router->GetLinkInfo().GetLinkQuality();
aRouterInfo.mLinkQualityOut = router->GetLinkQualityOut();
aRouterInfo.mAge = static_cast<uint8_t>(TimerMilli::MsecToSec(TimerMilli::GetNow() - router->GetLastHeard()));
aRouterInfo.mAge = static_cast<uint8_t>(TimerMilli::MsecToSec(TimerMilli::Elapsed(router->GetLastHeard())));
exit:
return error;
@@ -449,7 +449,7 @@ Router *RouterTable::GetLeader(void)
uint32_t RouterTable::GetLeaderAge(void) const
{
return (mActiveRouterCount > 0) ? TimerMilli::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated)
return (mActiveRouterCount > 0) ? TimerMilli::MsecToSec(TimerMilli::Elapsed(mRouterIdSequenceLastUpdated))
: 0xffffffff;
}
+3 -2
View File
@@ -66,6 +66,7 @@ TimeSync::TimeSync(Instance &aInstance)
, mTimer(aInstance, HandleTimeout, this)
, mCurrentStatus(OT_NETWORK_TIME_UNSYNCHRONIZED)
{
mLastTimeSyncReceived = TimerMilli::GetNow();
CheckAndHandleChanges(false);
}
@@ -133,7 +134,7 @@ void TimeSync::NotifyTimeSyncCallback(void)
void TimeSync::ProcessTimeSync(void)
{
if (Get<Mle::MleRouter>().GetRole() == OT_DEVICE_ROLE_LEADER &&
TimerMilli::GetNow() - mLastTimeSyncSent > TimerMilli::SecToMsec(mTimeSyncPeriod))
TimerMilli::Elapsed(mLastTimeSyncSent) > TimerMilli::SecToMsec(mTimeSyncPeriod))
{
IncrementTimeSyncSeq();
mTimeSyncRequired = true;
@@ -180,7 +181,7 @@ void TimeSync::CheckAndHandleChanges(bool aTimeUpdated)
otNetworkTimeStatus networkTimeStatus = OT_NETWORK_TIME_SYNCHRONIZED;
const otDeviceRole role = Get<Mle::MleRouter>().GetRole();
const uint32_t resyncNeededThresholdMs = 2 * TimerMilli::SecToMsec(mTimeSyncPeriod);
const uint32_t timeSyncLastSyncMs = TimerMilli::GetNow() - mLastTimeSyncReceived;
const uint32_t timeSyncLastSyncMs = TimerMilli::Elapsed(mLastTimeSyncReceived);
mTimer.Stop();
+3 -6
View File
@@ -208,7 +208,7 @@ exit:
void JamDetector::UpdateHistory(bool aDidExceedThreshold)
{
uint32_t now = TimerMilli::GetNow();
int32_t diff = TimerMilli::Diff(mCurSecondStartTime, TimerMilli::GetNow());
// If the RSSI is ever below the threshold, update mAlwaysAboveThreshold
// for current second interval.
@@ -218,7 +218,7 @@ void JamDetector::UpdateHistory(bool aDidExceedThreshold)
}
// If we reached end of current one second interval, update the history bitmap
if (now - mCurSecondStartTime >= kOneSecondInterval)
if (diff >= kOneSecondInterval)
{
mHistoryBitmap <<= 1;
@@ -229,10 +229,7 @@ void JamDetector::UpdateHistory(bool aDidExceedThreshold)
mAlwaysAboveThreshold = true;
while (now - mCurSecondStartTime >= kOneSecondInterval)
{
mCurSecondStartTime += kOneSecondInterval;
}
mCurSecondStartTime += (static_cast<uint32_t>(diff) / kOneSecondInterval) * kOneSecondInterval;
UpdateJamState();
}