mirror of
https://github.com/espressif/openthread.git
synced 2026-09-13 12:40:05 +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(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||||
VerifyOrExit(!netif.GetMac().GetRxOnWhenIdle(), 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);
|
VerifyOrExit((parent != NULL) && parent->IsStateValidOrRestoring(), error = OT_ERROR_INVALID_STATE);
|
||||||
|
|
||||||
mTimer.Stop();
|
mTimer.Stop();
|
||||||
|
|||||||
@@ -619,7 +619,7 @@ Message *MeshForwarder::GetDirectTransmission(void)
|
|||||||
case Message::kTypeMacDataPoll:
|
case Message::kTypeMacDataPoll:
|
||||||
{
|
{
|
||||||
ThreadNetif &netif = GetNetif();
|
ThreadNetif &netif = GetNetif();
|
||||||
Neighbor *parent = netif.GetMle().GetParent();
|
Neighbor *parent = netif.GetMle().GetParentCandidate();
|
||||||
|
|
||||||
if ((parent != NULL) && (parent->IsStateValidOrRestoring()))
|
if ((parent != NULL) && (parent->IsStateValidOrRestoring()))
|
||||||
{
|
{
|
||||||
@@ -1781,7 +1781,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError)
|
|||||||
|
|
||||||
if (mSendMessage->GetType() == Message::kTypeMacDataPoll)
|
if (mSendMessage->GetType() == Message::kTypeMacDataPoll)
|
||||||
{
|
{
|
||||||
neighbor = netif.GetMle().GetParent();
|
neighbor = netif.GetMle().GetParentCandidate();
|
||||||
|
|
||||||
if (neighbor->GetState() == Neighbor::kStateInvalid)
|
if (neighbor->GetState() == Neighbor::kStateInvalid)
|
||||||
{
|
{
|
||||||
|
|||||||
+67
-39
@@ -83,6 +83,7 @@ Mle::Mle(Instance &aInstance) :
|
|||||||
mChildUpdateAttempts(0),
|
mChildUpdateAttempts(0),
|
||||||
mParentLinkMargin(0),
|
mParentLinkMargin(0),
|
||||||
mParentIsSingleton(false),
|
mParentIsSingleton(false),
|
||||||
|
mReceivedResponseFromParent(false),
|
||||||
mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()),
|
mSocket(aInstance.GetThreadNetif().GetIp6().GetUdp()),
|
||||||
mTimeout(kMleEndDeviceTimeout),
|
mTimeout(kMleEndDeviceTimeout),
|
||||||
mSendChildUpdateRequest(aInstance, &Mle::HandleSendChildUpdateRequest, this),
|
mSendChildUpdateRequest(aInstance, &Mle::HandleSendChildUpdateRequest, this),
|
||||||
@@ -501,6 +502,7 @@ otError Mle::BecomeDetached(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetStateDetached();
|
SetStateDetached();
|
||||||
|
mParent.SetState(Neighbor::kStateInvalid);
|
||||||
SetRloc16(Mac::kShortAddrInvalid);
|
SetRloc16(Mac::kShortAddrInvalid);
|
||||||
BecomeChild(kAttachAny);
|
BecomeChild(kAttachAny);
|
||||||
|
|
||||||
@@ -539,19 +541,12 @@ otError Mle::BecomeChild(AttachMode aMode)
|
|||||||
|
|
||||||
if (aMode != kAttachBetter)
|
if (aMode != kAttachBetter)
|
||||||
{
|
{
|
||||||
memset(&mParent, 0, sizeof(mParent));
|
|
||||||
|
|
||||||
if (mDeviceMode & ModeTlv::kModeFFD)
|
if (mDeviceMode & ModeTlv::kModeFFD)
|
||||||
{
|
{
|
||||||
netif.GetMle().StopAdvertiseTimer();
|
netif.GetMle().StopAdvertiseTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aMode == kAttachAny)
|
|
||||||
{
|
|
||||||
mParent.SetState(Neighbor::kStateInvalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
netif.GetMeshForwarder().SetRxOnWhenIdle(true);
|
netif.GetMeshForwarder().SetRxOnWhenIdle(true);
|
||||||
|
|
||||||
mParentRequestTimer.Start((otPlatRandomGet() % kParentRequestRouterTimeout) + 1);
|
mParentRequestTimer.Start((otPlatRandomGet() % kParentRequestRouterTimeout) + 1);
|
||||||
@@ -611,6 +606,7 @@ otError Mle::SetStateChild(uint16_t aRloc16)
|
|||||||
SetRloc16(aRloc16);
|
SetRloc16(aRloc16);
|
||||||
mRole = OT_DEVICE_ROLE_CHILD;
|
mRole = OT_DEVICE_ROLE_CHILD;
|
||||||
mParentRequestState = kParentIdle;
|
mParentRequestState = kParentIdle;
|
||||||
|
mReattachState = kReattachStop;
|
||||||
mChildUpdateAttempts = 0;
|
mChildUpdateAttempts = 0;
|
||||||
netif.GetMac().SetBeaconEnabled(false);
|
netif.GetMac().SetBeaconEnabled(false);
|
||||||
|
|
||||||
@@ -1404,31 +1400,28 @@ void Mle::HandleParentRequestTimer(void)
|
|||||||
case kParentRequestStart:
|
case kParentRequestStart:
|
||||||
mParentRequestState = kParentRequestRouter;
|
mParentRequestState = kParentRequestRouter;
|
||||||
mParentCandidate.SetState(Neighbor::kStateInvalid);
|
mParentCandidate.SetState(Neighbor::kStateInvalid);
|
||||||
|
mReceivedResponseFromParent = false;
|
||||||
SendParentRequest();
|
SendParentRequest();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kParentRequestRouter:
|
case kParentRequestRouter:
|
||||||
mParentRequestState = kParentRequestChild;
|
mParentRequestState = kParentRequestChild;
|
||||||
|
|
||||||
if (mParentCandidate.GetState() == Neighbor::kStateValid)
|
if (mParentCandidate.GetState() != Neighbor::kStateParentResponse)
|
||||||
{
|
|
||||||
SendChildIdRequest();
|
|
||||||
mParentRequestState = kChildIdRequest;
|
|
||||||
mParentRequestTimer.Start(kParentRequestChildTimeout);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
SendParentRequest();
|
SendParentRequest();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
// fall through
|
||||||
|
|
||||||
case kParentRequestChild:
|
case kParentRequestChild:
|
||||||
mParentRequestState = 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;
|
mParentRequestState = kChildIdRequest;
|
||||||
mParentRequestTimer.Start(kParentRequestChildTimeout);
|
mParentRequestTimer.Start(kParentRequestChildTimeout);
|
||||||
break;
|
break;
|
||||||
@@ -1465,21 +1458,30 @@ void Mle::HandleParentRequestTimer(void)
|
|||||||
switch (mParentRequestMode)
|
switch (mParentRequestMode)
|
||||||
{
|
{
|
||||||
case kAttachAny:
|
case kAttachAny:
|
||||||
if (mPreviousPanId != Mac::kPanIdBroadcast)
|
if (mRole != OT_DEVICE_ROLE_CHILD)
|
||||||
{
|
{
|
||||||
netif.GetMac().SetChannel(mPreviousChannel);
|
if (mPreviousPanId != Mac::kPanIdBroadcast)
|
||||||
netif.GetMac().SetPanId(mPreviousPanId);
|
{
|
||||||
mPreviousPanId = Mac::kPanIdBroadcast;
|
netif.GetMac().SetChannel(mPreviousChannel);
|
||||||
BecomeDetached();
|
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();
|
// return to sleepy operation
|
||||||
BecomeDetached();
|
netif.GetMeshForwarder().GetDataPollManager().SetAttachMode(false);
|
||||||
}
|
netif.GetMeshForwarder().SetRxOnWhenIdle(false);
|
||||||
else if (netif.GetMle().BecomeLeader() != OT_ERROR_NONE)
|
|
||||||
{
|
|
||||||
BecomeDetached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1632,9 +1634,16 @@ otError Mle::SendChildIdRequest(void)
|
|||||||
{
|
{
|
||||||
otError error = OT_ERROR_NONE;
|
otError error = OT_ERROR_NONE;
|
||||||
uint8_t tlvs[] = {Tlv::kAddress16, Tlv::kNetworkData, Tlv::kRoute};
|
uint8_t tlvs[] = {Tlv::kAddress16, Tlv::kNetworkData, Tlv::kRoute};
|
||||||
Message *message;
|
Message *message = NULL;
|
||||||
Ip6::Address destination;
|
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);
|
VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
|
||||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildIdRequest));
|
SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildIdRequest));
|
||||||
SuccessOrExit(error = AppendResponse(*message, mChildIdRequest.mChallenge, mChildIdRequest.mChallengeLength));
|
SuccessOrExit(error = AppendResponse(*message, mChildIdRequest.mChallenge, mChildIdRequest.mChallengeLength));
|
||||||
@@ -1653,6 +1662,8 @@ otError Mle::SendChildIdRequest(void)
|
|||||||
SuccessOrExit(error = AppendActiveTimestamp(*message));
|
SuccessOrExit(error = AppendActiveTimestamp(*message));
|
||||||
SuccessOrExit(error = AppendPendingTimestamp(*message));
|
SuccessOrExit(error = AppendPendingTimestamp(*message));
|
||||||
|
|
||||||
|
mParentCandidate.SetState(Neighbor::kStateValid);
|
||||||
|
|
||||||
memset(&destination, 0, sizeof(destination));
|
memset(&destination, 0, sizeof(destination));
|
||||||
destination.mFields.m16[0] = HostSwap16(0xfe80);
|
destination.mFields.m16[0] = HostSwap16(0xfe80);
|
||||||
destination.SetIid(mParentCandidate.GetExtAddress());
|
destination.SetIid(mParentCandidate.GetExtAddress());
|
||||||
@@ -2370,8 +2381,6 @@ otError Mle::HandleAdvertisement(const Message &aMessage, const Ip6::MessageInfo
|
|||||||
mParent.GetRloc16() != sourceAddress.GetRloc16())
|
mParent.GetRloc16() != sourceAddress.GetRloc16())
|
||||||
{
|
{
|
||||||
BecomeDetached();
|
BecomeDetached();
|
||||||
mParent.GetLinkInfo().Clear();
|
|
||||||
mParent.SetState(Neighbor::kStateInvalid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2671,6 +2680,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
|
|||||||
LinkFrameCounterTlv linkFrameCounter;
|
LinkFrameCounterTlv linkFrameCounter;
|
||||||
MleFrameCounterTlv mleFrameCounter;
|
MleFrameCounterTlv mleFrameCounter;
|
||||||
ChallengeTlv challenge;
|
ChallengeTlv challenge;
|
||||||
|
Mac::ExtAddress extAddress;
|
||||||
int8_t diff;
|
int8_t diff;
|
||||||
|
|
||||||
// Source Address
|
// Source Address
|
||||||
@@ -2685,6 +2695,14 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
|
|||||||
memcmp(response.GetResponse(), mParentRequest.mChallenge, response.GetLength()) == 0,
|
memcmp(response.GetResponse(), mParentRequest.mChallenge, response.GetLength()) == 0,
|
||||||
error = OT_ERROR_PARSE);
|
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
|
// Leader Data
|
||||||
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData));
|
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData));
|
||||||
VerifyOrExit(leaderData.IsValid(), error = OT_ERROR_PARSE);
|
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 already have a candidate parent, only seek a better parent
|
||||||
if (mParentCandidate.GetState() == Neighbor::kStateValid)
|
if (mParentCandidate.GetState() == Neighbor::kStateParentResponse)
|
||||||
{
|
{
|
||||||
int compare = 0;
|
int compare = 0;
|
||||||
|
|
||||||
@@ -2771,7 +2789,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
|
|||||||
memcpy(mChildIdRequest.mChallenge, challenge.GetChallenge(), challenge.GetLength());
|
memcpy(mChildIdRequest.mChallenge, challenge.GetChallenge(), challenge.GetLength());
|
||||||
mChildIdRequest.mChallengeLength = challenge.GetLength();
|
mChildIdRequest.mChallengeLength = challenge.GetLength();
|
||||||
|
|
||||||
aMessageInfo.GetPeerAddr().ToExtAddress(mParentCandidate.GetExtAddress());
|
mParentCandidate.SetExtAddress(extAddress);
|
||||||
mParentCandidate.SetRloc16(sourceAddress.GetRloc16());
|
mParentCandidate.SetRloc16(sourceAddress.GetRloc16());
|
||||||
mParentCandidate.SetLinkFrameCounter(linkFrameCounter.GetFrameCounter());
|
mParentCandidate.SetLinkFrameCounter(linkFrameCounter.GetFrameCounter());
|
||||||
mParentCandidate.SetMleFrameCounter(mleFrameCounter.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.GetLinkInfo().AddRss(netif.GetMac().GetNoiseFloor(), linkInfo->mRss);
|
||||||
mParentCandidate.ResetLinkFailures();
|
mParentCandidate.ResetLinkFailures();
|
||||||
mParentCandidate.SetLinkQualityOut(LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMarginTlv.GetLinkMargin()));
|
mParentCandidate.SetLinkQualityOut(LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMarginTlv.GetLinkMargin()));
|
||||||
mParentCandidate.SetState(Neighbor::kStateValid);
|
mParentCandidate.SetState(Neighbor::kStateParentResponse);
|
||||||
mParentCandidate.SetKeySequence(aKeySequence);
|
mParentCandidate.SetKeySequence(aKeySequence);
|
||||||
|
|
||||||
mParentPriority = connectivity.GetParentPriority();
|
mParentPriority = connectivity.GetParentPriority();
|
||||||
@@ -2874,7 +2892,6 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn
|
|||||||
|
|
||||||
// Parent Attach Success
|
// Parent Attach Success
|
||||||
mParentRequestTimer.Stop();
|
mParentRequestTimer.Stop();
|
||||||
mReattachState = kReattachStop;
|
|
||||||
SetStateDetached();
|
SetStateDetached();
|
||||||
|
|
||||||
SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
|
SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
|
||||||
@@ -3344,12 +3361,23 @@ bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const
|
|||||||
|
|
||||||
Router *Mle::GetParent(void)
|
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)
|
otError Mle::CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, Ip6::Header &aIp6Header)
|
||||||
|
|||||||
@@ -710,6 +710,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
Router *GetParent(void);
|
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.
|
* This method indicates whether or not an IPv6 address is an RLOC.
|
||||||
*
|
*
|
||||||
@@ -1463,6 +1474,7 @@ private:
|
|||||||
LeaderDataTlv mParentLeaderData;
|
LeaderDataTlv mParentLeaderData;
|
||||||
uint8_t mParentLinkMargin;
|
uint8_t mParentLinkMargin;
|
||||||
bool mParentIsSingleton;
|
bool mParentIsSingleton;
|
||||||
|
bool mReceivedResponseFromParent;
|
||||||
|
|
||||||
Router mParentCandidate;
|
Router mParentCandidate;
|
||||||
|
|
||||||
|
|||||||
@@ -1886,6 +1886,7 @@ void MleRouter::HandleStateUpdateTimer(void)
|
|||||||
timeout = TimerMilli::SecToMsec(mChildren[i].GetTimeout());
|
timeout = TimerMilli::SecToMsec(mChildren[i].GetTimeout());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Neighbor::kStateParentResponse:
|
||||||
case Neighbor::kStateLinkRequest:
|
case Neighbor::kStateLinkRequest:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
@@ -4210,6 +4211,7 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Header *aHeader, Message *aMe
|
|||||||
SendChildIdResponse(mChildren[i]);
|
SendChildIdResponse(mChildren[i]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Neighbor::kStateParentResponse:
|
||||||
case Neighbor::kStateLinkRequest:
|
case Neighbor::kStateLinkRequest:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
kStateInvalid, ///< Neighbor link is invalid
|
kStateInvalid, ///< Neighbor link is invalid
|
||||||
kStateRestored, ///< Neighbor is restored from non-volatile memory
|
kStateRestored, ///< Neighbor is restored from non-volatile memory
|
||||||
kStateParentRequest, ///< Received an MLE Parent Request message
|
kStateParentRequest, ///< Received an MLE Parent Request message
|
||||||
|
kStateParentResponse, ///< Received an MLE Parent Response message
|
||||||
kStateChildIdRequest, ///< Received an MLE Child ID Request message
|
kStateChildIdRequest, ///< Received an MLE Child ID Request message
|
||||||
kStateLinkRequest, ///< Sent an MLE Link Request message
|
kStateLinkRequest, ///< Sent an MLE Link Request message
|
||||||
kStateChildUpdateRequest, ///< Sent an MLE Child Update Request message (trying to restore the child)
|
kStateChildUpdateRequest, ///< Sent an MLE Child Update Request message (trying to restore the child)
|
||||||
|
|||||||
Reference in New Issue
Block a user