[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.
This commit is contained in:
Jonathan Hui
2017-12-05 17:16:11 +00:00
committed by GitHub
parent da4ddd7bf0
commit 0097c403bc
6 changed files with 85 additions and 42 deletions
+1 -1
View File
@@ -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();
+2 -2
View File
@@ -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)
{
+67 -39
View File
@@ -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)
+12
View File
@@ -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;
+2
View File
@@ -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;
+1
View File
@@ -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)