From 38f206c6708d8fc7eae21db6ff3e3a50a2053b58 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 23 May 2018 01:19:49 -0700 Subject: [PATCH] [mle] update processing of received MLE Announce messages (#2707) This commit changes how the received MLE Announce messages are processed. The new implementation adds a delay before taking action when it receives an MLE Announce message that has a more recent Active timestamp (compared to device's current Active Dataset timestamp). A timeout interval of `kAnnounceProcessTimeout` (250ms) is used before the device switches to the new channel or pan-id from the received MLE Announce message. During the timeout interval, device can receive and parse other MLE Announce messages and it will ignore any with the same timestamp. --- src/core/thread/mle.cpp | 77 +++++++++++++++++++++++-------- src/core/thread/mle.hpp | 7 ++- src/core/thread/mle_constants.hpp | 1 + 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 684cdbaad..6d5a729f7 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -101,8 +101,9 @@ Mle::Mle(Instance &aInstance) , mParentSearchTimer(aInstance, &Mle::HandleParentSearchTimer, this) #endif , mAnnounceChannel(OT_RADIO_CHANNEL_MIN) - , mPreviousChannel(0) - , mPreviousPanId(Mac::kPanIdBroadcast) + , mAlternateChannel(0) + , mAlternatePanId(Mac::kPanIdBroadcast) + , mAlternateTimestamp(0) , mNotifierCallback(&Mle::HandleStateChanged, this) { uint8_t meshLocalPrefix[8]; @@ -658,14 +659,14 @@ otError Mle::SetStateChild(uint16_t aRloc16) void Mle::InformPreviousChannel(void) { - VerifyOrExit(mPreviousPanId != Mac::kPanIdBroadcast); + VerifyOrExit(mAlternatePanId != Mac::kPanIdBroadcast); VerifyOrExit(mRole == OT_DEVICE_ROLE_CHILD || mRole == OT_DEVICE_ROLE_ROUTER); if (!IsFullThreadDevice() || mRole == OT_DEVICE_ROLE_ROUTER || GetNetif().GetMle().GetRouterSelectionJitterTimeout() == 0) { - mPreviousPanId = Mac::kPanIdBroadcast; - GetNetif().GetAnnounceBeginServer().SendAnnounce(1 << mPreviousChannel); + mAlternatePanId = Mac::kPanIdBroadcast; + GetNetif().GetAnnounceBeginServer().SendAnnounce(1 << mAlternateChannel); } exit: @@ -1478,6 +1479,10 @@ void Mle::HandleAttachTimer(void) SendChildUpdateRequest(); break; + case kAttachStateProcessAnnounce: + ProcessAnnounce(); + break; + case kAttachStateStart: SetAttachState(kAttachStateParentRequestRouter); mParentCandidate.SetState(Neighbor::kStateInvalid); @@ -1615,11 +1620,11 @@ uint32_t Mle::Reattach(void) case kAttachAny: if (mRole != OT_DEVICE_ROLE_CHILD) { - if (mPreviousPanId != Mac::kPanIdBroadcast) + if (mAlternatePanId != Mac::kPanIdBroadcast) { - netif.GetMac().SetPanChannel(mPreviousChannel); - netif.GetMac().SetPanId(mPreviousPanId); - mPreviousPanId = Mac::kPanIdBroadcast; + netif.GetMac().SetPanChannel(mAlternateChannel); + netif.GetMac().SetPanId(mAlternatePanId); + mAlternatePanId = Mac::kPanIdBroadcast; BecomeDetached(); } else if (!IsFullThreadDevice()) @@ -3268,7 +3273,6 @@ exit: otError Mle::HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - ThreadNetif & netif = GetNetif(); otError error = OT_ERROR_NONE; ChannelTlv channelTlv; ActiveTimestampTlv timestamp; @@ -3290,25 +3294,31 @@ otError Mle::HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMe VerifyOrExit(panIdTlv.IsValid(), error = OT_ERROR_PARSE); panId = panIdTlv.GetPanId(); - localTimestamp = netif.GetActiveDataset().GetTimestamp(); + localTimestamp = GetNetif().GetActiveDataset().GetTimestamp(); if (localTimestamp == NULL || localTimestamp->Compare(timestamp) > 0) { - uint8_t curChannel = netif.GetMac().GetPanChannel(); - uint16_t curPanId = netif.GetMac().GetPanId(); + Mac::Mac &mac = GetNetif().GetMac(); // No action is required if device is detached, and current // channel and pan-id match the values from the received MLE // Announce message. - VerifyOrExit((mRole != OT_DEVICE_ROLE_DETACHED) || (curChannel != channel) || (curPanId != panId)); + VerifyOrExit((mRole != OT_DEVICE_ROLE_DETACHED) || (mac.GetPanChannel() != channel) || + (mac.GetPanId() != panId)); - Stop(false); - mPreviousChannel = curChannel; - mPreviousPanId = curPanId; - netif.GetMac().SetPanChannel(channel); - netif.GetMac().SetPanId(panId); - Start(false, true); + if (mAttachState == kAttachStateProcessAnnounce) + { + VerifyOrExit(mAlternateTimestamp < timestamp.GetSeconds()); + } + + mAlternateTimestamp = timestamp.GetSeconds(); + mAlternateChannel = channel; + mAlternatePanId = panId; + SetAttachState(kAttachStateProcessAnnounce); + mAttachTimer.Start(kAnnounceProcessTimeout); + + otLogInfoMle(GetInstance(), "Delay processing Announce - channel %d, panid 0x%02x", channel, panId); } else if (localTimestamp->Compare(timestamp) < 0) { @@ -3331,6 +3341,29 @@ exit: return error; } +void Mle::ProcessAnnounce(void) +{ + Mac::Mac &mac = GetNetif().GetMac(); + uint8_t newChannel = mAlternateChannel; + uint16_t newPanId = mAlternatePanId; + + assert(mAttachState == kAttachStateProcessAnnounce); + + otLogInfoMle(GetInstance(), "Processing Announce - channel %d, panid 0x%02x", newChannel, newPanId); + + Stop(/* aClearNetworkDatasets */ false); + + // Save the current/previous channel and pan-id + mAlternateChannel = mac.GetPanChannel(); + mAlternatePanId = mac.GetPanId(); + mAlternateTimestamp = 0; + + mac.SetPanChannel(newChannel); + mac.SetPanId(newPanId); + + Start(/* aEnableReattach */ false, /* aAnnounceAttach */ true); +} + otError Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { otError error = OT_ERROR_NONE; @@ -3820,6 +3853,10 @@ const char *Mle::AttachStateToString(AttachState aState) str = "Sync"; break; + case kAttachStateProcessAnnounce: + str = "ProcessAnnounce"; + break; + case kAttachStateStart: str = "Start"; break; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index b7e855773..49b6aacf8 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -998,6 +998,7 @@ protected: { kAttachStateIdle, ///< Not currently searching for a parent. kAttachStateSynchronize, ///< Looking to synchronize with a parent (after reset). + kAttachStateProcessAnnounce, ///< Waiting to process a received Announce (to switch channel/pan-id). kAttachStateStart, ///< Starting to look for a parent. kAttachStateParentRequestRouter, ///< Searching for a Router to attach to. kAttachStateParentRequestReed, ///< Searching for Routers or REEDs to attach to. @@ -1565,6 +1566,7 @@ private: otError HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); otError HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); otError HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void ProcessAnnounce(void); otError SendParentRequest(ParentRequestType aType); otError SendChildIdRequest(void); @@ -1644,8 +1646,9 @@ private: #endif uint8_t mAnnounceChannel; - uint8_t mPreviousChannel; - uint16_t mPreviousPanId; + uint8_t mAlternateChannel; + uint16_t mAlternatePanId; + uint64_t mAlternateTimestamp; Ip6::NetifUnicastAddress mLeaderAloc; diff --git a/src/core/thread/mle_constants.hpp b/src/core/thread/mle_constants.hpp index 05b06e801..9bcd5bcfb 100644 --- a/src/core/thread/mle_constants.hpp +++ b/src/core/thread/mle_constants.hpp @@ -62,6 +62,7 @@ enum kParentRequestRouterTimeout = 750, ///< Router Parent Request timeout kParentRequestReedTimeout = 1250, ///< Router and REEDs Parent Request timeout kParentRequestJitter = 50, ///< Maximum jitter time added to Parent Request timeout + kAnnounceProcessTimeout = 250, ///< Timeout after receiving Announcement before channel/pan-id change kAnnounceTimeout = 1400, ///< Total timeout used for sending Announcement messages kMinAnnounceDelay = 80, ///< Minimum delay between Announcement messages kParentResponseMaxDelayRouters = 500, ///< Maximum delay for response for Parent Request sent to routers only