diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index d3408d1a3..a7f0f8180 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -453,6 +453,11 @@ exit: return rval; } +bool Netif::IsStateChangedCallbackPending(void) +{ + return mStateChangedFlags != 0; +} + void Netif::SetStateChangedFlags(uint32_t aFlags) { mStateChangedFlags |= aFlags; diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index a7f987b9f..2dd7eed09 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -317,6 +317,14 @@ public: */ ThreadError RegisterCallback(NetifCallback &aCallback); + /** + * This method indicates whether or not a state changed callback is pending. + * + * @retval TRUE if a state changed callback is pending, FALSE otherwise. + * + */ + bool IsStateChangedCallbackPending(void); + /** * This method schedules notification of @p aFlags. * diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 739c71abd..396cbb221 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -61,7 +61,8 @@ Mle::Mle(ThreadNetif &aThreadNetif) : mMesh(aThreadNetif.GetMeshForwarder()), mMleRouter(aThreadNetif.GetMle()), mNetworkData(aThreadNetif.GetNetworkDataLeader()), - mParentRequestTimer(&HandleParentRequestTimer, this) + mParentRequestTimer(&HandleParentRequestTimer, this), + mSendChildUpdateRequest(&HandleSendChildUpdateRequest, this) { mDeviceState = kDeviceStateDisabled; mDeviceMode = ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeSecureDataRequest | ModeTlv::kModeFFD | @@ -930,8 +931,6 @@ void Mle::HandleNetifStateChanged(uint32_t aFlags, void *aContext) void Mle::HandleNetifStateChanged(uint32_t aFlags) { - bool sendChildUpdateRequest = false; - if ((aFlags & (OT_IP6_ADDRESS_ADDED | OT_IP6_ADDRESS_REMOVED)) != 0) { if (!mNetif.IsUnicastAddress(mMeshLocal64.GetAddress())) @@ -948,7 +947,7 @@ void Mle::HandleNetifStateChanged(uint32_t aFlags) if (mDeviceState == kDeviceStateChild && (mDeviceMode & ModeTlv::kModeFFD) == 0) { - sendChildUpdateRequest = true; + mSendChildUpdateRequest.Post(); } } @@ -960,14 +959,9 @@ void Mle::HandleNetifStateChanged(uint32_t aFlags) } else { - sendChildUpdateRequest = true; + mSendChildUpdateRequest.Post(); } } - - if (sendChildUpdateRequest) - { - SendChildUpdateRequest(); - } } void Mle::HandleParentRequestTimer(void *aContext) @@ -1217,6 +1211,25 @@ exit: return error; } +void Mle::HandleSendChildUpdateRequest(void *aContext) +{ + static_cast(aContext)->SendChildUpdateRequest(); +} + +void Mle::HandleSendChildUpdateRequest(void) +{ + // a Network Data udpate can cause a change to the IPv6 address configuration + // only send a Child Update Request after we know there are no more pending changes + if (mNetif.IsStateChangedCallbackPending()) + { + mSendChildUpdateRequest.Post(); + } + else + { + SendChildUpdateRequest(); + } +} + ThreadError Mle::SendChildUpdateRequest(void) { ThreadError error = kThreadError_None; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index e43fb394e..2cb424532 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1082,6 +1082,8 @@ private: void HandleParentRequestTimer(void); static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + static void HandleSendChildUpdateRequest(void *aContext); + void HandleSendChildUpdateRequest(void); ThreadError HandleAdvertisement(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); ThreadError HandleChildIdResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -1121,6 +1123,8 @@ private: Ip6::UdpSocket mSocket; uint32_t mTimeout; + Tasklet mSendChildUpdateRequest; + DiscoverHandler mDiscoverHandler; void *mDiscoverContext; bool mIsDiscoverInProgress;