mirror of
https://github.com/espressif/openthread.git
synced 2026-08-17 07:59:51 +00:00
[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:
@@ -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();
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user