diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index d07dcb96c..c230cab9c 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -361,6 +361,7 @@ bool Message::IsSubTypeMle(void) const if (mInfo.mSubType == kSubTypeMleAnnounce || mInfo.mSubType == kSubTypeMleDiscoverRequest || mInfo.mSubType == kSubTypeMleDiscoverResponse || + mInfo.mSubType == kSubTypeMleChildUpdateRequest || mInfo.mSubType == kSubTypeMleGeneral) { rval = true; diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index 925898c9e..0cf77090e 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -110,7 +110,7 @@ struct MessageInfo }; uint8_t mType : 2; ///< Identifies the type of message. - uint8_t mSubType : 3; ///< Identifies the message sub type. + uint8_t mSubType : 4; ///< Identifies the message sub type. bool mDirectTx : 1; ///< Used to indicate whether a direct transmission is required. bool mLinkSecurity : 1; ///< Indicates whether or not link security is enabled. uint8_t mPriority : 2; ///< Identifies the message priority level (lower value is higher priority). @@ -218,6 +218,7 @@ public: kSubTypeMplRetransmission = 5, ///< MPL next retranmission message kSubTypeMleGeneral = 6, ///< General MLE kSubTypeJoinerFinalizeResponse = 7, ///< Joiner Finalize Response + kSubTypeMleChildUpdateRequest = 8, ///< MLE Child Update Request }; enum diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 9c8865770..57728e7cb 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1672,6 +1672,7 @@ ThreadError Mle::SendChildUpdateRequest(void) mChildUpdateAttempts++; VerifyOrExit((message = NewMleMessage()) != NULL); + message->SetSubType(Message::kSubTypeMleChildUpdateRequest); SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildUpdateRequest)); SuccessOrExit(error = AppendMode(*message, mDeviceMode)); diff --git a/src/core/thread/mle_constants.hpp b/src/core/thread/mle_constants.hpp index 663094a56..4ea72161e 100644 --- a/src/core/thread/mle_constants.hpp +++ b/src/core/thread/mle_constants.hpp @@ -64,7 +64,6 @@ enum kUnicastRetransmissionDelay = 1000, ///< Base delay before retransmitting an MLE unicast. kMaxResponseDelay = 1000, ///< Maximum delay before responding to a multicast request kMaxChildIdRequestTimeout = 5000, ///< Maximum delay for receiving a Child ID Request - kChildUpdateRequestPeriod = 100, ///< The period for sending Child Update Request kMaxChildUpdateResponseTimeout = 2000, ///< Maximum delay for receiving a Child Update Response }; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index e33a6f6e6..db7b8cce7 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -56,7 +56,6 @@ MleRouter::MleRouter(ThreadNetif &aThreadNetif): Mle(aThreadNetif), mAdvertiseTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleAdvertiseTimer, NULL, this), mStateUpdateTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleStateUpdateTimer, this), - mChildUpdateRequestTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleChildUpdateRequestTimer, this), mAddressSolicit(OPENTHREAD_URI_ADDRESS_SOLICIT, &MleRouter::HandleAddressSolicit, this), mAddressRelease(OPENTHREAD_URI_ADDRESS_RELEASE, &MleRouter::HandleAddressRelease, this) { @@ -74,6 +73,7 @@ MleRouter::MleRouter(ThreadNetif &aThreadNetif): mLeaderWeight = kLeaderWeight; mFixedLeaderPartitionId = 0; mMaxChildrenAllowed = kMaxChildren; + mIsRouterRestoringChildren = false; SetRouterId(kInvalidRouterId); mPreviousPartitionId = 0; @@ -406,7 +406,7 @@ ThreadError MleRouter::SetStateRouter(uint16_t aRloc16) { if (mChildren[i].GetState() == Neighbor::kStateRestored) { - mChildUpdateRequestTimer.Start(kChildUpdateRequestPeriod); + mIsRouterRestoringChildren = true; break; } } @@ -447,7 +447,7 @@ ThreadError MleRouter::SetStateLeader(uint16_t aRloc16) { if (mChildren[i].GetState() == Neighbor::kStateRestored) { - mChildUpdateRequestTimer.Start(kChildUpdateRequestPeriod); + mIsRouterRestoringChildren = true; break; } } @@ -1766,6 +1766,26 @@ void MleRouter::HandleStateUpdateTimer(void) break; } + if (mIsRouterRestoringChildren) + { + bool hasRestoringChildren = false; + + for (uint8_t i = 0; i < mMaxChildrenAllowed; i++) + { + if (mChildren[i].GetState() == Neighbor::kStateRestored) + { + SendChildUpdateRequest(&mChildren[i]); + hasRestoringChildren = true; + } + } + + // no child to restore + if (!hasRestoringChildren) + { + mIsRouterRestoringChildren = false; + } + } + // update children state for (int i = 0; i < mMaxChildrenAllowed; i++) { @@ -1834,36 +1854,6 @@ exit: return; } -void MleRouter::HandleChildUpdateRequestTimer(void *aContext) -{ - static_cast(aContext)->HandleChildUpdateRequestTimer(); -} - -void MleRouter::HandleChildUpdateRequestTimer(void) -{ - VerifyOrExit(GetDeviceState() == kDeviceStateRouter || GetDeviceState() == kDeviceStateLeader); - - for (int i = 0; i < mMaxChildrenAllowed; i++) - { - if (mChildren[i].GetState() == Neighbor::kStateRestored) - { - SendChildUpdateRequest(&mChildren[i]); - mChildren[i].SetState(Neighbor::kStateChildUpdateRequest); - - if (mChildren[i].IsRxOnWhenIdle()) - { - mChildren[i].SetTimeout(Timer::MsecToSec(kMaxChildUpdateResponseTimeout)); - } - - mChildUpdateRequestTimer.Start(kChildUpdateRequestPeriod); - break; - } - } - -exit: - return; -} - ThreadError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &challenge, bool aRoutersOnlyRequest) { ThreadError error = kThreadError_None; @@ -2679,7 +2669,22 @@ ThreadError MleRouter::SendChildUpdateRequest(Child *aChild) Ip6::Address destination; Message *message; + if (!aChild->IsRxOnWhenIdle()) + { + uint8_t childIndex = mNetif.GetMle().GetChildIndex(*aChild); + + // No need to send "Child Update Request" to the sleepy child if there is one already queued for it. + for (message = mNetif.GetMeshForwarder().GetSendQueue().GetHead(); message; message = message->GetNext()) + { + if (message->GetChildMask(childIndex) && message->GetSubType() == Message::kSubTypeMleChildUpdateRequest) + { + ExitNow(); + } + } + } + VerifyOrExit((message = NewMleMessage()) != NULL); + message->SetSubType(Message::kSubTypeMleChildUpdateRequest); SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildUpdateRequest)); SuccessOrExit(error = AppendSourceAddress(*message)); SuccessOrExit(error = AppendLeaderData(*message)); diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp index 9b19128c9..85a3bb34f 100644 --- a/src/core/thread/mle_router_ftd.hpp +++ b/src/core/thread/mle_router_ftd.hpp @@ -718,12 +718,9 @@ private: bool HandleAdvertiseTimer(void); static void HandleStateUpdateTimer(void *aContext); void HandleStateUpdateTimer(void); - static void HandleChildUpdateRequestTimer(void *aContext); - void HandleChildUpdateRequestTimer(void); TrickleTimer mAdvertiseTimer; Timer mStateUpdateTimer; - Timer mChildUpdateRequestTimer; Coap::Resource mAddressSolicit; Coap::Resource mAddressRelease; @@ -743,6 +740,7 @@ private: uint8_t mLeaderWeight; uint32_t mFixedLeaderPartitionId; ///< only for certification testing bool mRouterRoleEnabled; + bool mIsRouterRestoringChildren; uint8_t mRouterId; uint8_t mPreviousRouterId; diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index 368d7c020..f4a650424 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -93,7 +93,6 @@ public: switch (mState) { case kStateValid: case kStateRestored: - case kStateChildUpdateRequest: return true; default: