From 0097c403bc5e6a88cdfd947b17ca679a147be60c Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Tue, 5 Dec 2017 17:16:11 +0000 Subject: [PATCH] [mle] support MLE attach without having to detach first (#2337) This commit allows a device to execute the MLE attach protocol without first having to detach from it's existing parent. This change allows a device to search for a better parent without disrupting existing connectivity. This commit involves the following changes: 1. Support sending MLE Parent Request and receiving MLE Parent Response while attached. 2. If the set of MLE Parent Responses yields a better parent than the one the device is currently attached to, the device proceeds to complete the attach process with the better parent. --- src/core/thread/data_poll_manager.cpp | 2 +- src/core/thread/mesh_forwarder.cpp | 4 +- src/core/thread/mle.cpp | 106 ++++++++++++++++---------- src/core/thread/mle.hpp | 12 +++ src/core/thread/mle_router.cpp | 2 + src/core/thread/topology.hpp | 1 + 6 files changed, 85 insertions(+), 42 deletions(-) diff --git a/src/core/thread/data_poll_manager.cpp b/src/core/thread/data_poll_manager.cpp index d9c6bcf74..2b03fdcef 100644 --- a/src/core/thread/data_poll_manager.cpp +++ b/src/core/thread/data_poll_manager.cpp @@ -103,7 +103,7 @@ otError DataPollManager::SendDataPoll(void) VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE); VerifyOrExit(!netif.GetMac().GetRxOnWhenIdle(), error = OT_ERROR_INVALID_STATE); - parent = netif.GetMle().GetParent(); + parent = netif.GetMle().GetParentCandidate(); VerifyOrExit((parent != NULL) && parent->IsStateValidOrRestoring(), error = OT_ERROR_INVALID_STATE); mTimer.Stop(); diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index d3491d044..d5ef2c347 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -619,7 +619,7 @@ Message *MeshForwarder::GetDirectTransmission(void) case Message::kTypeMacDataPoll: { ThreadNetif &netif = GetNetif(); - Neighbor *parent = netif.GetMle().GetParent(); + Neighbor *parent = netif.GetMle().GetParentCandidate(); if ((parent != NULL) && (parent->IsStateValidOrRestoring())) { @@ -1781,7 +1781,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError) if (mSendMessage->GetType() == Message::kTypeMacDataPoll) { - neighbor = netif.GetMle().GetParent(); + neighbor = netif.GetMle().GetParentCandidate(); if (neighbor->GetState() == Neighbor::kStateInvalid) { diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 02625da9b..f4df0f2b9 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -83,6 +83,7 @@ Mle::Mle(Instance &aInstance) : mChildUpdateAttempts(0), mParentLinkMargin(0), mParentIsSingleton(false), + mReceivedResponseFromParent(false), mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()), mTimeout(kMleEndDeviceTimeout), mSendChildUpdateRequest(aInstance, &Mle::HandleSendChildUpdateRequest, this), @@ -501,6 +502,7 @@ otError Mle::BecomeDetached(void) } SetStateDetached(); + mParent.SetState(Neighbor::kStateInvalid); SetRloc16(Mac::kShortAddrInvalid); BecomeChild(kAttachAny); @@ -539,19 +541,12 @@ otError Mle::BecomeChild(AttachMode aMode) if (aMode != kAttachBetter) { - memset(&mParent, 0, sizeof(mParent)); - if (mDeviceMode & ModeTlv::kModeFFD) { netif.GetMle().StopAdvertiseTimer(); } } - if (aMode == kAttachAny) - { - mParent.SetState(Neighbor::kStateInvalid); - } - netif.GetMeshForwarder().SetRxOnWhenIdle(true); mParentRequestTimer.Start((otPlatRandomGet() % kParentRequestRouterTimeout) + 1); @@ -611,6 +606,7 @@ otError Mle::SetStateChild(uint16_t aRloc16) SetRloc16(aRloc16); mRole = OT_DEVICE_ROLE_CHILD; mParentRequestState = kParentIdle; + mReattachState = kReattachStop; mChildUpdateAttempts = 0; netif.GetMac().SetBeaconEnabled(false); @@ -1404,31 +1400,28 @@ void Mle::HandleParentRequestTimer(void) case kParentRequestStart: mParentRequestState = kParentRequestRouter; mParentCandidate.SetState(Neighbor::kStateInvalid); + mReceivedResponseFromParent = false; SendParentRequest(); break; case kParentRequestRouter: mParentRequestState = kParentRequestChild; - if (mParentCandidate.GetState() == Neighbor::kStateValid) - { - SendChildIdRequest(); - mParentRequestState = kChildIdRequest; - mParentRequestTimer.Start(kParentRequestChildTimeout); - } - else + if (mParentCandidate.GetState() != Neighbor::kStateParentResponse) { SendParentRequest(); + break; } - break; + // fall through case kParentRequestChild: mParentRequestState = kParentRequestChild; - if (mParentCandidate.GetState() == Neighbor::kStateValid) + if (mParentCandidate.GetState() == Neighbor::kStateParentResponse && + (mRole != OT_DEVICE_ROLE_CHILD || mReceivedResponseFromParent) && + SendChildIdRequest() == OT_ERROR_NONE) { - SendChildIdRequest(); mParentRequestState = kChildIdRequest; mParentRequestTimer.Start(kParentRequestChildTimeout); break; @@ -1465,21 +1458,30 @@ void Mle::HandleParentRequestTimer(void) switch (mParentRequestMode) { case kAttachAny: - if (mPreviousPanId != Mac::kPanIdBroadcast) + if (mRole != OT_DEVICE_ROLE_CHILD) { - netif.GetMac().SetChannel(mPreviousChannel); - netif.GetMac().SetPanId(mPreviousPanId); - mPreviousPanId = Mac::kPanIdBroadcast; - BecomeDetached(); + if (mPreviousPanId != Mac::kPanIdBroadcast) + { + netif.GetMac().SetChannel(mPreviousChannel); + netif.GetMac().SetPanId(mPreviousPanId); + mPreviousPanId = Mac::kPanIdBroadcast; + BecomeDetached(); + } + else if ((mDeviceMode & ModeTlv::kModeFFD) == 0) + { + SendOrphanAnnounce(); + BecomeDetached(); + } + else if (netif.GetMle().BecomeLeader() != OT_ERROR_NONE) + { + BecomeDetached(); + } } - else if ((mDeviceMode & ModeTlv::kModeFFD) == 0) + else if ((mDeviceMode & ModeTlv::kModeRxOnWhenIdle) == 0) { - SendOrphanAnnounce(); - BecomeDetached(); - } - else if (netif.GetMle().BecomeLeader() != OT_ERROR_NONE) - { - BecomeDetached(); + // return to sleepy operation + netif.GetMeshForwarder().GetDataPollManager().SetAttachMode(false); + netif.GetMeshForwarder().SetRxOnWhenIdle(false); } break; @@ -1632,9 +1634,16 @@ otError Mle::SendChildIdRequest(void) { otError error = OT_ERROR_NONE; uint8_t tlvs[] = {Tlv::kAddress16, Tlv::kNetworkData, Tlv::kRoute}; - Message *message; + Message *message = NULL; Ip6::Address destination; + if (mRole == OT_DEVICE_ROLE_CHILD && + memcmp(&mParent.GetExtAddress(), &mParentCandidate.GetExtAddress(), OT_EXT_ADDRESS_SIZE) == 0) + { + otLogInfoMle(GetInstance(), "Already attached to candidate parent"); + ExitNow(error = OT_ERROR_ALREADY); + } + VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildIdRequest)); SuccessOrExit(error = AppendResponse(*message, mChildIdRequest.mChallenge, mChildIdRequest.mChallengeLength)); @@ -1653,6 +1662,8 @@ otError Mle::SendChildIdRequest(void) SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); + mParentCandidate.SetState(Neighbor::kStateValid); + memset(&destination, 0, sizeof(destination)); destination.mFields.m16[0] = HostSwap16(0xfe80); destination.SetIid(mParentCandidate.GetExtAddress()); @@ -2370,8 +2381,6 @@ otError Mle::HandleAdvertisement(const Message &aMessage, const Ip6::MessageInfo mParent.GetRloc16() != sourceAddress.GetRloc16()) { BecomeDetached(); - mParent.GetLinkInfo().Clear(); - mParent.SetState(Neighbor::kStateInvalid); } } } @@ -2671,6 +2680,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf LinkFrameCounterTlv linkFrameCounter; MleFrameCounterTlv mleFrameCounter; ChallengeTlv challenge; + Mac::ExtAddress extAddress; int8_t diff; // Source Address @@ -2685,6 +2695,14 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf memcmp(response.GetResponse(), mParentRequest.mChallenge, response.GetLength()) == 0, error = OT_ERROR_PARSE); + aMessageInfo.GetPeerAddr().ToExtAddress(extAddress); + + if (mRole == OT_DEVICE_ROLE_CHILD && + memcmp(&mParent.GetExtAddress(), &extAddress, sizeof(extAddress)) == 0) + { + mReceivedResponseFromParent = true; + } + // Leader Data SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData)); VerifyOrExit(leaderData.IsValid(), error = OT_ERROR_PARSE); @@ -2734,7 +2752,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf } // if already have a candidate parent, only seek a better parent - if (mParentCandidate.GetState() == Neighbor::kStateValid) + if (mParentCandidate.GetState() == Neighbor::kStateParentResponse) { int compare = 0; @@ -2771,7 +2789,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf memcpy(mChildIdRequest.mChallenge, challenge.GetChallenge(), challenge.GetLength()); mChildIdRequest.mChallengeLength = challenge.GetLength(); - aMessageInfo.GetPeerAddr().ToExtAddress(mParentCandidate.GetExtAddress()); + mParentCandidate.SetExtAddress(extAddress); mParentCandidate.SetRloc16(sourceAddress.GetRloc16()); mParentCandidate.SetLinkFrameCounter(linkFrameCounter.GetFrameCounter()); mParentCandidate.SetMleFrameCounter(mleFrameCounter.GetFrameCounter()); @@ -2781,7 +2799,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf mParentCandidate.GetLinkInfo().AddRss(netif.GetMac().GetNoiseFloor(), linkInfo->mRss); mParentCandidate.ResetLinkFailures(); mParentCandidate.SetLinkQualityOut(LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMarginTlv.GetLinkMargin())); - mParentCandidate.SetState(Neighbor::kStateValid); + mParentCandidate.SetState(Neighbor::kStateParentResponse); mParentCandidate.SetKeySequence(aKeySequence); mParentPriority = connectivity.GetParentPriority(); @@ -2874,7 +2892,6 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn // Parent Attach Success mParentRequestTimer.Stop(); - mReattachState = kReattachStop; SetStateDetached(); SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); @@ -3344,12 +3361,23 @@ bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const Router *Mle::GetParent(void) { - if ((!mParent.IsStateValidOrRestoring()) && (mParentCandidate.GetState() == Neighbor::kStateValid)) + return &mParent; +} + +Router *Mle::GetParentCandidate(void) +{ + Router *rval; + + if (mParentCandidate.GetState() == Neighbor::kStateValid) { - return &mParentCandidate; + rval = &mParentCandidate; + } + else + { + rval = &mParent; } - return &mParent; + return rval; } otError Mle::CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, Ip6::Header &aIp6Header) diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 0f51f219a..02f23f003 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -710,6 +710,17 @@ public: */ Router *GetParent(void); + /** + * This method returns a pointer to the parent candidate or parent. + * + * This method is useful when sending IEEE 802.15.4 Data Request frames while attempting to attach to a new parent. + * + * If attempting to attach to a new parent, this method returns the parent candidate. + * If not attempting to attach, this method returns the parent. + * + */ + Router *GetParentCandidate(void); + /** * This method indicates whether or not an IPv6 address is an RLOC. * @@ -1463,6 +1474,7 @@ private: LeaderDataTlv mParentLeaderData; uint8_t mParentLinkMargin; bool mParentIsSingleton; + bool mReceivedResponseFromParent; Router mParentCandidate; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index da3136691..c5b5e897a 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1886,6 +1886,7 @@ void MleRouter::HandleStateUpdateTimer(void) timeout = TimerMilli::SecToMsec(mChildren[i].GetTimeout()); break; + case Neighbor::kStateParentResponse: case Neighbor::kStateLinkRequest: assert(false); break; @@ -4210,6 +4211,7 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Header *aHeader, Message *aMe SendChildIdResponse(mChildren[i]); break; + case Neighbor::kStateParentResponse: case Neighbor::kStateLinkRequest: assert(false); break; diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index c0a881efd..e04fbbb81 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -62,6 +62,7 @@ public: kStateInvalid, ///< Neighbor link is invalid kStateRestored, ///< Neighbor is restored from non-volatile memory kStateParentRequest, ///< Received an MLE Parent Request message + kStateParentResponse, ///< Received an MLE Parent Response message kStateChildIdRequest, ///< Received an MLE Child ID Request message kStateLinkRequest, ///< Sent an MLE Link Request message kStateChildUpdateRequest, ///< Sent an MLE Child Update Request message (trying to restore the child)